728x90
반응형

YOLO - Camera 객체탐지

사용할 라이브러리

import cv2
import numpy as np

데이터 읽어들이기

  • 웹캠 신호 받기
    - 어떤 카메라를 사용할지 채널 선택
    - 여러개의 카메라가 있으면, 카메라 별로 번호가 부여된다.
    - 내 PC에 1개만 연결되어 있다면, 0번 카메라 번호가 부여된다.
    VideoSignal = cv2.VideoCapture(0)
    VideoSignal​

Yolo 모델 생성하기

YOLO_net = cv2.dnn.readNet("./yolo/config/yolov2-tiny.weights",
                          "./yolo/config/yolov2-tiny.cfg")
YOLO_net

 

라벨링 명칭(이름 ) 데이터 읽어들이기

# - coco.names : 인식(감지)된 객체의 레이블 명칭(이름)이 저장된 파일
''' 저장할 변수 정의 '''
classes = []

# open() : 파일 열기
# - 모드 : r 읽기모드, w 쓰기모드, b 바이너리
# as(별칭) f에는 열려있는 파일 정보가 담겨있음
with open("./yolo/config/coco.names", "r") as f :
    # strip() : 왼쪽 오른쪽 공백제거
    # readlines() : 파일 내에 문장들을 행단위로 모두 읽어들이기
    classes = [line.strip() for line in f.readlines()]

classes

출력계층 이름 추출하기

''' YOLO 레이어 전체 추출 '''
layer_names = YOLO_net.getLayerNames()

''' YOLO 출력 레이어(계층)만 추출 '''
output_layer = [layer_names[i - 1] for i in YOLO_net.getUnconnectedOutLayers()]

layer_names, output_layer

 

윈도우 창 관리 영역 : 카메라 영상 처리 영역

import cv2
import numpy as np

VideoSignal = cv2.VideoCapture(0)

YOLO_net = cv2.dnn.readNet("./yolo/config/yolov2-tiny.weights",
                          "./yolo/config/yolov2-tiny.cfg")

classes = []

# open() : 파일 열기
# - 모드 : r 읽기모드, w 쓰기모드, b 바이너리
# as(별칭) f에는 열려있는 파일 정보가 담겨있음
with open("./yolo/config/coco.names", "r") as f :
    # strip() : 왼쪽 오른쪽 공백제거
    # readlines() : 파일 내에 문장들을 행단위로 모두 읽어들이기
    classes = [line.strip() for line in f.readlines()]

''' YOLO 레이어 전체 추출 '''
layer_names = YOLO_net.getLayerNames()

''' YOLO 출력 레이어(계층)만 추출 '''
output_layer = [layer_names[i - 1] for i in YOLO_net.getUnconnectedOutLayers()]

'''
대표 윈도우 설정 
 - 윈도우 창 관리는 이름으로 한다.
'''
cv2.namedWindow("YOLO3_CM_01")

