컴퓨터/Python

opencv 마우스 클릭 4번 이미지 가져오기 - 마지막 코드

풍경소리^^ 2022. 11. 18. 15:33

https://kyeonghyeon86.tistory.com/83

 

OpenCV Persperctive 2 (마우스로 좌표 찍기)

이번에는 좌표를 수기로 적는 것이 아닌, 이미지를 보고 그 위에 원하는 곳을 클릭하여 그 클릭한 곳을 좌표로 설정하여 , 이미지를 확대해보려한다. 아래는 그 예제 코드이다. 먼저 마우스 관련

kyeonghyeon86.tistory.com

b_capture.py--------------------

import cv2
import numpy as np
import mapper
image=cv2.imread("img/pexels-photo-900108.jpg")   #read in the image
image=cv2.resize(image,(1300,800)) #resizing because opencv does not work well with bigger images
orig=image.copy()

gray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)  #RGB To Gray Scale
# cv2.imshow("Title",gray)

blurred=cv2.GaussianBlur(gray,(5,5),0)  #(5,5) is the kernel size and 0 is sigma that determines the amount of blur
# cv2.imshow("Blur",blurred)

edged=cv2.Canny(blurred,30,50)  #30 MinThreshold and 50 is the MaxThreshold
# cv2.imshow("Canny",edged)


contours,hierarchy=cv2.findContours(edged,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)  #retrieve the contours as a list, with simple apprximation model
contours=sorted(contours,key=cv2.contourArea,reverse=True)

#the loop extracts the boundary contours of the page
for c in contours:
    p=cv2.arcLength(c,True)
    approx=cv2.approxPolyDP(c,0.02*p,True)

    if len(approx)==4:
        target=approx
        break
approx=mapper.mapp(target) #find endpoints of the sheet

pts=np.float32([[0,0],[800,0],[800,800],[0,800]])  #map to 800*800 target window

op=cv2.getPerspectiveTransform(approx,pts)  #get the top or bird eye view effect
dst=cv2.warpPerspective(orig,op,(800,800))


cv2.imshow("Scanned",dst)
# press q or Esc to close
cv2.waitKey(0)
cv2.destroyAllWindows()

mapper.py--------------------

import numpy as np

def mapp(h):
    h = h.reshape((4,2))
    hnew = np.zeros((4,2),dtype = np.float32)

    add = h.sum(1)
    hnew[0] = h[np.argmin(add)]
    hnew[2] = h[np.argmax(add)]

    diff = np.diff(h,axis = 1)
    hnew[1] = h[np.argmin(diff)]
    hnew[3] = h[np.argmax(diff)]

    return hnew

######################################################################

mouse_handler.py--------------------

# mouse_handler.py
 
import cv2
import numpy as np
 
img_path = './img/pexels-photo-900108.jpg'
ori_img = cv2.imread(img_path)
 
src = []  # 왼쪽위, 오른쪽위, 오른쪽아래, 왼쪽아래 순으로 각 점의 좌표
 
# mouse callback handler
def mouse_handler(event, x, y, flags, param):
    if event == cv2.EVENT_LBUTTONUP:  # 마우스가 좌클릭을 했을때 (4번의 클릭으로 좌표 얻기)
        img = ori_img.copy()
 
        src.append([x, y])
 
        for xx, yy in src:  # 클릭한 곳에 점 그리기
            cv2.circle(img, center=(xx, yy), radius=5, color=(0, 255, 0), thickness=-1)
 
        cv2.imshow('Original Image - Car', img)
 
        # perspective transform
        if len(src) == 4:
            src_np = np.array(src, dtype=np.float32)
            print("original points : \n", src_np)
 
cv2.namedWindow('Original Image - Car')
cv2.setMouseCallback('Original Image - Car', mouse_handler)  # 마우스 이벤트 전달
 
cv2.imshow('Original Image - Car', ori_img)
if cv2.waitKey(0) == 32:
    cv2.destroyAllWindows()

car.py--------------------

# car.py
 
import cv2
import numpy as np
import keyboard
 
img_path = './img/pexels-photo-900108.jpg'
ori_img = cv2.imread(img_path)

src = []  # 왼쪽위, 오른쪽위, 오른쪽아래, 왼쪽아래 순으로 각 점의 좌표
src.append([211, 229])
src.append([969, 68])
src.append([1079, 601])
src.append([324, 756])
 
# 32비트로 바꿔줌
src_np = np.array(src, dtype=np.float32)
 
# width ,height 길이 계산
width = max(np.linalg.norm(src_np[0] - src_np[1]), np.linalg.norm(src_np[2] - src_np[3]))
height = max(np.linalg.norm(src_np[0] - src_np[3]), np.linalg.norm(src_np[1] - src_np[2]))
 
