Object Detection
환경설정 → 데이터 전처리 → 모델링 → 탐지
환경설정
1) 구글 크롬을 이용하기 때문에 구글 드라이브 연동 필수!
from google.colab import drive
drive.mount('/content/drive')
2) 데이터 셋 파일 압축 해제
import zipfile
# 압축파일 경로
# 구글 드라이브인 경우 경로에 맞게 지정하세요.
dataset_path = '/content/drive/MyDrive/Datasets2/'
file_path = dataset_path + 'money_dataset.zip'
# 압축 해제
data = zipfile.ZipFile(file_path)
data.extractall('/content/drive/MyDrive/Datasets2/money_dataset/')
데이터 셋 압축 해제하고 불러오는 데 시간이 꽤 걸렸다
데이터 전처리
1) Image와 Label을 구분하는 폴더를 만들기
# 폴더 구조 만들기
!mkdir /content/drive/MyDrive/Datasets2/images;
!mkdir /content/drive/MyDrive/Datasets2/images/train; mkdir /content/drive/MyDrive/Datasets2/images/val
!mkdir /content/drive/MyDrive/Datasets2/labels;
!mkdir /content/drive/MyDrive/Datasets2/labels/train; mkdir /content/drive/MyDrive/Datasets2/labels/val
import glob, shutil
# 화폐 단위 종류 리스트 및 데이터 경로
won_list = ['10', '50', '100', '500', '1000', '5000', '10000', '50000']
data_path = '/content/Dataset2/'
2) 이미지 데이터는 /images에, JSON 데이터는 /labels에 넣어주기
# 10_이미지, 라벨 구분
import glob
images_10 = glob.glob('/content/drive/MyDrive/Datasets2/money_dataset/10/*.jpg')
labels_10 = glob.glob('/content/drive/MyDrive/Datasets2/money_dataset/10/*.json')
# 10_구분한 정보로 하나씩 파일 옮김
for file in images_10:
shutil.move(f"{file}", f"/content/drive/MyDrive/Datasets2/images/")
for file in labels_10:
shutil.move(f"{file}", f"/content/drive/MyDrive/Datasets2/labels/")
각 화폐 단위별 폴더에 jpg, json 파일이 같이 있어서 두 파일을 분리해주기 위한 단계다
위의 코드를 10 ~ 50000 차례대로 수행했다
3) label은 label끼리, image는 image끼리 모은 것을 하나의 하위 폴더 all로 이동
!mkdir /content/drive/MyDrive/Datasets2/images/all;
!mkdir /content/drive/MyDrive/Datasets2/labels/all;
# images 폴더 안에 jpg파일을 하위 폴더 all로 이동
images_jpg = glob.glob('/content/drive/MyDrive/Datasets2/images/*.jpg')
labels_json = glob.glob('/content/drive/MyDrive/Datasets2/labels/*.json')
#
for file in images_jpg:
shutil.move(f"{file}", f"/content/drive/MyDrive/Datasets2/images/all/")
for file in labels_json:
shutil.move(f"{file}", f"/content/drive/MyDrive/Datasets2/labels/all/")
4) 데이터를 Training set | Validation set으로 분할
Training과 Validation은 8:2로 분리
import os
import random
image_path = '/content/drive/MyDrive/Datasets2/images/all/'
label_path = '/content/drive/MyDrive/Datasets2/labels/all/'
# 전체 이미지 갯수를 확인합니다.
print(len(os.listdir(image_path)) , len(os.listdir(label_path)))
# val 사이즈 : 전체 이미지의 20%
val_data_num = [round(len(os.listdir(image_path))*0.2), round(len(os.listdir(label_path))*0.2)]
print(val_data_num)
random.seed(2023)
image_file_list = os.listdir(image_path)
label_file_list = os.listdir(label_path)
# 랜덤 추출 (.png)
val_image = random.sample(image_file_list, val_data_num[0])
val_label = random.sample(label_file_list, val_data_num[1])
print(len(val_image))
print(len(val_label))
# 랜덤하게 추출한 png를 지정해둔 경로로 옮김
for file in val_image:
shutil.move(f"/content/drive/MyDrive/Datasets2/images/all/{file}", f"/content/drive/MyDrive/Datasets2/images/val/{file}")
for file in val_label:
shutil.move(f"/content/drive/MyDrive/Datasets2/labels/all/{file}", f"/content/drive/MyDrive/Datasets2/labels/val/{file}")
# all의 모든 파일
images_all = glob.glob('/content/drive/MyDrive/Datasets2/images/all/*.jpg')
labels_all = glob.glob('/content/drive/MyDrive/Datasets2/labels/all/*.json')
# 하나씩 train 파일 옮김
for file in images_all:
shutil.move(f"{file}", f"/content/drive/MyDrive/Datasets2/images/train/")
for file in labels_all:
shutil.move(f"{file}", f"/content/drive/MyDrive/Datasets2/labels/train")
우선 val 데이터를 먼저 옮기고 남은 것은 train으로 옮겼다
5) json 파일내에서 위치, 박스, 클래스 정보를 추출하여 txt 파일로 만드는 과정
import os, json
json_path = '/content/drive/MyDrive/Datasets2/labels/'
temp_list = ['train', 'val']
coin = {'Ten' : 0,
'Fifty' : 1,
'Hundred' : 2,
'Five_Hundred' : 3,
'Thousand' : 4,
'Five_Thousand' : 5,
'Ten_Thousand' : 6,
'Fifty_Thousand' : 7}
train_json = glob.glob('/content/drive/MyDrive/Datasets2/labels/train/*.json')
val_json = glob.glob('/content/drive/MyDrive/Datasets2/labels/val/*.json')
def trans_txt(json_file, idx):
if idx==0:
category='train'
else:
category='val'
for cur in json_file:
data = json.load(open(cur))
shapes = data['shapes']
points = shapes[0]['points']
label = shapes[0]['label']
shape = shapes[0]['shape_type']
x1, y1 = points[0]
x2, y2 = points[1]
image_width = data["imageWidth"]
image_height = data["imageHeight"]
#label 앞 뒤 제거
if label[-1]=='k':
label = label[:len(label)-5]
else:
label = label[:len(label)-6]
#1/4된 x, y 센터 찾기
x1, x2, y1, y2 = x1/5, x2/5, y1/5, y2/5
width = x2 - x1
height = y2 - y1
x_center = x1 + (width/2)
y_center = y1 + (height/2)
#이미지 0~1사이 값으로 만들기
x_center = x_center / (image_width/5)
y_center = y_center / (image_height/5)
width = width / (image_width/5)
height = height / (image_height/5)
#txt 파일로 저장
txt_name = data["imagePath"].split(".")[0] + ".txt"
f = open(f"/content/drive/MyDrive/Datasets2/labels/{category}/{txt_name}", 'w')
f.write(f'{coin[label]} {x_center} {y_center} {width} {height}')
f.close()
trans_txt(train_json, 0)
trans_txt(val_json, 1)
json 파일에서 가져올 정보를 변수에 저장
label의 앞, 뒤를 제거 해주는 작업
→ 'ten_front', 'ten_back' -> 'ten'이므로 front와 back을 구분함
원본의 1/5로 축소
→ x1, x2, y1, y2 좌표, width height도 1/5로 축소한 값으로 변경
마지막으로 필요한 변수값들을 txt 파일에 현재 json파일의 파일명으로 만들어 각각 저장하면 끝!
6) 데이터셋 정보가 담긴 파일 생성
import yaml
won_dict = {0:'10', 1:'50', 2:'100', 3:'500', 4:'1000', 5:'5000', 6:'10000', 7:'50000'}
names = list(won_dict.values())
nc = len(names)
train_path = '/content/drive/MyDrive/Datasets2/images/train'
val_path = '/content/drive/MyDrive/Datasets2/images/val'
dataset_info = {
"names": names,
"nc": nc,
"train": train_path,
"val": val_path,
}
with open('/content/Dataset/coin.yaml', 'w') as f :
yaml.dump(dataset_info, f, default_flow_style=False)
yaml 파일에 class 이름, 수, train, val 위치 정보를 저장한다
모델링
1) 모델 라이브러리 설치
!pip install jedi
!git clone https://github.com/ultralytics/yolov5
temp_str = 'setuptools<=64.0.2\n'
f = open('/content/yolov5/requirements.txt', 'r')
f_str = f.readlines()
f.close()
f2 = open('/content/yolov5/requirements.txt', 'w')
for idx, val in enumerate(f_str) :
if 'setuptools' in val :
idx_v = idx
f_str.remove(val)
f_str.insert(idx_v, temp_str)
for val in f_str :
f2.write(val)
f2.close()
!cd yolov5; pip install -r requirements.txt
2) 가중치 파일 다운로드
%cd /content/yolov5
!wget https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x.pt
3) 학습 : train.py
# train.py
%cd /content/yolov5
!python train.py --img 640 --batch 16 --epochs 20 --data /content/Dataset/coin.yaml --cfg ./models/yolov5x.yaml
--weights yolov5x.pt --name coin_yolov5x_results
train.py를 통해 학습!
이미지 크기는 640, batch는 16, epochs는 20으로 설정
data에는 yaml 파일 경로
weights와 cfg에는 위에서 다운로드한 yolov5x의 파일
마지막으로 결과를 저장할 이름을 설정하고 학습을 진행하면 끝!
yolov5x가 무거운 모델이다 보니 오래 걸림...
4) 탐지 : detect.py
%cd /content/yolov5
!python detect.py --weights /content/yolov5/runs/train/coin_yolov5x_results/weights/best.pt
--img 640 --conf 0.75 --iou 0.25 --source /content/Dataset/images/val
세부 요구사항
- 학습과정에서 생성된 가중치 파일을 이용
- IoU threshold를 0.25이하로 설정
- confidence threshold를 0.75 이상으로 설정
path = '/content/drive/MyDrive/yolov5/runs/detect/exp3/'
result_images = os.listdir(path)
for i in range(10):
name=result_images[i]
before_img = Image.open(f'/content/drive/MyDrive/Datasets2/images/val/{name}')
after_img = Image.open(f'/content/drive/MyDrive/yolov5/runs/detect/exp3/{name}')
plt.figure(figsize=(10,10))
plt.subplot(221)
plt.imshow(before_img)
plt.subplot(222)
plt.imshow(after_img)
plt.show()
직접 촬영한 화폐 사진과 동영상을 탐지 과정에 이용하여 결과를 확인
전처리 과정이 너무너무너무 힘들었던 프로젝트였다..
'mini project' 카테고리의 다른 글
| 네 번째 미니프로젝트 - 1대1 문의 내용 유형 분류기 (0) | 2023.05.06 |
|---|---|
| 다섯 번째 미니 프로젝트 - 스마트폰 센서 데이터 기반 모션 분류 (0) | 2023.04.14 |
| 세 번째 미니프로젝트 - 차량 공유업체의 차량 파손여부 분류 (0) | 2023.03.22 |
| 두 번째 미니프로젝트 - 악성 사이트 탐지 (0) | 2023.03.07 |
| 두 번째 미니 프로젝트 - 미세먼지 예측 머신러닝 모델링 (0) | 2023.03.07 |