반응형

 

YOLO v3 ship_detection 실습

  • coco json에 bbox를 읽어서 detection

 

YOLO v3 데이터 준비

  • Yolo v3 준비
!git clone https://github.com/ultralytics/yolov3
%cd yolov3
!pip install -r requirements.txt

 

  • 데이터 준비
# 위치를 /content로 이동
%cd ..

# ship Object Detection 데이터셋 다운
!gdown https://drive.google.com/uc?id=1LwLwl-T4ShmcDLIDbnAch4OZMqfmk_67

# 압축 풀기
!unzip -qq "/content/ship_rle_coco.zip"
  • train : test 데이터 확인
train_dir = glob('./ship_rle_coco/train/*.jpg')
test_dir = glob('./ship_rle_coco/test/*.jpg')

print(f'train 이미지 수 : {len(train_dir)}, test 이미지 수 : {len(test_dir)}')

 

COCO 데이터의 annotations bbox 추출

**coco 데이터는 아래와 같은 특성이 존재**
```
{
    "categories": [   # categories는 사용하는 class의 내용을 기록
        {
            "id": 0,
            "name": "ship",
            "supercategory": "ship"
        }
    ],
    "images": [  # images 이미지의 file명, width, height 기록
        {
            "id": 0,
            "file_name": "thumbnail-ba5c72edb320b49a69e86b05775c49b2-scaled-1_jpeg.rf.035d587add7bc2a6c7616d72e56bfad4.jpg",
            "height": 416,
            "width": 416,
            "date_captured": "2020-05-11T04:28:59+00:00"
        },

    ],
    "annotations": [ # image_id 해당하는 이미지 번호, bbox에 bounding box 좌표 기록
        {
            "id": 0,
            "image_id": 0,
            "category_id": 2,
            "bbox": [
                253,
                120,
                16,
                21
            ],
            "area": 336,
            "segmentation": [],
            "iscrowd": 0
        },
      ]
}
```
  • COCO data 불러오기
with open('./ship_rle_coco/coco_train.json', "r") as json_file:
    json_data = json.load(json_file)
  • coco 데이터 DataFrame에 저장
    • yolov3 format 순서인 'classes','x_center','y_center','w','h' 로 변경하기 위해 annotations 의 bbox 데이터 가져오기
image_list = {}  # 이미지 고유 번호를 위해 생성한 dict
for i in json_data['images']:
    image_list[i['id']] = i['file_name']


box_df = pd.DataFrame()
img_list = []
x_min_list = []
x_max_list = []
y_min_list = []
y_max_list = []

for i in json_data['annotations']:

    x_min,x_max,y_min,y_max = i['bbox']
    img_list.append(image_list[i['image_id']])
    x_min_list.append(x_min)
    x_max_list.append(x_max)
    y_min_list.append(y_min)
    y_max_list.append(y_max)


box_df['image'] = img_list
box_df['xmin'] = x_min_list
box_df['xmax'] = x_max_list
box_df['ymin'] = y_min_list
box_df['ymax'] = y_max_list
  • Yolov3 format으로 변환
img_h, img_w = json_data['images'][0]['height'], json_data['images'][0]['width']

# x_center 생성
box_df['x_center'] = (box_df['xmin'] + box_df['xmax'])/2
box_df['x_center'] = box_df['x_center']/img_w

# y_center 생성
box_df['y_center'] = (box_df['ymin'] + box_df['ymax'])/2
box_df['y_center'] = box_df['y_center']/img_h

# width 생성
box_df['w'] = box_df['xmax'] - box_df['xmin']
box_df['w'] = box_df['w']/img_w

# height 생성
box_df['h'] = box_df['ymax'] - box_df['ymin']
box_df['h'] = box_df['h']/img_h

# class 생성
box_df['classes'] = 0

box_df.head()
  • 데이터 시각화
cnt = 0

for i,d in box_df.groupby('image'):
  if cnt == 5:
    break
  else:
    img = imread(f'./ship_rle_coco/train/{i}')

    for num in range(len(d)):
      xmin,xmax,ymin,ymax = d.iloc[num][['xmin', 'xmax', 'ymin', 'ymax']]
      cv2.rectangle(img,(xmin,ymin),(xmax,ymax),(0,255,0),3)

    cv2_imshow(img)
    cnt +=1

 