'''
카메라를 통한 영상처리 시에는 윈도우 창을 계속 띄어 놓아야 한다.
 - 정지 옵션(윈도우 창 닫기)은 필수
'''
while True : 
    '''
    카메라에서 영상 읽어들이기 : read() 함수 사용
     - 영상파일 또는 카메라로부터 프레임을 읽어오는 역할 수행
     * ret : 읽어들이는 프레임이 있는지 여부 판단(True or False)
           : 더 이상 읽어들일 프레임이 없으면 False가 됨
     * frame : 실제로 읽어들이는 프레임(이미지) 자체
             : 더 이상 읽어들일 프레임이 없으면 None이 됨
             : 우리가 사용할 변수
    '''
    ret, frame = VideoSignal.read()

    ''' frame 정보에서 높이, 너비, 채널(흑백 또는 컬러) 추출하기 '''
    h, w, c = frame.shape

    ''' --------------------------------------------------------- '''
    ''' BLOB 데이터 구조화 '''
    blob = cv2.dnn.blobFromImage(
        ### 카메라에서 읽어들인 frame(이미지) 데이터
        image = frame,

        ### 이미지 픽셀 값 정규화(스케일링)
        scalefactor = 1/255.0,

        ### Yolo 모델이 사용할 크기로 조정
        size=(416, 416),

        ### BRG, RGB 선택
        # - True이면 OpenCV의 기본 BGR 생상 순서를 RGB로 변경
        swapRB=True,

        ### 위에 size로 조정 후 어떻게 할지 결정
        # - True이면 잘라내기
        # - Fasle이면 size 전체 조정하기
        crop=False
    )

    ''' YOLO 입력 데이터로 넣어주기 '''
    YOLO_net.setInput(blob)

    ''' YOLO모델에 출력계층 이름을 알려주고, 출력 결과 받아오기 '''
    outs = YOLO_net.forward(output_layer)

    ''' 라벨(명칭, 이름) 담을 리스트 변수 '''
    class_ids = []
    ''' 인식률(정확도) 담을 리스트 변수 '''
    confidences = []
    ''' 바운딩 박스의 좌표를 담을 리스트 변수 '''
    boxes = []

    ''' 출력 결과 여러개(인식된 객체 여러개)'''
    for out in outs :
        ''' 실제 객체 인식 데이터 처리 '''
        for detection in out :
            ''' 인식 데이터의 인식률(정밀도) '''
            scores = detection[5:]

            ''' 인식률(정밀도)가 가장 높은 인덱스 위치 얻기 : 라벨(명칭, 이름)의 위치값 '''
            class_id = np.argmax(scores)

            ''' 인식률(정밀도) 값 추출하기 : class_id의 인덱스 번호 위치값이 정밀도 '''
            confidence = scores[class_id]

            ''' 정밀도가 50% 이상인 경우만 처리 : 기준은 자유롭게 정의 '''
            if confidence > 0.5 :
                
                ''' 중앙값의 좌표 비율에 실제 너비로 연산하여 중앙 x값 추출 '''
                center_x = int(detection[0] * w)
                ''' 중앙값의 좌표 비율에 실제 높이로 연산하여 중앙 y값 추출 '''
                center_y = int(detection[1] * h)

                ''' 바운딩 박스의 실제 너비와 높이 계산하기 '''
                dw = int(detection[2]  * w)
                dh = int(detection[3] * h)

                ''' 바운딩 박스의 시작 좌표(x, y) 계산하기 '''
                x = int(center_x - dw /2)
                y = int(center_x - dh / 2)

                boxes.append([x, y, dw, dh])
                confidences.append(float(confidence))
                class_ids.append(class_id)

    ''' 
    중복된 바운딩 박스 제거하기
     -정확도가 0.45보다 작으면 제거
    '''
    indexes = cv2.dnn.NMSBoxes(boxes, confidences, 0.45, 0.4)
    
    ''' 인식된 객체마다 바운딩 박스 처리하기 '''
    for i in range(len(boxes)) :

        ''' 중복 제거 이후 남은 바운딩 박스의 정보만 이용 '''
        if i in indexes :
            ''' 해당 객체에 대한 좌표값 '''
            x, y, w, h = boxes[i]

            ''' 해당 객체에 대한 라벨값 '''
            label = str(classes[class_ids[i]])

            ''' 해당 객체에 대한 정확도 '''
            score = confidences[i]

            ''' 바운딩 박스 그리기 '''
            cv2.rectangle(
                ### 원본 이미지(frame)
                frame,
                ### 시작좌표
                (x, y),
                ### 종료좌표
                (x+w, y+h),
                ### 선 색상
                (0, 0, 255),
                ### 선 굵기
                5
            )

            ''' 라벨, 정확도 이미지에 텍스트 그리기 '''
            cv2.putText(
                ### 지금까지 그려진 frame 이미지
                img = frame,
                ### 추가할 텍스트(문자열 타입으로)
                text = label,
                ### 텍스트 시작위치 지정
                org=(x, y-20),
                ### 텍스트 font 스타일
                fontFace=cv2.FONT_ITALIC,
                ### font 크기
                fontScale=0.5,
                ### font 색상
                color=(255, 255, 255),
                ### font 굵기
                thickness=1
            )
            
    
    ''' 윈도우 창 open하기 '''
    cv2.imshow("YOLO3_CM_01", frame)

    ''' 윈도우 창 크기 조절하기 '''
    cv2.resizeWindow("YOLO3_CM_01", 650, 500)
    
    ''' 키보드에서 아무키 눌리면, while문 종료하기 '''
    if cv2.waitKey(100) > 0 :
        ''' 윈도우 무조건 종료 '''
        cv2.destroyAllWindows()
        break
        
    ''' 키보드에서 q 입력 시 종료시키기 '''
    if cv2.waitKey(1) & 0xFF == ord("q") :
        ''' 윈도우 무조건 종료 ''' 
        cv2.destroyAllWindows()
        break

