📌 목차

1. YOLO v3로 정지영상에서 Object Detection하기
2. YOLO v3로 비디오에서 Object Detection하기(랩탑 캠사용)

 

0.  파일준비 및 YOLO v3 공통코드

먼저 자신의 로컬 폴더에 다음 3개의 파일이 있어야한다.
'coco_names.txt' (이 파일은 1~80행까지 복사후 txt파일을 생성해 붙여넣는다.)
'yolov3.weights'
'yolov3.cfg'


이후 아래 코드에 대해 설명해보겠다.
- 5~13행: YOLO 모델 구성함수
- 15~38행: YOLO모델로 img영상에서 물체탐지 후 반환하는 함수
def construct_yolo_v3():
    f=open('coco_names.txt', 'r')
    class_names=[line.strip() for line in f.readlines()]

    model=cv.dnn.readNet('yolov3.weights','yolov3.cfg')
    layer_names=model.getLayerNames()
    out_layers=[layer_names[i-1] for i in model.getUnconnectedOutLayers()]
    
    return model,out_layers,class_names

def yolo_detect(img,yolo_model,out_layers):
    height,width=img.shape[0],img.shape[1]
    test_img=cv.dnn.blobFromImage(img,1.0/256,(448,448),(0,0,0),swapRB=True)
    
    yolo_model.setInput(test_img)
    output3=yolo_model.forward(out_layers)
    
    box,conf,id=[],[],[]		# 박스, 신뢰도, 클래스 번호
    for output in output3:
        for vec85 in output:
            scores=vec85[5:]
            class_id=np.argmax(scores)
            confidence=scores[class_id]
            if confidence>0.5:	# 신뢰도가 50% 이상인 경우만 취함
                centerx,centery=int(vec85[0]*width),int(vec85[1]*height)
                w,h=int(vec85[2]*width),int(vec85[3]*height)
                x,y=int(centerx-w/2),int(centery-h/2)
                box.append([x,y,x+w,y+h])
                conf.append(float(confidence))
                id.append(class_id)
            
    ind=cv.dnn.NMSBoxes(box,conf,0.5,0.4)
    objects=[box[i]+[conf[i]]+[id[i]] for i in range(len(box)) if i in ind]
    return objects

model,out_layers,class_names=construct_yolo_v3()		# YOLO 모델 생성
colors=np.random.uniform(0,255,size=(len(class_names),3))	# 클래스마다 색깔​

 

05~13행의 construct_yolo_v3 함수를 살펴보자.
∙ 06~07행은 COCO 데이터셋의 클래스이름을 담고 있는 coco_names. txt 파일에서 클래스 이름을 읽어 class_names에 저장한다.

09행은 YOLO v3 모델 정보를 파일에서 읽어 yolo_model 객체에 저장한다.

yolov3.weights 파일에서는 신경망의 가중치 정보를 읽어오고 yolov3.cfg 파일에서는 신경망의 구조 정보를 가져온다.

10~11행은 getUnconnectedOutLayers 함수를 이용하여 yolo 82, yolo 94, yolo_106 층을 알아내어 out_layers 객체에 저장한다.

13행은 모델, 층, 클래스 이름을 담은 객체를 반환한다.


15~38행의 yolo_detect 함수를 살펴보자.
16행은 원본 영상인 img의 높이와 너비 정보를 height와 width에 저장한다.

17행은 OpenCV의 blobFromImage 함수로 영상을 YOLO에 입력할 수 있는 형태로 변환해 test_img에 저장한다.
이 함수는 [0,255] 범위의 화솟값을 [0,1]로 변환하고 영상 크기를 448 X 448로 변환하며 BGR 순서를 RGB로 바꾼다.원본 영상은 img에 남아있다.

19행은 test_img에 저장되어 있는 영상을 신경망에 입력한다.

20행은 신경망의 전방 계산을 수행하는데, out layers가 출력한 텐서를 output3 객체에 저장한다.
이로 인해 Ouput3 객체는 아래 3가지 텐서를 갖는다.
14×14×85×3,
28×28×85×3,
56×56×85×3 

 22~34행은 output3 객체로부터 물체 위치를 나타내는 박스 정보와 함께 물체 클래스와 신뢰도 정보를 추출한다.
