본문 바로가기
AI/컴퓨터 비전

[DL] ROI함수 활용하여 마우스 클릭 이벤트 구현하기 /완료

by 바다의 공간 2024. 8. 22.

1. 관심 영역(ROI, Region of Interest)
- 영상 내에서 관심이 있는 영역

 

cv2 모듈을 이용해서 이미지를 확인하고 

이미지를 확인하여서 태양부분의 이미지만! 스퀘어 처리를 하고 그 옆으로 카피를 해보려고 합니다.

ROI 는 관심영역 이라고 생각하면 되고 내가 액션을 취할 부분(구간)이라고 이해하면 

좋을것같습니다.

 

이번 시간에는

중에서 태양만 옆으로 하나 더 복사하고 , 2개의 태양을 테두리 치는것을 해보았습니다.


import cv2

img = cv2.imread('./sun.jpg')

# x, y, w, h
x = 182
y = 21
w = 120
h = 110

# 태양을 복사
roi = img[y: y+h, x: x+w]
roi_copy = roi.copy()

img[y: y+h, x+w: x+w+w] = roi

# 두 태양을 박스로 감싸기
cv2.rectangle(img, (x,y), (x+w+w, y+h) , (0, 255, 0), 3)

cv2.imshow('img', img)
cv2.imshow('roi_copy', roi_copy)
cv2.waitKey()

 

x,y의 높이 w,h를 각각 구하고 ROI를 구해서 복사해보려고 합니다.

 

w,h는 각 좌표의 차이값이고, x,y는 가장 왼쪽 좌표(시작) 좌표를 뜻합니다.

 

roi의 변수에 img[y와 x]를 넣고

copy를 해줍니다.

open cv로 불러왔기때문에 x가 아닌 y먼저 써야합니다!

그러면 원본에 문제가 생기는것이 아니죠.

 

여기서 궁금했던 점

img[y: y+h, x+w: x+w+w] = roi 

roi = img[y: y+h, x+w: x+w+w]
는 왜 다를까 굳이 왜 roi를 뒤에다쓸까? 라는게 궁금했습니다.

img[y: y+h, x+w: x+w+w] 이 부분은 좌표의 이미지를 긁어오는것은 알겠지만
매번 좌변에 쓰다가 왜 우변에 쓰는지 갑자기 헷갈렸습니다.

이 부분은 다시 보드를 이해하면 자연스럽게 고개가 끄덕여지긴했는데
1번은

roi가 img[y: y+h, x+w: x+w+w]에 붙여넣어지는것을 의미하고  

2번째는
img[y: y+h, x+w: x+w+w] 의 복사된 부분이 다시roi로 저장되는 것이었습니다.

즉 좌변은 저장하는공간이고 우변은 복사해오는 데이터입니다.


그래서 이렇게 img라는 파일에 roi태양을 추가했습니다.

 

# 두 태양을 박스로 감싸기

# 두 태양을 박스로 감싸기
cv2.rectangle(img, (x,y), (x+w+w, y+h), (0, 255, 0), 3)

#x y부터 시작해서 태양 하나를 더 복사 한 w까지 (x+w+w, y+h),

색상 (0,255, 0) 두께는 3 이라는 뜻입니다.

 


## selectROL 함수

: 내가 마우스를 통해서 드래그를 할 수 있고

그 액션으로 원하는 박스를 선택할수있고 그거만 따서 화면에서 볼 수 있습니다.

 

import cv2

img = cv2.imread('./sun.jpg')

x, y, w, h = cv2.selectROI('img', img, False) #Cross 표기

if w and h:
    roi = img[y: y+h, x: x+w]
    cv2.imshow('roi', roi)

cv2.waitKey()

네모칸을 치고 엔터를 치면 roi로 열립니다. 

cv2.selectROI('IMG', IMG, cross표시(4분할) 을 해줄건지 안 해줄건지?)

를 각각 적어주면 됩니다.

 

좌) FALSE, 우)TRUE

 

이렇게 엔터를 누르게 되면 내가 선택한 영역 자체가 따른 roi창으로 나오게 됩니다.

4분할을 TRUE로 해도 엔터치면 4분할로 나누어지진않고 좌측 FALSE와 같은 결과가 나오게 됩니다.


#makeROI 

 

마우스이벤트를 통해서 진행하는데 위에서는 ENTER을 눌러야 roi창이 떴지만 

이제는 마우스 드래그를 떼면! 창이 뜨는걸로 만들어보려고 합니다.

import cv2

#움직이는 좌표를 알아야하기때문에
#원래있었던좌표, 움직인 좌표를 0으로 세팅함
oldx = oldy = w= h= 0
color = (255,0, 0)
img_copy = None
#드래그가 됐는지 안 됐는지?
isDrag= False

def on_mouse(event, x, y, flags, parma):
    global oldx, oldy, w, h, color, img_copy, isDrag
    if event == cv2.EVENT_LBUTTONDOWN:
        isDrag = True
        oldx = x
        oldy = y
    elif event == cv2.EVENT_MOUSEMOVE:
        if isDrag:
            img_copy = img.copy()
            cv2.rectangle(img_copy, (oldx, oldy), (x,y), color, 3)
            cv2.imshow('img', img_copy)

    #마우스 드레그 떼기
    elif event == cv2.EVENT_LBUTTONUP:
        #드레그 되는 상황이라면~
        if isDrag:
            #그만하게 해주고
            isDrag = False
            # 우측방향으로만만들 수 있게 만드니까 oldx보다 크다면~
            if x > oldx and y > oldy:
                #현재좌표에서 빼서 너비와 높이라고 지정
                w = x-oldx
                h = y-oldy
                if w>0 and h>0:
                    cv2.rectangle(img_copy, (oldx,oldy), (x,y),color, 3)
                    cv2.imshow('img', img_copy)
                    roi = img[oldy: oldy+h, oldx: oldx+w]
                    cv2.imshow('roi', roi)
        else:
            cv2.imshow('img', img)
            print('영역이 잘못 되었음!')
img = cv2.imread('./sun.jpg')
cv2.imshow('img', img)
cv2.setMouseCallback('img', on_mouse)
cv2.waitKey()

 

oldx = oldy = w = h = 0 이건 좌표 등록입니다.

그 외는 글로벌함수로 만들어놓고 코드를 적어줍니다.

 

if event == cv.ENENT_LBUTTINDOWN: 

마우스 L버튼이 눌리고 드래그가 되고있으면

TRUE를 넣고 그 좌표를 oldx, oldy에 저장해줍니다.

 

드래그가 된 상태에서 if isDrag는 img카피를 해주고

이미지 카피 부분에 ractangle을 그려주고 

rectangle로 표시를 해줍니다. (여기까지는 마우스가 안떼짐)


#마우스 떼기 (LBUTTINUP)

이제 떼는걸 만들어봅니다.--> LBUTTONUP부분

그러면 이제 드레그를 시작했다가 떼는 순간에 그 RECTENTGLE부분에 ROI창이 생기게 됩니다.