'''
위도우 종료 후 재실행 시 안되는 경우가 발생할 수 있음.
이때는 주피터가 실행된 프롬프트 창에서 [CTRL+C]
'''

 

YOLO - Camera 객체탐지 이미지로 추출하기

  • 정확도가 0.8 이상일 때 이미지 저장
import cv2
import numpy as np

VideoSignal = cv2.VideoCapture(0)

YOLO_net = cv2.dnn.readNet("./yolo/config/yolov2-tiny.weights",
                          "./yolo/config/yolov2-tiny.cfg")

classes = []

# open() : 파일 열기
# - 모드 : r 읽기모드, w 쓰기모드, b 바이너리
# as(별칭) f에는 열려있는 파일 정보가 담겨있음
with open("./yolo/config/coco.names", "r") as f :
    # strip() : 왼쪽 오른쪽 공백제거
    # readlines() : 파일 내에 문장들을 행단위로 모두 읽어들이기
    classes = [line.strip() for line in f.readlines()]

''' YOLO 레이어 전체 추출 '''
layer_names = YOLO_net.getLayerNames()

''' YOLO 출력 레이어(계층)만 추출 '''
output_layer = [layer_names[i - 1] for i in YOLO_net.getUnconnectedOutLayers()]

cv2.namedWindow("YOLO3_CM_01")


############################
### 인식된 객체 이미지로 저장
# - 이미지 파일 저장 시 파일명에 번호 붙이기
img_cnt = 1
############################

