본문 바로가기

Study/class note

딥러닝 / 동영상 object detection 주석 설명

# 동영상 오브젝트 디텍션
 
import cv2  #영상이나 이미지 데이터 전처리를 위한 모듈
import numpy as np
 
LABELS = ['gorani','raccoon']  # 라벨 데이터
#gorani, raccoon
 
CONFIDENCE = 0.3  # 사물이 라벨에 해당하는 데이터인지에 대한 확률 임계치
THRESHOLD = 0.3  #NMS(Num Max Suppression)  박스 안에 사물이 존재할 확률의 임계치
 
#yolo4버전으로 학습시킨 환경구성파일과 가중치를 로드해서 신경망 구성
net = cv2.dnn.readNetFromDarknet('c:\\animal\\yolov4_custom.cfg','c:\\animal\\yolov4_custom_final.weights')
 
classes =['gorani','raccoon']  # 화면 박싱할 때 사용할 클래스명을 classes에 담음
 
#cap = cv2.VideoCapture('D:\\test\\New folder\\test1.mp4')  
cap = cv2.VideoCapture('c:\\animal\\test2.mp4') #원본 동영상 위치, 이름 / 영상이 홈디렉토리 밑에 있다면 경로 안써도 됨 -> 가끔 parsing 오류
font = cv2.FONT_HERSHEY_PLAIN  # 디텍션할때 나타나는 폰트
colors = np.random.uniform(0, 255, size=(100, 3))  # 폰트 컬러
 
# 동영상 프레임의 가로와 세로 사이즈 변수에 담음
frame_size = (cap.get(cv2.CAP_PROP_FRAME_WIDTH), cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) 

#생성되는 영상의 동영상 형식을 mp4로 지정
fourcc = cv2.VideoWriter_fourcc(*'mp4v')  
fps = cap.get(cv2.CAP_PROP_FPS) #동영상을 프레임별로 가져옴
 
# 결과 동영상 출력
out = cv2.VideoWriter('c:\\animal\\detections.mp4', fourcc, fps, (int(frame_size[0]), int(frame_size[1])))
 
