yolo를 활용한 사람 수 추출하기

이진우·2022년 5월 27일
0
post-thumbnail

대기열 혼잡도 검색 시스템 프로젝트를 진행함에 있어서 사진으로부터 사람 수를 추출하는 모듈이 필요하게 되었다.

object detection에 있어서 가장 성능이 좋은 yolo를 활용해서 모듈을 만들어 보기로 하였다.



yolo 설치하기(윈도우 기준)

자세한 설명은 공식 페이지

  1. (option)gpu 사용 설정

  2. CMake 다운로드

    • 설치를 하고 시스템 변수 Path에 설치한 cmake/bin 경로를 추가해주어야 한다.

  3. darknet-yolov4 다운로드 (repository)

    • Releases 버전의 Assets에서 yolov4.weightsSource code (zip)을 다운받고 소스코드의 압축을 풀고 소스코드 내부에 yolov4.weights파일을 넣는다. 그리고 build.ps1을 실행 시키고 현재 환경에 맞게 빌드를 진행한다.



object detection을 해보자 👀

darknet_yolov4 폴더내에 보면 darknet_images.py 파일이 있는데 이를 실행시키고 이미지 경로를 입력하면 객체검출을 해준다.

  • 여러 사람들을 검출한 모습 (핸드백이랑 넥타이까지 검출했다.)

  • 고양이도 가능하다.



🐈 이미지로 부터 detetion하는 코드 구성

먼저 detections 데이터를 반환하는 함수를 살펴보면 다음과 같다.

def image_detection(self, image_path, network, class_names, class_colors, thresh):
    # Darknet doesn't accept numpy images.
    # Create one with image we reuse for each detect
    width = darknet.network_width(network)
    height = darknet.network_height(network)
    darknet_image = darknet.make_image(width, height, 3)
    
    image = cv2.imread(image_path)
    image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    image_resized = cv2.resize(image_rgb, (width, height),
                                interpolation=cv2.INTER_LINEAR)

    darknet.copy_image_from_bytes(darknet_image, image_resized.tobytes())
    detections = darknet.detect_image(network, class_names, darknet_image, thresh=thresh)
    darknet.free_image(darknet_image)
    return detections
  1. 불러온 네트워크에 맞는 크기로 다크넷 이미지를 생성한다.
width = darknet.network_width(network)
height = darknet.network_height(network)
darknet_image = darknet.make_image(width, height, 3)
  1. 입력받은 이미지 경로를 통해 이미지를 불러오고 색상 표현 방식을 BGR에서 RGB로 바꾼다. 그 후에 전에 설정한 width와 height로 resize를 한다.
image = cv2.imread(image_path)
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
image_resized = cv2.resize(image_rgb, (width, height),
                           interpolation=cv2.INTER_LINEAR)
  1. detect_image 함수를 호출해서 이미지로 부터 detections 데이터를 생성하고 반환한다.
darknet.copy_image_from_bytes(darknet_image, image_resized.tobytes())
detections = darknet.detect_image(network, class_names, darknet_image, thresh=thresh)
darknet.free_image(darknet_image)
return detections

  • detection 데이터는 다음과 같이 생겼다.

리스트에 객체들에 대한 정보가 튜플형태로 포함되어 있으며 각 객체의 형태는 다음과 같다.

('객체', '확률', '객체 바운딩 박스 좌표')


🌃 darknet api를 이용한 사람 수 추출하는 코드

PeopleCounter 라는 클래스를 만들어서 사진으로부터 사람 수를 셀 수 있도록 하였다. 다음은 메소드들에 대한 설명이다.

  • image_detection(image_path, network, class_names, class_colors, thresh): 사진으로부터 detections 데이터를 생성해서 반환
  • count_people(self, image_name): 사진경로를 입력하면 사진에서 검출된 사람 수를 반환

코드

from darknetyolov4 import darknet
import random
import cv2
import os

class PeopleCounter:
    def __init__(self):
        random.seed(3)  # deterministic bbox colors
        cd_path = os.path.dirname(os.path.abspath(__file__))
        self.network, self.class_names, self.class_colors = darknet.load_network(
            cd_path + '/darknetyolov4/cfg/yolov4.cfg',
            cd_path + '/darknetyolov4/cfg/coco.data',
            cd_path + '/darknetyolov4/yolov4.weights',
            batch_size=1
        )
    
    def image_detection(self, image_path, network, class_names, class_colors, thresh):
        # Darknet doesn't accept numpy images.
        # Create one with image we reuse for each detect
        width = darknet.network_width(network)
        height = darknet.network_height(network)
        darknet_image = darknet.make_image(width, height, 3)

        image = cv2.imread(image_path)
        image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
        image_resized = cv2.resize(image_rgb, (width, height),
                                interpolation=cv2.INTER_LINEAR)

        darknet.copy_image_from_bytes(darknet_image, image_resized.tobytes())
        detections = darknet.detect_image(network, class_names, darknet_image, thresh=thresh)
        darknet.free_image(darknet_image)
        return detections

    def count_people(self, image_name):
        detections = self.image_detection(
            image_name, self.network, self.class_names, self.class_colors, 0.3
        )
        cnt = 0
        for i in detections:
            if i[0] == 'person':
                cnt+=1
        return cnt
profile
언젠가 보게 된다. 기록하자 😡🔥🔥

0개의 댓글