'''
카메라를 통한 영상처리 시에는 윈도우 창을 계속 띄어 놓아야 한다.
 - 정지 옵션(윈도우 창 닫기)은 필수
'''
while True : 
    '''
    카메라에서 영상 읽어들이기 : read() 함수 사용
     - 영상파일 또는 카메라로부터 프레임을 읽어오는 역할 수행
     * ret : 읽어들이는 프레임이 있는지 여부 판단(True or False)
           : 더 이상 읽어들일 프레임이 없으면 False가 됨
     * frame : 실제로 읽어들이는 프레임(이미지) 자체
             : 더 이상 읽어들일 프레임이 없으면 None이 됨
             : 우리가 사용할 변수
    '''
    ret, frame = VideoSignal.read()

    ''' frame 정보에서 높이, 너비, 채널(흑백 또는 컬러) 추출하기 '''
    h, w, c = frame.shape

    ''' --------------------------------------------------------- '''
    ''' BLOB 데이터 구조화 '''
    blob = cv2.dnn.blobFromImage(
        ### 카메라에서 읽어들인 frame(이미지) 데이터
        image = frame,

        ### 이미지 픽셀 값 정규화(스케일링)
        scalefactor = 1/255.0,

        ### Yolo 모델이 사용할 크기로 조정
        size=(416, 416),

        ### BRG, RGB 선택
        # - True이면 OpenCV의 기본 BGR 생상 순서를 RGB로 변경
        swapRB=True,

        ### 위에 size로 조정 후 어떻게 할지 결정
        # - True이면 잘라내기
        # - Fasle이면 size 전체 조정하기
        crop=False
    )

    ''' YOLO 입력 데이터로 넣어주기 '''
    YOLO_net.setInput(blob)

    ''' YOLO모델에 출력계층 이름을 알려주고, 출력 결과 받아오기 '''
    outs = YOLO_net.forward(output_layer)

    ''' 라벨(명칭, 이름) 담을 리스트 변수 '''
    class_ids = []
    ''' 인식률(정확도) 담을 리스트 변수 '''
    confidences = []
    ''' 바운딩 박스의 좌표를 담을 리스트 변수 '''
    boxes = []

    ''' 출력 결과 여러개(인식된 객체 여러개)'''
    for out in outs :
        ''' 실제 객체 인식 데이터 처리 '''
        for detection in out :
            ''' 인식 데이터의 인식률(정밀도) '''
            scores = detection[5:]

            ''' 인식률(정밀도)가 가장 높은 인덱스 위치 얻기 : 라벨(명칭, 이름)의 위치값 '''
            class_id = np.argmax(scores)

            ''' 인식률(정밀도) 값 추출하기 : class_id의 인덱스 번호 위치값이 정밀도 '''
            confidence = scores[class_id]

            ''' 정밀도가 50% 이상인 경우만 처리 : 기준은 자유롭게 정의 '''
            if confidence > 0.5 :
                
                ''' 중앙값의 좌표 비율에 실제 너비로 연산하여 중앙 x값 추출 '''
                center_x = int(detection[0] * w)
                ''' 중앙값의 좌표 비율에 실제 높이로 연산하여 중앙 y값 추출 '''
                center_y = int(detection[1] * h)

                ''' 바운딩 박스의 실제 너비와 높이 계산하기 '''
                dw = int(detection[2]  * w)
                dh = int(detection[3] * h)

                ''' 바운딩 박스의 시작 좌표(x, y) 계산하기 '''
                x = int(center_x - dw /2)
                y = int(center_x - dh / 2)

                boxes.append([x, y, dw, dh])
                confidences.append(float(confidence))
                class_ids.append(class_id)

    ''' 
    중복된 바운딩 박스 제거하기
     -정확도가 0.45보다 작으면 제거
    '''
    indexes = cv2.dnn.NMSBoxes(boxes, confidences, 0.45, 0.4)
    
    ''' 인식된 객체마다 바운딩 박스 처리하기 '''
    for i in range(len(boxes)) :

        ''' 중복 제거 이후 남은 바운딩 박스의 정보만 이용 '''
        if i in indexes :
            ''' 해당 객체에 대한 좌표값 '''
            x, y, w, h = boxes[i]

            ''' 해당 객체에 대한 라벨값 '''
            label = str(classes[class_ids[i]])

            ''' 해당 객체에 대한 정확도 '''
            score = confidences[i]

            ''' 바운딩 박스 그리기 '''
            cv2.rectangle(
                ### 원본 이미지(frame)
                frame,
                ### 시작좌표
                (x, y),
                ### 종료좌표
                (x+w, y+h),
                ### 선 색상
                (0, 0, 255),
                ### 선 굵기
                5
            )

            ''' 라벨, 정확도 이미지에 텍스트 그리기 '''
            cv2.putText(
                ### 지금까지 그려진 frame 이미지
                img = frame,
                ### 추가할 텍스트(문자열 타입으로)
                text = label,
                ### 텍스트 시작위치 지정
                org=(x, y-20),
                ### 텍스트 font 스타일
                fontFace=cv2.FONT_ITALIC,
                ### font 크기
                fontScale=0.5,
                ### font 색상
                color=(255, 255, 255),
                ### font 굵기
                thickness=1
            )
            
    
    ''' 윈도우 창 open하기 '''
    cv2.imshow("YOLO3_CM_01", frame)

    ''' 윈도우 창 크기 조절하기 '''
    cv2.resizeWindow("YOLO3_CM_01", 650, 500)


    ###########################################################
    ###  이미지로 저장하기
    print(f">>>>>>>>>>>>>>정확도 평균 : {np.mean(confidences)}")

    ### 정확도 평균이 0.8이상인 경우만 저장시키기
    if np.mean(confidences) >= 0.8 :
        # 이미지 저장 함수 : imwrite() 함수 사용
        cv2.imwrite(f"./yolo/images_new/img_{img_cnt}.jpg", frame)
        img_cnt = img_cnt + 1
    ############################################################
    
    ''' 키보드에서 아무키 눌리면, while문 종료하기 '''
    if cv2.waitKey(100) > 0 :
        ''' 윈도우 무조건 종료 '''
        cv2.destroyAllWindows()
        break
        
    ''' 키보드에서 q 입력 시 종료시키기 '''
    if cv2.waitKey(1) & 0xFF == ord("q") :
        ''' 윈도우 무조건 종료 ''' 
        cv2.destroyAllWindows()
        break

'''
위도우 종료 후 재실행 시 안되는 경우가 발생할 수 있음.
이때는 주피터가 실행된 프롬프트 창에서 [CTRL+C]
'''

 

728x90
반응형

+ Recent posts