while True:
    ret, img = cap.read()  # ret변수에는 True가 들어감. 동영상에서 frame을 가져와 img에 담음
    print(img) #동영상에서의 하나의 이미지인 img 출력
    if not ret:  # 더이상 가져오지 않을 경우 False ->  break걸겠다
        break
    # height, width, _ = img.shape  이미지 딱 하나에 대한 높이와 넓이를 구했는데
    
    #이번에는 동영상 frame에 대해 넓이와 높이를 구해야하므로
    # cv2.CAP_PROP_FRAME_WIDTH/HEIGHT를 사용
    width,height = (cap.get(cv2.CAP_PROP_FRAME_WIDTH), cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    
    #동영상 속의 frame 이미지 전처리 함수인 blobFrameImage를 사용해서 학습할 당시에
    #수행했던대로 전처리 되게 함
    blob = cv2.dnn.blobFromImage(img, 1/255, (416, 416), (0,0,0), swapRB=True, crop=False)
    #학습할 당시에 학습 데이터를 정규화 했으면 object detection 할때도(데이터를 넣을때도)
    # 정규화(1/255)를 해야함.
    # 학습할 때 사용했던 이미지 사이즈로 resize 해줘야함. 다크넷 신경망 학습할 때 
    # (416,416)으로 학습함.
    #(0,0,0) (red,green,blue)행렬릐 평균값을 널어서 기존 픽셀 값에서 빼주는 작업을 학습할 때
    # 학습했다면 여기에 그 평균값 3개를 적어줘야함. 안했다면 안적어줘도 됨.
    # 학습할 때 평균값 빼는 이유는 학습이 잘되게 하려고 하는 것같음?
    
    # swapRB = True는 RGB를 BGR로 변경
    # openCV가 RGB가 아니라 BGR순서기 때문에 변경함.
    
    # crop = False 여기서 설명 확인 https://m.blog.daum.net/architekton/97
    
    #학습된 가중치와 환경구성파일이 셋팅된 다크넷 신경망에 전처리된 frame을 넣음
    net.setInput(blob)
    
    #다크넷 신경망에 어느정도 결론이 난 맨 마지막층들의 이름을 가져와서 변수에 담음
    output_layers_names = net.getUnconnectedOutLayersNames()
    layerOutputs = net.forward(output_layers_names) # 마지막 층등을 신경망에 흘려보냄
    # 하나의 사진당 박싱을 하는 윈도우들이 총 507개 생김
    
    # 사물 검출을 위해서 사용할 비어있는 리스트 3개 선언
    boxes = []
    confidences = []
    class_ids = []
 
    for output in layerOutputs:  # 507개의 박스 데이터 하나씩 불러옴
        for detection in output: # 리스트 안에 리스트로 되어 있어서 한번 더 for문 사용해 리스트 안의 요소 가져옴
            scores = detection[5:]  # 507개의 박스에서 고라니와 너구리일 확률 scores에 담음
            class_id = np.argmax(scores)  # [0.960552 0.] 이렇게 될 경우 0이 class_id에 담김
            confidence = scores[class_id]  #[0]이니까 0.960552가 confidence에 담기고
            if confidence > 0.2:  # confidence값이 0.2보다 크면
                center_x = int(detection[0]*width)  #0~1사이로 변경된 좌표값을 실제 좌표로 변경
                center_y = int(detection[1]*height)
                w = int(detection[2]*width)  #실제 가로
                h = int(detection[3]*height) # 실제 높이
 
                x = int(center_x - w/2)  # 박스의 중심 x좌표
                y = int(center_y - h/2)  # 박스의 중심 y좌표
 
                boxes.append([x, y, w, h])  #원하는 사물이 있는 박스 정보를 boxes에 넣음
                confidences.append((float(confidence)))  #0.2보다 큰 확률 데이터를 confidence에 넣음
                class_ids.append(class_id)  #0아니면 1이 class_ids에 담김
 
    indexes = cv2.dnn.NMSBoxes(boxes, confidences, 0.2, 0.4)
    # 여기서 0.2는 사물을 맞힐 확률이고 0.4는 박스 안에 사물이 있을 확률 임계치
    # 임계치보다 더 큰 정보들만 indexes에 담음
     
    if len(indexes)>0:  #indexes에 값이 있다면
        for i in indexes.flatten():  #boxes리스트에 (x,y,w,h)에 대한 정보를 flatten시켜서
            x, y, w, h = boxes[i] #x,y,w,h에 넣음
            label = str(classes[class_ids[i]]) #라벨링 값 담고
            confidence = str(round(confidences[i],2))  # confidence값 넣고
            color = colors[i]
            cv2.rectangle(img, (x,y), (x+w, y+h), color, thickness = 2)
            cv2.putText(img, label + " " + confidence, (x, y+20), font, 2, (255,255,255), 2)
            # cv2의 putText를 이용해 라벨과 확률을 중심좌표에서 y축으로 +20지점에 표시합니다.
                
    cv2.imshow('Image', img)
    
    #cap = cv2.VideoCapture(input_names[0])
    #win_name = 'Video detection'
    #cv2.namedWindow(win_name) 
   
    out.write(img)  #동영상 기록
    
    key = cv2.waitKey(1)  #opencv에서 제공하는 입력을 기다리는 대기 함수를 실행하고
    if key==27: #취소키를 누르면 (esc지정키)
        break  
        
        
out.release()  # 디텍션된 동영상에 대한 데이터가 있는 변수 지움   
cv2.destroyAllWindows()  # 열어높은 동영상 플레이창 닫음

 

 

문제215. 이번에는 정규화 하지 말고 detections2.mp4로 동영상을 생성하시오.

=> 정규화하지 않고 동영상 돌리면 정확도가 현저히 낮아짐. 정규화해서 돌려야함

반응형