본문 바로가기
Developer/OpenCV

[OpenCV] 이미지에서 관심영역 설정하기 (좌표 입력, 마우스 드래그)

by Doony 2020. 2. 3.

이번 포스팅에서는 OpenCV를 이용해 이미지에서 관심영역을 설정하는 방법에 대해 알아보겠습니다. 해당 포스팅은 이세우님의 '파이썬으로 만드는 OpenCV 프로젝트'를 참고했습니다.
순서는 다음과 같습니다.

  1. 이미지의 좌표를 직접 설정해서 관심영역 표시하기
  2. 설정된 관심영역으로 이미지 수정하기 (복제)
  3. 마우스 드래그로 관심영역 설정하기

이미지에서 좌표값 입력을 통해 관심영역 표시하기

먼저 이미지를 불러온 뒤, 특정 좌표에 대한 값을 코드에 미리 설정함으로써 관심영역으로 지정하는 방법입니다. 직관적이지만, 실제 사용을 위해서는 제한사항이 많아보이는 방법입니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import cv2
 
img = cv2.imread('./image.png')
 
= 675
= 100
= 150
= 150
roi = img[y:y+h, x:x+w]
 
print(roi.shape)
cv2.rectangle(roi, (0,0), (h-1, w-1), (02550))
 
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
cs


먼저 원하는 지역의 좌측 상단에 해당하는 좌표값과, 지정하고자 하는 영역의 폭과 높이를 각각 지정합니다. 그 후 roi에 이미지의 해당영역을 설정하고, 테두리 선을 둘러줍니다. (rectangle을 통해 간단하게 직사각형 형태의 선을 표시할 수 있습니다.) 적용 시 이미지에는 아래와 같이 테두리 선이 나타나게 됩니다.

관심영역을 통해 이미지 수정하기

위 예시에서 태양을 관심영역으로 지정했습니다. 이번에는 태양을 바로 옆에 복제시켜보도록 하겠습니다. 이미지는 어쨌거나 rgb에 해당하는 다차원 행렬데이터이기 때문에, 태양 옆의 영역에, 태양과 동일한 수치들로 이루어진 행렬만 복붙해주면 되는 원리입니다. 코드는 다음과 같습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import cv2
 
img = cv2.imread('./image.png')
 
= 675
= 100
= 150
= 150
roi = img[y:y+h, x:x+w]
img2 = roi.copy()
 
img[y:y+h, x+w:x+w+w] = roi
cv2.rectangle(img, (x,y), (x+w+w, y+h), (02550))
 
cv2.imshow('img', img)
cv2.imshow('roi', img2)
cv2.waitKey(0)
cv2.destroyAllWindows()
cs

생성된 이미지는 다음과 같습니다. 다소 어색하게 보이네요.

마우스 드래그를 통해 관심영역 설정하기

이번에는 이미지를 띄운 뒤, 사용자가 마우스 드래그를 통해 관심영역을 설정하는 방법입니다. 아무래도 위 방법들보다는 직관적이고 사용성이 좋은 듯 합니다. 원리는 콜백함수를 이용합니다. 콜백함수는 마우스 인풋을 이용하는 방식으로, 아래 코드를 보시면 직관적인 이해가 가능합니다. 사용자가 마우스를 누르거나, 드래그하거나, 떼거나 하면 콜백함수가 실행되고 그에 따라 조건 별로 코드를 작성합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import cv2
 
isDragging = False
x0, y0, w, h = -1-1-1-1
blue, red = (25500), (00255)
 
def onMouse(event, x, y, flags, param):
    global isDragging, x0, y0, img
    if event == cv2.EVENT_LBUTTONDOWN:
        isDragging = True
        x0 = x
        y0 = y
    elif event == cv2.EVENT_MOUSEMOVE:
        if isDragging:
            img_draw = img.copy()
            cv2.rectangle(img_draw, (x0, y0), (x, y), blue, 2)
            cv2.imshow('img', img_draw)
    elif event == cv2.EVENT_LBUTTONUP:
        if isDragging:
            isDragging = False
            w = x - x0
            h = y - y0
            if w > 0 and h > 0:
                img_draw = img.copy()
                cv2.rectangle(img_draw, (x0, y0), (x, y), red, 2)
                cv2.imshow('img', img_draw)
                roi = img[y0:y0+h, x0:x0+w]
                cv2.imshow('cropped', roi)
                cv2.moveWindow('cropped'00)
                cv2.imwrite('./cropped.png', roi)
            else:
                cv2.imshow('img', img)
                print('drag should start from left-top side')
 
img = cv2.imread('./image.png')
cv2.imshow('img', img)
cv2.setMouseCallback('img', onMouse)
cv2.waitKey()
cv2.destroyAllWindows()
        
cs

코드가 좀 길어보이지만, 하나하나 뜯어보면 단순합니다.

댓글