총 6개의 Class(chip, crispy, almond, gum, coffee, pepero)를 위에서 내려다보는 각도에 고정시킨 카메라로 볼 때 Object detection 결과를 확인하는 프로젝트를 수행했습니다.
1차 (학습 : 12000번)
물체의 옆 면과 윗면을 돌리면서 물체 자체를 회전시키는 데이터셋을 만들었습니다.
Class 1 (원본 11개, rotate 396개, 총 407개) Class 2 (원본 9개, rotate 346개, 총 355개) Class 3 (원본 7개, rotate 504개, 총 511개) Class 4 (원본 18개, rotate 630개, 총 648개) Class 5 (원본 10개, rotate 489개, 총 499개) Class 6 (원본 10개, rotate 539개, 총 549개)
★ 문제점
-> 두 개 이상의 object를 붙여 놓았을 때 bounding box가 잘 잡히지 않고 인식을 제대로 못 함 -> 두 개 이상의 object를 붙여 놓은 dataset 만들기 -> 학습시킨 object들 이외의 물건을 인식하는 경우가 있었습니다. -> 몇 개의 object는 scale이 작아졌을 때 인식을 제대로 못했습니다. -> 2차에서는 2, 3 object dataset과 4, 5 object dataset 학습 / 1 object 배경이 다른 dataset 학습 / 모든 dataset을 학습 / 1, 6 object dataset 학습
rotation을 많이 시키면 bounding box가 필요 이상으로 커져 회전을 많이 시키지 않은 dataset 사용했습니다.
Class 2, 3 (원본 263개, rotate 790개, 총 1053개) Class 4, 5 (원본 102개, rotate 503개, 총 605개)
★ 문제점
-> pepero, coffee, gum, chip을 붙여 놓았을 때 coffee와 gum이 잘 인식이 안됐습니다. -> coffee, almond, chip을 붙여 놓았을 때 coffee나 almond가 잘 인식이 안됐습니다. -> crispy와 almond를 붙여 놓았을 때 label은 잡았으나 crispy의 영역이 넓게 잡히는 등 여전히 object들을 붙여 놓았을 때 인식이 잘 되지 않음을 확인했습니다.
● 배경을 다르게 한 1 object(학습 : 10000번)
Class 1 (원본 21개, rotate 63개, 총 84개) Class 2 (원본 33개, rotate 99개, 총 132개) Class 3 (원본 44개, rotate 132개, 총 176개) Class 4 (원본 17개, rotate 51개, 총 68개) Class 5 (원본 28개, rotate 84개, 총 112개) Class 6 (원본 47개, rotate 138개, 총 185개)
★ 문제점
-> 카메라를 고정시키고 test를 해봤으나 많이 가려진 object는 잘 인식하지 못했습니다. -> json파일을 분석해 본 결과 Precision이 매우 높게 나와 대부분의 object들을 잘 인식하는 것으로 확인했습니다.
● 모든 dataset(학습 : 15000번)
-> webcam으로 확인해 본 결과 육안으로 object들을 놓았을 때 잘 인식하는 것을 확인했습니다. -> 그러나 mAP를 확인해 본 결과 FN, FP의 개수가 있는 것으로 보아 잘 인식하지 못하는 image가 있음을 확인했습니다.
● 1, 6 object dataset(학습 : 20000번)
Class 6 (원본 7개, rotate 280개, 총 287개)
★ 문제점
-> 검은색 물체 edge 부분이 흐려지면 잘 인식하지 못했습니다. -> 흰색 배경이 아닌 곳에서 webcam으로 test, object가 없는 부분을 object로 인식하는 경우가 있었습니다. -> crispy와 pepero의 특징을 잘 잡지 못한 것으로 보입니다.
MAP(Mean Average Precision)
대표적으로 Object 4, 5 학습 MAP을 가져왔습니다.
<Result.json 파일 분석 결과>
Test data : object 3, 5(train시키지 않은), 6개 img
<FN example>
정답 class = [0, 2, 3, 4, 5] 검출 class = [4, 3, 2]
-> TP : 4, 3, 2 총 3개 -> FP : x -> FN : 0, 5 총 2개
<FP example>
★ 문제점 : class 개수가 같으면 TP 로 처리했기 때문에 AlexeyAB의 mAP과 차이가 납니다.
IoU(Intersection over Union)을 고려하면 더 정확한 결과가 나올 것이라고 생각됩니다.
정답 class = [0, 2, 3, 4, 5] 검출 class = [4, 5, 3, 2, 0]
-> TP : 0, 2, 3, 4 총 4개 -> 실제 TP : 2, 3, 4 -> FP : 4 총 1개-> 실제 FP : 0, 4 -> FN : x
<TP example>
정답 class = [0, 1, 2, 3, 4] 검출 class = [4, 3, 2, 1, 0]
-> TP : 0, 1, 2, 3, 4 총 5개
결론
object들을 붙여 놓았을 때 edge검출이 잘 되지 않음을 확인했습니다. 배경을 다르게 해서 찍은 dataset이나 object들을 붙여 놓은 dataset을 많이 train한 시도들에서는 test에서나 mAP를 확인해본 결과 잘 인식하는 것을 확인했습니다. 이 문제 이외에 crispy와 pepero object에서 특징을 잘 뽑아내지 못하는 것을 확인했습니다. 이 문제는 배경이 다른 1 object train과 1~6object train 모두에서 발견된 문제점으로 더 개선되어야 할 점으로 생각됩니다.
3차로 더 train시킨다면
-> crispy와 pepero의 train dataset을 좀 더 넣어보기.(좀 더 여러 방향에서 찍은 dataset) -> object가 많이 가려진 dataset도 넣어보기.
Yolo V3 데이터 셋 박스 코드 (객체가 여러 개일 때)
import cv2
import math
## ! 수정하는 부분
def read_file(txt_file):
lst = []
original_rectangle = [0]*6
class_num = []
center = []
rectangle = [0]*6
# print(original_rectangle)
for line in txt_file:
lst = list(map(float, line.strip().split()))
# lst[0] = class 번호
# lst[1] = x_center / width
# lst[2] = y_center / height
# lst[3] = w / width
# lst[4] = h / height
class_num.append(int(lst[0]))
x_center = width * lst[1]
y_center = height * lst[2]
center.append((x_center, y_center))
w = width * lst[3]
h = height * lst[4]
rectangle[int(lst[0])] = (w, h)
# print(x_center, y_center, w, h)
# class 번호 index에 좌표값 저장
left_top_x = int(x_center - w / 2)
left_top_y = int(y_center - h / 2)
right_top_x = int(x_center + w / 2)
right_top_y = int(y_center - h / 2)
right_bottom_x = int(x_center + w / 2)
right_bottom_y = int(y_center + h / 2)
left_bottom_x = int(x_center - w / 2)
left_bottom_y = int(y_center + h / 2)
original_rectangle[int(lst[0])] = [(left_top_x, left_top_y), (right_top_x, right_top_y),
(right_bottom_x, right_bottom_y), (left_bottom_x, left_bottom_y)]
return original_rectangle, class_num, center, rectangle
def rotate_img(image, th):
matrix = cv2.getRotationMatrix2D((width / 2, height / 2), th, 1)
dst = cv2.warpAffine(image, matrix, (width, height))
return dst
def draw_rectangle(image, o, class_num):
for j in class_num:
cv2.rectangle(image, o[j][0], o[j][2], (0, 30*j, 0), 2)
def rotation(image, c_num, center, rect, count):
class_num = 0
_count = 0
flag = 0
for cx, cy in center:
c = c_num[class_num]
_count = count
for i in range(10, 360, 10):
img_theta = i
rot_img = rotate_img(image, img_theta)
theta = math.radians(360 - img_theta)
a = int((cx - width / 2) * math.cos(theta) - (cy - height / 2) * math.sin(theta) + width / 2)
b = int((cx - width / 2) * math.sin(theta) + (cy - height / 2) * math.cos(theta) + height / 2)
rct = ((a, b), (rect[c][0], rect[c][1]), -img_theta)
box = cv2.boxPoints(rct).astype(int)
# cv2.polylines(rot_img, [box], True, (255, 0, 0), 2)
l_b = list(box)
x = []
y = []
for k in range(len(l_b)):
x.append(l_b[k][0])
y.append(l_b[k][1])
# cv2.rectangle(rot_img, (min(x), min(y)), (max(x), max(y)), (0, 0, 255), 2)
rw = max(x) - min(x)
rh = max(y) - min(y)
d3 = rw / width
d4 = rh / height
d1 = (min(x) + (rw/2)) / width
d2 = (min(y) + (rh/2)) / height
# print(c, d1, d2, d3, d4)
direct = 'C:\\Users\\cosge\\Desktop\\image\\train{}.txt'.format(_count) ## ! 파일 이름, 경로 수정
i_dir = 'C:\\Users\\cosge\\Desktop\\image\\train{}.jpg'.format(_count) ## ! 파일 이름, 경로 수정
# print(_count)
cv2.imwrite(i_dir, rot_img)
data = '{} {} {} {} {}\n'.format(c, d1, d2, d3, d4)
f = open(direct, mode='a', encoding='utf-8')
f.write(data)
_count += 1
cv2.imshow('img2', rot_img)
key = cv2.waitKey(1)
if key == 27:
flag = 1
break
class_num += 1
if flag == 1:
break
return _count
#
# key = cv2.waitKey(0)
# cv2.destroyAllWindows()
############MAIN################
count = 28 # train image 원본 개수 + 1 ## ! 원본 이미지 파일 번호 +1로 수정
for number in range(28): ## 원본 이미지 개수 = 28개, 번호 0~27 ## ! count와 같은 수로 수정
filename = 'C:\\Users\\cosge\\Desktop\\image\\train{}.jpg'.format(number) ## ! 파일 이름, 경로 수정
txt = 'C:\\Users\\cosge\\Desktop\\image\\train{}.txt'.format(number) ## ! 파일 이름, 경로 수정
img = cv2.imread(filename)
height, width, channel = img.shape
# print(width, height)
t = open(txt, mode='rt', encoding='utf-8')
origin, c_num, center, rect = read_file(t)
print(c_num)
# draw_rectangle(img, origin, c_num)
# print(origin)
count = rotation(img, c_num, center, rect, count)
# cv2.imshow('img', img)
MAP 비교 코드
import json
#### json 파일 열기 ####
with open('/home/moon/Alexey/darknet/result.json', 'r') as f:
json_data = json.load(f)
#### test.txt파일 읽기 ####
jpg = []
with open('/home/moon/darknet/data/test.txt', 'r') as t:
for line in t:
jpg.append(line.strip().replace('jpg', 'txt'))
print(jpg)
class_id = [[] for _ in range(len(json_data))]
# print(class_id)
#### json 파일 읽기 ####
for test_number in range(len(json_data)):
# print("test_number", test_number)
# print("objects", json_data[test_number]["objects"])
# for object_number in range(len(json_data[test_number]["objects"])):
# print(json_data[test_number]["objects"][object_number])
for class_id_number in range(len(json_data[test_number]["objects"])):
class_id[test_number].append(json_data[test_number]["objects"][class_id_number]["class_id"])
# print(json_data[test_number]["objects"][class_id_number]["class_id"])
answer = [[] for _ in range(len(json_data))]
count = 0
for file in jpg:
with open(file, 'r') as a:
for line in a:
answer[count].append(int(line[0]))
count += 1
# print(json_data[0]["objects"][0])
# print(len(json_data[0]["objects"]))
# print(json.dumps(json_data, indent="\t") )
print("answer = ", answer)
print("prediction = ", class_id)
total_prediction = 0 # 검출된 class 개수
total_answer = 0 # 실제 class 개수
TP = 0 # 예측 개수 중 맞은 것
FN = 0 # 예측에 포함되지 않은 것
FP = 0 # 예측에는 있으나 실제는 없는 것
Precision = 0 # 검출된 것 중 맞는 것(class / 검출된 것들(json에서 나온 class 개수, number) = TP / total_prediction
Recall = 0 # 검출된 것 중 맞는 것 / 실제 개수(jpg.txt파일에 있는 class 개수, number) = TP / total_answer
for i in range(len(json_data)):
print("=======================")
print(json_data[i]["filename"])
print(answer[i])
print(class_id[i])
total_answer += len(answer[i])
total_prediction += len(class_id[i])
tp = 0
fp = 0
fn = 0
for _answer in answer[i]:
fp = 0
for _predict in class_id[i]:
fp = 0
if _answer == _predict:
TP += 1 # 총 TP 수
tp += 1 # 한 개의 img 당 검출된 tp 개수
fp = len(class_id[i]) - tp # 틀린 검출
if len(answer[i]) > len(class_id[i]):
fn = len(answer[i]) - (tp + fp) # 검출되어야 할 것이 검출되지 않았음
else:
fn = 0 # 검출되어야 할 것이 검출되지 않았음
break
fp = len(class_id[i]) - tp # 틀린 검출
# fn = len(answer[i]) - (tp + fp) # 검출되어야 할 것이 검출되지 않았음
print("fp = ", fp)
FP += fp
print("tp = ", tp)
FN += fn
print("fn = ", fn)
print("=====================")
print("TP = ", TP)
print("FP = ", FP)
print("FN = ", FN)
print("Precision = ", TP/total_prediction)
print("Recall = ", TP/total_answer)
[Yolo V3] 편의점 물품 객체 인식
총 6개의 Class(chip, crispy, almond, gum, coffee, pepero)를 위에서 내려다보는 각도에 고정시킨 카메라로 볼 때 Object detection 결과를 확인하는 프로젝트를 수행했습니다.
1차 (학습 : 12000번)
물체의 옆 면과 윗면을 돌리면서 물체 자체를 회전시키는 데이터셋을 만들었습니다.
Class 1 (원본 11개, rotate 396개, 총 407개)
Class 2 (원본 9개, rotate 346개, 총 355개)
Class 3 (원본 7개, rotate 504개, 총 511개)
Class 4 (원본 18개, rotate 630개, 총 648개)
Class 5 (원본 10개, rotate 489개, 총 499개)
Class 6 (원본 10개, rotate 539개, 총 549개)
★ 문제점
-> 두 개 이상의 object를 붙여 놓았을 때 bounding box가 잘 잡히지 않고 인식을 제대로 못 함 -> 두 개 이상의 object를 붙여 놓은 dataset 만들기
-> 학습시킨 object들 이외의 물건을 인식하는 경우가 있었습니다.
-> 몇 개의 object는 scale이 작아졌을 때 인식을 제대로 못했습니다.
-> 2차에서는 2, 3 object dataset과 4, 5 object dataset 학습 / 1 object 배경이 다른 dataset 학습 / 모든 dataset을 학습 / 1, 6 object dataset 학습
2차
● 2, 3 object(학습 : 16000번) vs. 4, 5 object (학습 : 17000번)
rotation을 많이 시키면 bounding box가 필요 이상으로 커져 회전을 많이 시키지 않은 dataset 사용했습니다.
Class 2, 3 (원본 263개, rotate 790개, 총 1053개)
Class 4, 5 (원본 102개, rotate 503개, 총 605개)
★ 문제점
-> pepero, coffee, gum, chip을 붙여 놓았을 때 coffee와 gum이 잘 인식이 안됐습니다.
-> coffee, almond, chip을 붙여 놓았을 때 coffee나 almond가 잘 인식이 안됐습니다.
-> crispy와 almond를 붙여 놓았을 때 label은 잡았으나 crispy의 영역이 넓게 잡히는 등 여전히 object들을 붙여 놓았을 때 인식이 잘 되지 않음을 확인했습니다.
● 배경을 다르게 한 1 object(학습 : 10000번)
Class 1 (원본 21개, rotate 63개, 총 84개)
Class 2 (원본 33개, rotate 99개, 총 132개)
Class 3 (원본 44개, rotate 132개, 총 176개)
Class 4 (원본 17개, rotate 51개, 총 68개)
Class 5 (원본 28개, rotate 84개, 총 112개)
Class 6 (원본 47개, rotate 138개, 총 185개)
★ 문제점
-> 카메라를 고정시키고 test를 해봤으나 많이 가려진 object는 잘 인식하지 못했습니다.
-> json파일을 분석해 본 결과 Precision이 매우 높게 나와 대부분의 object들을 잘 인식하는 것으로 확인했습니다.
● 모든 dataset(학습 : 15000번)
-> webcam으로 확인해 본 결과 육안으로 object들을 놓았을 때 잘 인식하는 것을 확인했습니다.
-> 그러나 mAP를 확인해 본 결과 FN, FP의 개수가 있는 것으로 보아 잘 인식하지 못하는 image가 있음을 확인했습니다.
● 1, 6 object dataset(학습 : 20000번)
Class 6 (원본 7개, rotate 280개, 총 287개)
★ 문제점
-> 검은색 물체 edge 부분이 흐려지면 잘 인식하지 못했습니다.
-> 흰색 배경이 아닌 곳에서 webcam으로 test, object가 없는 부분을 object로 인식하는 경우가 있었습니다.
-> crispy와 pepero의 특징을 잘 잡지 못한 것으로 보입니다.
MAP(Mean Average Precision)
대표적으로 Object 4, 5 학습 MAP을 가져왔습니다.
<Result.json 파일 분석 결과>
Test data : object 3, 5(train시키지 않은), 6개 img
<FN example>
정답 class = [0, 2, 3, 4, 5]
검출 class = [4, 3, 2]
-> TP : 4, 3, 2 총 3개
-> FP : x
-> FN : 0, 5 총 2개
<FP example>
★ 문제점 : class 개수가 같으면 TP 로 처리했기 때문에 AlexeyAB의 mAP과 차이가 납니다.
IoU(Intersection over Union)을 고려하면 더 정확한 결과가 나올 것이라고 생각됩니다.
정답 class = [0, 2, 3, 4, 5]
검출 class = [4, 5, 3, 2, 0]
-> TP : 0, 2, 3, 4 총 4개 -> 실제 TP : 2, 3, 4
-> FP : 4 총 1개 -> 실제 FP : 0, 4
-> FN : x
<TP example>
정답 class = [0, 1, 2, 3, 4]
검출 class = [4, 3, 2, 1, 0]
-> TP : 0, 1, 2, 3, 4 총 5개
결론
object들을 붙여 놓았을 때 edge검출이 잘 되지 않음을 확인했습니다. 배경을 다르게 해서 찍은 dataset이나 object들을 붙여 놓은 dataset을 많이 train한 시도들에서는 test에서나 mAP를 확인해본 결과 잘 인식하는 것을 확인했습니다. 이 문제 이외에 crispy와 pepero object에서 특징을 잘 뽑아내지 못하는 것을 확인했습니다. 이 문제는 배경이 다른 1 object train과 1~6object train 모두에서 발견된 문제점으로 더 개선되어야 할 점으로 생각됩니다.
3차로 더 train시킨다면
-> crispy와 pepero의 train dataset을 좀 더 넣어보기.(좀 더 여러 방향에서 찍은 dataset)
-> object가 많이 가려진 dataset도 넣어보기.
Yolo V3 데이터 셋 박스 코드 (객체가 여러 개일 때)
MAP 비교 코드
'Project > Project' 카테고리의 다른 글