2024. 8. 8. 16:56ㆍ---포트폴리오---/개인 프로젝트 or 작업물
< 설계 >
1. 이미지의 관심 영역을 설정하고 추출하는 기능을 구현.
2. 입력 영상은 컬러 or 흑백 사진 사용.
3. 이미지 관심영역이란 임의로 도형을 드래그 또는 포인트 점을 찍어 만든 영역을 말함.
3-1. 타원
- 마우스 왼쪽 버튼을 눌러 드래그 하여 영역 설정.
- 드래그하는 동안 타원 그림이 그려져야 함.
3-2. 다각형 (포인트 사용)
- 여러 개의 점을 찍어 다각형 영역을 설정.
- 최소 3개의 점이 찍혀야 함.
- 점과 점 사이에는 선이 그려져야함
- 다각형을 유지하기 위해서는 내각이 180도 이하여야 함.
- 임의로 클릭하여 점을 찍을 때, 첫 번째 점과의 거리가 20px 이하여 다각형을 닫음. (마지막으로 찍은 점은 무시.)
4. 타원 또는 다각형 형태로 설정한 영역 내부의 이미지를 추출 후 저장.
5. 타원, 다각형을 할 수 있는 모드는 키보드를 눌러 선택.
- 처음 시작은 NULL 모드.
- 타원 모드는 키보드 숫자 '1'을 눌러 변경.
다시 누르면 'NULL' 모드로 변경. - 다각형 모드는 키보드 숫자 '2'를 눌러 변경.
마찬가지로 다시 누르면 'NULL' 모드로 변경.
< 작성 코드 >
import cv2
import numpy as np
drawing = False
mode = 'NULL'
ix, iy = -1, -1
img_count = 1
Polygon_points = []
def onMouse(event, x, y, flags, param):
global ix, iy, drawing, mode, image, Polygon_points, img_count
if event == cv2.EVENT_LBUTTONDOWN:
if mode == 'Ellipse':
drawing = True
ix, iy = x, y
elif mode == 'Polygon':
if len(Polygon_points) > 0 and np.linalg.norm(np.array(Polygon_points[0]) - np.array([x,y])) < 20:
Polygon_points.append(Polygon_points[0])
cv2.polylines(image, [np.array(Polygon_points)], isClosed=True, color=(0,255,0),thickness= 2)
save_roi_polygon()
Polygon_points.clear()
else:
Polygon_points.append((x,y))
if len(Polygon_points) > 1:
cv2.line(image, Polygon_points[-2], Polygon_points[-1], (0,255,0),2)
cv2.circle(image, (x,y),3,(0,0,255),-1)
cv2.imshow('image',image)
elif event == cv2.EVENT_MOUSEMOVE:
if drawing and mode == 'Ellipse':
temp_image = image.copy()
radius = int(np.sqrt((x - ix)**2 + (y - iy)**2))
cv2.circle(temp_image, (ix, iy), radius, (255, 0, 0), 2)
cv2.imshow('image', temp_image)
elif event == cv2.EVENT_LBUTTONUP:
if drawing and mode == 'Ellipse':
drawing = False
radius = int(np.sqrt((x - ix)**2 + (y - iy)**2))
cv2.circle(image, (ix, iy), radius, (0, 255, 0), 2)
save_roi_ellipse(ix, iy, radius)
cv2.imshow('image', image)
def save_roi_ellipse(ix, iy, radius):
global img_count
x1, y1 = max(0, ix - radius), max(0, iy - radius)
x2, y2 = min(image.shape[1], ix + radius), min(image.shape[0], iy + radius)
roi = image[y1:y2, x1:x2].copy()
cv2.imwrite(f'roi_{img_count:04d}.jpg', roi)
img_count += 1
def save_roi_polygon():
global img_count
mask = np.zeros_like(image)
cv2.fillPoly(mask, [np.array(Polygon_points)], (255, 255, 255))
masked_image = cv2.bitwise_and(image, mask)
x, y, w, h = cv2.boundingRect(np.array(Polygon_points))
roi = masked_image[y:y + h, x:x + w].copy()
cv2.imwrite(f'roi_{img_count:04d}.jpg', roi)
img_count += 1
def switch(key):
global mode, Polygon_points
if key == ord('1'):
mode = 'Ellipse' if mode != 'Ellipse' else 'NULL'
elif key == ord('2'):
mode = 'Polygon' if mode != 'Polygon' else 'NULL'
if mode == 'NULL' and len(Polygon_points) > 2:
cv2.polylines(image, [np.array(Polygon_points)], isClosed=True, color=(0,255,0),thickness=2)
Polygon_points.clear()
print(f'Mode switched to: {mode}')
image = cv2.imread('old.jpg')
cv2.imshow('image', image)
cv2.setMouseCallback('image', onMouse)
while True:
key = cv2.waitKey(1) & 0xFF
if key == 27:
break
switch(key)
cv2.destroyAllWindows()
<코드 설명>
1. 원을 그리는 모드일 때 그리는 상태로 설정하고, 마우스 클릭 지점 저장.
2. 다각형 그리기 모드일 때 첫 번째 점과 가까운 위치를 클릭하면 다각형을 닫고, 닫힌 다각형을 의해 시작점을 추가함.
그리고 해당 다각형을 저장하고 새로운 다각형을 그리기 위해 다각형 점 리스트를 초기화 시킴.
2-1. 새로운 점을 추가하고 이전의 점과 현재 그린 점을 연결하는 선 그리고 클릭한 위치에 작은 원을 그려 점을 표시 후 업데이트 된 이미지를 표시함.
3. 타원 모드에서 드래그하여 마우스를 움직일 때 원본 이미지를 복사해 임시 이미지를 만들고 반지름을 계산 후 임시 이미지에 원을 그리고 표시함.
3-1. 마우스 왼쪽 버튼을 뗐을 때 그리는 상태를 해제하고 최종적으로 반지름을 계산 후 원본 이미지에 최종 원을 그린 다음 저장하고 표시함.
4. 타원 ROI를 저장하는 부분은 타원의 바운딩 박스를 계산하여 영역을 설정하고 타원 내부 영역을 추출 후 이미지 파일로 저장. 그리고 여러 장의 사진을 저장할 수 있으니 저장할 이미지의 번호를 증가 시킴.
5. 다각형도 위와 마찬가지로 동작함.
6. 모드를 전환하기 위해 switch 함수를 사용하여 '1'을 눌렀을 때 타원 모드로 전환 다시 누르면 'NULL'로 전환
'2'를 누르면 다각형 모드로 전환.
7. 아스키코드를 이용해 메인 루프 동작 여부 결정. ESC(27) 을 누르면 프로그램 종료. (아닐 경우 모드 전환 함수 호출)
< 동작 사진>
1. 기본 동작 상태 (NULL)
2. 키보드 '1'을 눌렀을 때 (Ellipse)
3. 키보드 '2'를 눌렀을 때 (Polygon)
4. 타원 그리기 모드
5. 다각형 그리기 모드
6. 종료 후 저장된 사진
'---포트폴리오--- > 개인 프로젝트 or 작업물' 카테고리의 다른 글
HTML,CSS,Js - 메모장 만들기. (+저장 기능) (0) | 2024.07.26 |
---|---|
HTML,CSS,Js - 디지털 시계 만들기. (시간, 알람, 타이머 기능) (0) | 2024.07.26 |
HTML,CSS,Js - 최대공약수와 최소공배수 계산기 화면 만들기. (0) | 2024.07.25 |