import cv2
def mouse_handler(event,x,y,flag,param):
if event == cv2.EVENT_LBUTTONDOWN :
print('왼쪽 버튼 다운')
elif event == cv2.EVENT_LBUTTONUP:
print('왼쪽 버튼 업')
elif event == cv2.EVENT_LBUTTONDBLCLK:
print('왼쪽 더블 클릭')
# elif event == cv2.EVENT_MOUSEMOVE:
# print('마우스 움직임')
elif event == cv2.EVENT_RBUTTONDOWN:
print('오른쪽 버튼 다운')
img = cv2.imread('poker.jpg')
cv2.namedWindow('img') #img라는 이름의 윈도우를 먼저 만들어둠 여기에 마우스 이벤트를 처리하기 위한 핸들러 적용
cv2.setMouseCallback('img',mouse_handler)
cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.setMouseCallback(windowName, callback, param=None)
- windowName: 마우스 이벤트를 적용할 창의 이름입니다.
- callback: 마우스 이벤트가 발생했을 때 호출될 콜백 함수의 이름입니다. 이 함수는 OpenCV에서 정의된 마우스 이벤트, 좌표, 그리고 사용자가 추가로 전달한 데이터를 인자로 받습니다.
- param: 콜백 함수에 전달할 추가적인 데이터입니다.
import cv2
import numpy as np
#변수 선언부
point_list = [] #마우스 클릭으로 얻은 x,y좌표를 보관할 리스트
src_img = cv2.imread('poker640.jpg') #작업할 사진 불러오기
orig1_img = src_img.copy() #우클릭 시 초기화할 원본이미지의 사본
COLOR = (255,0,255) #마우스 클릭으로 찍힐 점
THICKNESS = 3 #마우스 움직임으로 그려질 선 두께
drawing = False #선 그리기 기본값 false
def mouse_handler(event,x,y,flag,param): #마우스 핸들러함수 선언(마우스에서 시행되는 작업, x와 y좌표,flag와 param은 readme 확인)
global drawing #전역으로 선언된 drawing함수를 가져와 사용한다
dst_img = src_img.copy() #src원본에서 dst 카피본에 작업을 한다 *마우스가 이동하는 동안 계속 선이 생겨서 복사본에 작업
if event == cv2.EVENT_LBUTTONDOWN :
drawing =True #원이 그려지면 선 그리기 활성화가 됨
point_list.append((x,y)) #클릭된 부분의 좌표를 point_list에 저장
print('마우스 왼쪽 클릭')
elif event == cv2.EVENT_RBUTTONDOWN :
if point_list: # point_list가 비어있지 않은 경우에만
point_list.pop() # 가장 최근에 추가된 좌표를 삭제
dst_img = src_img.copy() # 이미지를 원본으로 다시 초기화
print('마우스 오른쪽 클릭')
if drawing: #선 그리기 활성화가 되면
prev_point = None #직선의 시작점에 초기값을 넣지 않음
for point in point_list: #point_list의 값들을 point라는 변수로 순회하며 조회
cv2.circle(dst_img, point,7,COLOR,cv2.FILLED) #클릭된 x,y좌표에 원을 그림(point_list의 값을 point에 넣음)
if prev_point: #만약 prev_point에 값이 있다면
cv2.line(dst_img, prev_point, point,COLOR, THICKNESS, cv2.LINE_AA) #복사된 이미지에 prev_point부터 새로찍힐 점까지 선을 그림
prev_point = point #모든 작업이 수행되면 방금 찍은 점의 좌표값이 prev_point로 대입
#첫 클릭에선 이전 클릭점이 없으므로 위 조건문을 스킵된다(첫 클릭이 일어나기 전 선이 그려지지 않음, 첫 클릭시 그 때부터 선이 생김)
next_point = (x,y) # 방금 클릭한 점의 좌표를 next_point에 대입
if len(point_list) == 4: #point_list(클릭된 점이 네개일 때)가 4개의 항목이 있을 때
show_result() #show_result 함수 발동(밑에 있음)
next_point = point_list[0] #위 조건이 되면 next_point에 가장 처음 클릭한 점의 좌표를 대입해줌
cv2.line(dst_img, prev_point, next_point,COLOR, THICKNESS, cv2.LINE_AA) #클릭이 4번 발생한 후 마지막 선이 그려지지 않고 종료되는걸 막음
#전 클릭점부터 가장 첫번째 점까지 선을 그어버림
cv2.imshow('img',dst_img)
def show_result(): #show_result함수선언
width, height = 477, 639 #최종적으로 잘라낸 사진의 크기를 정한 값
src = np.float32(point_list)#point_list의 값을 cv2.getPerspectiveTransform 사용하기 위해 float32형식으로 바꿔줌
dst = np.array([[0,0],[width,0],[width,height],[0,height]],dtype=np.float32) #최종적으로 완성될 사진의 크기 지정
matrix = cv2.getPerspectiveTransform(src,dst) #src 영역을 dst 영역으로 바꾸기 위한 변환 행렬(매트릭스)를 얻어옴
result = cv2.warpPerspective(src_img, matrix,(width,height))# 변환 행렬로 최종결과이미지를 적용
cv2.imshow('result',result) #완성된 사진 출력
cv2.namedWindow('img') #img라는 이름의 윈도우를 먼저 만들어둠 여기에 마우스 이벤트를 처리하기 위한 핸들러 적용
cv2.setMouseCallback('img',mouse_handler) #마우스 이벤트를 사용하기 위해 작성
cv2.imshow('img',src_img)
cv2.waitKey(0)
cv2.destroyAllWindows()