마우스로 직접 동영상 및 이미지에 관심영역을 지정 후
키보드의 [ ] 대괄호를 사용해 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 |