yolov3 폴더 형식 및 데이터 분할

─────────────────────────────────────────────────────────────

📁 yolov3_ship_data

├────📃 data.yaml : 데이터의 경로 및 class 내용이 담긴 yaml 파일

├──📁 images : tarin,val,test 이미지가 들어있는 폴더

│ ├──📁 train

│ ├──📁 val

│ └──📁 test

├──📁 labels : tarin,val label이 들어있는 폴더

│ ├──📁 train

│ └──📁 val

─────────────────────────────────────────────────────────────

def make_dir():
    if not os.path.exists('./yolov3_ship_data'):
        os.makedirs('./yolov3_ship_data')

    if not os.path.exists('./yolov3_ship_data/images/'):
        os.makedirs('./yolov3_ship_data/images/')

    if not os.path.exists('./yolov3_ship_data/labels/'):
        os.makedirs('./yolov3_ship_data/labels/')

    for i in ['train','val']:
        if not os.path.exists(f'./yolov3_ship_data/images/{i}/'):
            os.makedirs(f'./yolov3_ship_data/images/{i}/')
        if not os.path.exists(f'./yolov3_ship_data/labels/{i}/'):
            os.makedirs(f'./yolov3_ship_data/labels/{i}/')

# 경로 생성
make_dir()
  • 데이터 분할
# box_df 중 train : valid 분리
split_data = list(set(list(box_df['image'])))
train_valid_split = random.sample(split_data, k= 210)


for name,sep in tqdm(box_df.groupby('image')):
    if name in train_valid_split:
        folder = 'train'
    else:
        folder = 'val'

    with open(f'./yolov3_ship_data/labels/{folder}/{name.split(".")[0]}.txt', 'w+') as f:
        # 실제 yolov3 format에 사용되는 class, x_center, y_center, width, height 만 남기기
        row = sep[['classes','x_center','y_center','w','h']].astype(float).values
        row = row.astype(str)
        for j in range(len(row)):
            text = ' '.join(row[j])
            f.write(text)
            f.write("\n")

    sh.copy(f"./ship_rle_coco/train/{name}", f'./yolov3_ship_data/images/{folder}/{name}')
  • test 데이터 옮기기
test_imgs = [i.split('/')[-1] for i in glob('./ship_rle_coco/test/*.jpg')]

for i in tqdm(test_imgs):

    if not os.path.exists('./yolov3_ship_data/images/test/'):
        os.makedirs('./yolov3_ship_data/images/test/')

    sh.copy(f"./ship_rle_coco/test/{i}", f'./yolov3_ship_data/images/test/{i}')

 

yaml 파일 생성

%%writefile ./yolov3_ship_data/data.yaml
train : ../yolov3_ship_data/images/train
val : ../yolov3_ship_data/images/val
test: ../yolov3_ship_data/images/test

nc : 1
names: [ship]

 

모델 훈련

--batch : 한번에 훈련시킬 이미지 수 

--epochs : 훈련 횟수

--data : .yaml 경로

--weights : 사용할 모델 가중치, yolov3.py 입력시 자동으로 yolov3 가중치 다운 (연습에서는 사전에 학습시킨 모델 사용)
os.chdir('./yolov3')
!python train.py --img 640 --batch 16 --epochs 5 --exist-ok --data  ../yolov3_ship_data/data.yaml --weights ../ship_rle_coco/best.pt --cache --device 0
  • 훈련 결과 출력 맨 아래줄에 *Results saved to *경로에 best.pt라는 이름으로 학습 가중치 가운데 validation score가 가장 좋은 결과가 저장됨
  • 다음 셀의 --weights 인자에 위 경로/best.pt를 입력하여 저장된 가중치를 불러와 추론 수행
!python ./detect.py --weights ./runs/train/exp/weights/best.pt --img 640 --conf 0.25 --line-thickness 1 --exist-ok --device 0 --source  ../yolov3_ship_data/images/test

 

모델 결과 시각화

data_list = glob('./runs/detect/exp/*.jpg')
random_img = random.sample(data_list, k=5)
for i in random_img:
  src = cv2.imread(i)

  cv2_imshow(src)

 

전체 내용 한번에 보기

반응형

'DeepLearning > Yolo' 카테고리의 다른 글

YOLOV3 - Cardetection 실습  (2) 2024.07.23
YOLO V3 example  (1) 2024.07.22