본문 바로가기
공부/기타

python - 관심영역 지정 가장 큰 윤곽선 찾기

by 기묜몬 2023. 3. 27.

마우스로 직접 동영상 및 이미지에 관심영역을 지정 후
키보드의 [ ]  대괄호를 사용해 threshold 조절하여 물체의 가장 큰 윤곽선을 찾을 수 있다. 
 
[ 코드 내용 ]
1. opencv 라이브러리를 이용
2. 클래스를 정의하여 인스턴스 변수 관리 
3. mouseEvent 를 사용해서 직접 원하는 영역에 박스 지정 가능
-> sefl.start_x, y, w, h 변수로 마우스로 클릭한 위치와 드래그 위치를 저장해서 사용
-> step변수를 통해 마우스 클릭 값을 업데이트
4.  threshold 조절 가능
 
몇달 전 업무에 필요해서 연습삼아 간단한 기능만 넣어서 만들어봤는데, 2주나 걸렸다는 함정..
그래도 만들어놓고 보니 뿌듯하다. 
 
 
[ 결과물 ]

 

import cv2


class DrawBoxClass:
    def __init__(
        self,
        path: str,
    ) -> None:
        # self.dragging_status = False
        self.start_x, self.start_y, self.w, self.h = -1, -1, -1, -1
        self.step = 0
        self.threshold_count = 10
        self.path = path
        self.video = cv2.VideoCapture(path)
        self.ret, self.frame = self.video.read()

    def drag_mouse(self, event, x, y, flags, param):
        # 왼쪽 마우스 버튼 다운, 드래그 시작
        if event == cv2.EVENT_LBUTTONDOWN:
            self.step = 1
            # self.dragging_status = True
            self.start_x = x
            self.start_y = y

        elif event == cv2.EVENT_MOUSEMOVE:
            if self.step == 1:
                self.step = 2
            if self.step == 2:
                self.w = x
                self.h = y

        elif event == cv2.EVENT_LBUTTONUP:
            self.step = 3
            # self.dragging_status = False
            self.w = x - self.start_x  # 드래그 영역 폭 계산
            self.h = y - self.start_y  # 드래그 영역 높이 계산
            print("x%d, y%d, w%d, h%d" % (self.start_x, self.start_y, self.w, self.h))

    def draw_box_contours(self):
        if self.step == 2:
            cv2.rectangle(
                self.frame,
                (self.start_x, self.start_y),
                (self.w, self.h),
                (255, 0, 0),
                3,
            )
            cv2.imshow("result", self.frame)

        elif self.step == 3:
            roi = self.frame[
                self.start_y : self.start_y + self.h,
                self.start_x : self.start_x + self.w,
            ]
            roi_gray = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)
            _, thresh1 = cv2.threshold(  # 이진화
                roi_gray, self.threshold_count, 255, cv2.THRESH_BINARY
            )
            # roi_canny = cv2.Canny(thresh1, 0, 300)
            # contours
            contours, hierarchy = cv2.findContours(
                thresh1, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
            )
            roi_result = cv2.cvtColor(thresh1, cv2.COLOR_GRAY2BGR)
            self.frame[
                self.start_y : self.start_y + self.h,
                self.start_x : self.start_x + self.w,
            ] = roi_result
            max_area = 0
            contours_index = 0
            for i in range(len(contours)):
                cnt = contours[i]
                area = cv2.contourArea(cnt)
                if area > max_area:
                    max_area = area
                    contours_index = i  # contour에서의 배열 번호를 차례대로 저장.
            cnt = contours[contours_index]
            cv2.drawContours(roi, [contours[contours_index]], 0, (0, 0, 255), 2)
            # 원본에 복사

    def press_key_event(self):
        key = cv2.waitKey(10)

        if key == ord("q"):
            exit()

        elif key == ord("]"):  # 0x5D 증가
            self.threshold_count += 5
            if self.threshold_count > 255:
                # 255까지만 증가
                self.threshold_count = 255

        elif key == ord("["):  # 0x5B 감소
            self.threshold_count -= 5
            if self.threshold_count < 0:
                # 0까지만 감소
                self.threshold_count = 0

    def main(self):
        while self.video.isOpened():
            self.ret, self.frame = self.video.read()
            cv2.putText(
                self.frame,
                f"Threshold : {str(self.threshold_count)}",
                (self.start_x, self.start_y),
                cv2.FONT_HERSHEY_SIMPLEX,
                2,
                (0, 255, 0),
                5,
            )
            cv2.setMouseCallback("result", self.drag_mouse)
            self.draw_box_contours()
            self.press_key_event()
            cv2.namedWindow("result")
            cv2.imshow("result", self.frame)

 

'공부 > 기타' 카테고리의 다른 글

2022.08.02 - http 웹 기본지식 - (1)  (0) 2022.08.02
git 명령어 모음  (0) 2022.07.21
브라우저는 어떻게 동작하는가?  (1) 2022.06.14
iterm2 단축키  (0) 2022.06.04
2022.02.08 - Vue.js 개발환경세팅 MAC (+ 에러 추가)  (0) 2022.02.09