본문 바로가기

인공지능/딥러닝

[YOLO] YOLO 카메라 객체탐지

~ 목차 ~

 

 

 

웹캠 신호 받기 ✨

 

 

* 웹캠 신호 받기

 - 어떤 카메라를 사용할지 채널 선택
 - 여러개의 카메라가 있으면, 카메라 별로 번호가 부여됩니다.
 - 내 PC에 1개만 연결되어 있다면, 0번 카메라 번호가 부여됩니다.

 

 


 

 

실행 코드✨

 

사용할 라이브러리

 

import cv2
import numpy as np

 

 

데이터 읽어들이기 - 웹캠 신호 받기(0번채널)

- VideoCapture() : OpenCV라이브러리에서 제공하는 함수 중 하나로, 비디오 캡처(Video Capture) 기능을 사용하여 비디오 파일이나 카메라로부터 프레임을 읽어오는 데 사용

 

VideoSignal = cv2.VideoCapture(0)

VideoSignal

 

< cv2.VideoCapture 000002933E9E34F0>

 

 

Yolo 모델 생성하기

 

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

 

< cv2.dnn.Net 000002934023B7D0>

 

 

라벨링 명칭(이름) 데이터 읽어들이기 - coco.names

 

classes = []

with open("./yolo/config/coco.names", "r") as f :
    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() ]

 

* 전체계층

 

* 출력계층

['detection_out']

 

 

윈도우 창 관리 영역 ✨

 

 

* 대표 윈도우 설정

 - namedWindow() 함수 사용

 - OpenCV에서 윈도우를 생성하기 위해 사용되는 함수

 - imshow() 함수를 사용하여 해당 윈도우에 이미지를 표시할 수 있다.

 

* 카메라에서 영상 읽어 들이기

 - read() 함수 사용

 - 영상파일 또는 카메라로부터 프레임을 읽어오는 역할 수행
        → ret : 읽어 들이는 프레임이 있는지 여부 판단(True or False)
                  : 더 이상 읽어들일 프레임이 없으면 False가 됨
             
         frame : 실제로 읽어들인 프레임(이미지) 자체
                        : 더 이상 읽어들일 프레임이 없으면 None이 됨
                        : 우리가 사용할 변수...

 

*  정지 옵션(윈도우 창 닫기)

 - waitKey(0) , destroyAllWindows()  함수 사용

 - waitKey(0) : 사용자가 키보드 입력을 기다리는 함수로, 0은 무한정 대기하라는 의미.

 - destroyAllWindows() : 키 입력을 받으면 함수를 사용하여 모든 윈도우를 닫음.

 

* BLOB 데이터 구조화

 - blobFromImage() 함수 사용

 - cv2.dnn.blobFromImage(image = frame, scalerfactor = 1/255.0, size = (416, 416), swapRB = True,                                                               crop = False)

 - image : 카메라에서 읽어들인 frame(이미지) 데이터

 - scalerfactor : 이미지 픽셀 값 정규화(스케일링)

 - size : Yolo 모델이 사용할 크기로 조정

 - swapRB : BGR, RGB 선택 ( True이면 : OpenCV의 기본 BGR 색상 순서를 RGB로 변경 )

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

 

 

 

 

 

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

 

 [대표 윈도우 설정]

  - 윈도우 창 관리는 이름으로 합니다.

 

cv2.namedWindow("YOLO3_CM_01")

 

 

 

 [카메라를 통한 영상처리 시에는 윈도우 창 실행을 유지]
  - 정지 옵션(윈도우 창 닫기)은 필수!

 

while True:

    """카메라에서 영상 읽어 들이기 : read() 함수 사용 """
    ret, frame = VideoSignal.read()

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

    """------------------------------------------------------"""
    """BLOB 데이터 구조화"""
    blob = cv2.dnn.blobFromImage(
        image = frame,
        scalefactor = 1/255.0,
        size = (416, 416),
        swapRB = True,
        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_y - 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),
                ### 선 색상
                (255, 0, 0),
                ### 선 굵기
                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] 정지 후, 다시 주피터 실행하면 됨.
"""

 

 

 

 

윈도우 창 관리 영역 : 카메라 인식 실행

 

[하나의 셀 안에 다 입력해두기]

 

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 = []

with open("./yolo/config/coco.names", "r") as f :
    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, frame = VideoSignal.read()

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

    """------------------------------------------------------"""
    """BLOB 데이터 구조화"""
    blob = cv2.dnn.blobFromImage(
        image = frame,
        scalefactor = 1/255.0,
        size = (416, 416),
        swapRB = True,
        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_y - 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),
                ### 선 색상
                (255, 0, 0),
                ### 선 굵기
                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 객체탐지 이미지로 추출하기 ✨

 

 

* 이미지 파일 번호 생성

- 이미지 파일 저장 시 파일명에 번호 붙이기(저장 후 +1 해주기)
- img_cnt = 1

 

* 인식된 객체 이미지로 저장하기

 - 정확도 평균 출력
    print(f">>>>>>>정확도 평균 : {np.mean(confidences)}")

 - imwrite() : 이미지 저장함수
 - 정확도 평균이 0.85이상인 경우만 저장시키기

("C:\Users\user\gj_202311\09_딥러닝\08_YOLO_객체탐지_네트워크(모델)\yolo\images_new\img_3.jpg")
    if np.mean(confidences) >= 0.85 :
        cv2.imwrite(f"./yolo/images_new/img_{img_cnt}.jpg", frame)
        img_cnt = img_cnt + 1

 

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 = []

with open("./yolo/config/coco.names", "r") as f :
    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, frame = VideoSignal.read()

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

    """------------------------------------------------------"""
    """BLOB 데이터 구조화"""
    blob = cv2.dnn.blobFromImage(
        image = frame,
        scalefactor = 1/255.0,
        size = (416, 416),
        swapRB = True,
        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_y - 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),
                ### 선 색상
                (255, 0, 0),
                ### 선 굵기
                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.85이상인 경우만 저장시키기
    if np.mean(confidences) >= 0.85 :
        # 이미지 저장함수 : 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] 정지 후, 다시 주피터 실행하면 됨.
"""

 

 

 

웹캠 실행 윈도우 창열리고 정확도(0.85) 이상 이미지 저장

 

 

728x90