# width, height 비율
width_ratio = (width / height)
height_ratio = 1
 
# 비율 * 300 으로 픽셀 크기 맞춤
dst_np = np.array([[0, 0],
                    [int(width_ratio * 300), 0],
                    [int(width_ratio * 300), int(height_ratio * 300)],
                    [0, int(height_ratio * 300)]
                    ], dtype=np.float32)
 
M = cv2.getPerspectiveTransform(src=src_np, dst=dst_np)
result = cv2.warpPerspective(ori_img, M=M, dsize=(int(width_ratio * 300), height_ratio * 300))
#print("Perspective Transformation :\n", M)
 
cv2.imshow('img', ori_img)
 
print("스페이스바를 누르면 번호판의 4개 매칭점이 구해집니다.")
 
if cv2.waitKey(0) == ord(' '):
    for xx, yy in src:
        cv2.circle(ori_img, center=(xx, yy), radius=5, color=(0, 255, 0), thickness=-1, lineType=cv2.LINE_AA)
cv2.imshow('img', ori_img)
print("original points : \n", src_np)
 
if cv2.waitKey(0) == ord(' '):
    cv2.imshow('result', result)
    cv2.imwrite('result.jpg', result)
    print("\ndestination points : \n", dst_np)
 
if cv2.waitKey(0) == ord(' '):
    cv2.destroyAllWindows()

######################################################################

scanner.py--------------------

import cv2
import numpy as np
import keyboard
 
img_path = r'.\img\antique-art-painting-paper-162589.jpg'
ori_img = cv2.imread(img_path)
 
# src = []  # 왼쪽위, 오른쪽위, 오른쪽아래, 왼쪽아래 순으로 각 점의 좌표
# src.append([ 52,  23])
# src.append([600, 124])
# src.append([523, 446])
# src.append([ 13, 300])
#######################################################################
src = []  # 왼쪽위, 오른쪽위, 오른쪽아래, 왼쪽아래 순으로 각 점의 좌표
 
# mouse callback handler
def mouse_handler(event, x, y, flags, param):
    if event == cv2.EVENT_LBUTTONUP:  # 마우스가 좌클릭을 했을때 (4번의 클릭으로 좌표 얻기)
        img = ori_img.copy()
 
        src.append([x, y])
 
        for xx, yy in src:  # 클릭한 곳에 점 그리기
            cv2.circle(img, center=(xx, yy), radius=5, color=(0, 255, 0), thickness=-1)
 
        cv2.imshow('Original Image', img)
 
        # perspective transform
        if len(src) == 4:
            src_np = np.array(src, dtype=np.float32)
            # print("original points : \n", src_np)
 
cv2.namedWindow('Original Image')
cv2.setMouseCallback('Original Image', mouse_handler)  # 마우스 이벤트 전달
 
cv2.imshow('Original Image', ori_img)
if cv2.waitKey(0) == 32:
    # cv2.destroyAllWindows()
    pass
#######################################################################
 
# 32비트로 바꿔줌
src_np = np.array(src, dtype=np.float32)
 
# width ,height 길이 계산
width = max(np.linalg.norm(src_np[0] - src_np[1]), np.linalg.norm(src_np[2] - src_np[3]))
height = max(np.linalg.norm(src_np[0] - src_np[3]), np.linalg.norm(src_np[1] - src_np[2]))
 
# width, height 비율
width_ratio = (width / height)
height_ratio = 1
 
# 비율 * 300 으로 픽셀 크기 맞춤
dst_np = np.array([[0, 0],
                    [int(width_ratio * 300), 0],
                    [int(width_ratio * 300), int(height_ratio * 300)],
                    [0, int(height_ratio * 300)]
                    ], dtype=np.float32)
 
M = cv2.getPerspectiveTransform(src=src_np, dst=dst_np)
result = cv2.warpPerspective(ori_img, M=M, dsize=(int(width_ratio * 300), height_ratio * 300))
#print("Perspective Transformation :\n", M)
 
# cv2.imshow('img', ori_img)
 
# print("스페이스바를 누르면 번호판의 4개 매칭점이 구해집니다.")
 
# if cv2.waitKey(0) == ord(' '):
#     for xx, yy in src:
#         cv2.circle(ori_img, center=(xx, yy), radius=5, color=(0, 255, 0), thickness=-1, lineType=cv2.LINE_AA)
# cv2.imshow('img', ori_img)
# print("original points : \n", src_np)
 
cv2.imshow('result', result)
cv2.imwrite('result.jpg', result)
# if cv2.waitKey(0) == ord(' '):
#     cv2.imshow('result', result)
#     cv2.imwrite('result.jpg', result)
    # print("\ndestination points : \n", dst_np)
 
if cv2.waitKey(0) == ord(' '):
    cv2.destroyAllWindows()