22행은 박스와 신뢰도, 클래스정보를 저장할 리스트를 생성한다.
23행은 세 개의 텐서를 각각반복 처리하며
24행은 85차원 벡터를 반복 처리한다.
85 차원 벡터는 (x, y, w, h,o, p1. p2, … p80)으로 표현되며
앞의 네 요소는 박스, o는 신뢰도, 뒤의 80개 요소는 클래스확률이다.

 25~27행은 뒤의 80개 요소 값에서 최고 확률에 해당하는 클래스를 알아내 클래스 번호는 class_id, 확률은 confidence에 저장한다.

 28행은 confidence가 0.5보다 크지 않으면 버린다.
0.5보다 크면 29~31행에서 [0,1] 범위로 표현된 박스를 원래 영상 좌표 계로 변환해
왼쪽 위의 위치를 x와 y, 너비와 높이를 w와 h에 저장한다.

 32~34행은 박스와 신뢰도, 클래스 정보를 리스트에 추가한다. 박스는 왼쪽 위와 오른쪽 아래 구석 좌표를 저장한다.


 22~34행으로 검출한 박스들에는 상당한 중복성이 있다.
즉, 이전시간에 설명한 그림에서 빨간색 유니폼 선수를 검출한 박스가 검은색 칸에만 나타나지 않고 그 주위에 여럿 나타나는 현상이다.

 36행의 NMSBoxes 함수는 박스를 대상으로 비최대 억제를 적용해 중복성을 제거한다.

 37행 은 비최대 억제에서 살아남은 박스의 위치, 신뢰도, 클래스 이름을 모아 objects 객체에 저장한다.

 38행은 objects를 반환한다.

∙ 40행은 contruct yolo_v3 함수로 YOLO 모델을 구성한다.

∙ 41 행은 물체 클래스를 고유한 색으로 표시하기 위해 컬러 목록을 만들어 colors 객체에 저장한다.

 

 

 


1. YOLO v3로 정지영상에서 Object Detection하기

메인 프로그램이 시작되는 
∙ 43행은 입력 영상을 읽어 img에 저장한다.
∙ 46행은 yolo_detect 함수로 원본 영상 img에서 물체를 검출해 res에 저장한다.
∙ 48~52행은 res에 있는 박스와 클래스 이름, 신뢰도를 영상에 표시한다.

프로그램 실행 결과를 보면, 왼쪽과 오른쪽 선수를 각각 100%와 94.1% 신뢰도의 person 클래스로 제대로 검출했다.
또한 축구공을 99.9% 신뢰도로 sports ball 클래스로 옳게 검출했다.
img=cv.imread('soccer.jpg')
if img is None: sys.exit('파일이 없습니다.')

res=yolo_detect(img,model,out_layers)	# YOLO 모델로 물체 검출

for i in range(len(res)):			# 검출된 물체를 영상에 표시
    x1,y1,x2,y2,confidence,id=res[i]
    text=str(class_names[id])+'%.3f'%confidence
    cv.rectangle(img,(x1,y1),(x2,y2),colors[id],2)
    cv.putText(img,text,(x1,y1+30),cv.FONT_HERSHEY_PLAIN,1.5,colors[id],2)

plt.imshow(img[...,::-1])

 

 

 

 

 

 

 

 

 

 

 

 


2. YOLO v3로 비디오에서 Object Detection하기 (랩탑 캠사용)

∙ 43~64행은 웹 캠에서 비디오를 읽어 디스플레이하는 코드에 YOLO를 적용한다.
∙ 50행은 비디오에서 획득한 현재 프레임을 yolo_detect 함수에 입력해 물체를 검출하고 결과를 res에 저장한다.
∙ 52~56행은 검출한 물체 정보를 영상에 표시한다. 
cap=cv.VideoCapture(0)
if not cap.isOpened(): sys.exit('카메라 연결 실패')

while True:
    ret,frame=cap.read()
    if not ret: sys.exit('프레임 획득에 실패하여 루프를 나갑니다.')
        
    res=yolo_detect(frame,model,out_layers)   
 
    for i in range(len(res)):
        x1,y1,x2,y2,confidence,id=res[i]
        text=str(class_names[id])+'%.3f'%confidence
        cv.rectangle(frame,(x1,y1),(x2,y2),colors[id],2)
        cv.putText(frame,text,(x1,y1+30),cv.FONT_HERSHEY_PLAIN,1.5,colors[id],2)
    
    cv.imshow("Object detection from video by YOLO v.3",frame)
    
    key=cv.waitKey(1) 
    if key==ord('q'): break

 

+ Recent posts