You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

149 lines
4.5 KiB

import cv2
import numpy as np
# 全局变量
points = [] # 存储选择的四个点
img = None # 存储原始图像
img_copy = None # 用于绘制的图像副本
def mouse_callback(event, x, y, flags, param):
"""鼠标回调函数,用于选择四个点"""
global img_copy, points
if event == cv2.EVENT_LBUTTONDOWN:
if len(points) < 4:
points.append((x, y))
print(f"已选择点 {len(points)}: ({x}, {y})")
# 在图像上绘制点
cv2.circle(img_copy, (x, y), 5, (0, 255, 0), -1)
# 如果已经选择了4个点,绘制连线
if len(points) == 4:
# 按照上、右、下、左的顺序连接点
for i in range(4):
cv2.line(img_copy, points[i], points[(i + 1) % 4], (0, 255, 0), 2)
# 标记每个点的位置
cv2.putText(img_copy, "Top", points[0], cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)
cv2.putText(img_copy, "Right", points[1], cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)
cv2.putText(img_copy, "Bottom", points[2], cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)
cv2.putText(img_copy, "Left", points[3], cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)
cv2.imshow("Select Points", img_copy)
def perspective_transform(image, src_points):
"""执行透视变换"""
# 将点排序为上、右、下、左
top, right, bottom, left = src_points
# 计算新图像的宽度(取左右边的最大值)
width_a = np.linalg.norm(np.array(right) - np.array(left))
width_b = np.linalg.norm(np.array(top) - np.array(bottom))
max_width = max(int(width_a), int(width_b))
# 计算新图像的高度(取上下边的最大值)
height_a = np.linalg.norm(np.array(bottom) - np.array(top))
height_b = np.linalg.norm(np.array(right) - np.array(left))
max_height = max(int(height_a), int(height_b))
# 定义目标点
dst = np.array([
[0, 0], # 左上角
[max_width - 1, 0], # 右上角
[max_width - 1, max_height - 1], # 右下角
[0, max_height - 1] # 左下角
], dtype="float32")
# 转换源点数组为numpy数组
src = np.array([top, right, bottom, left], dtype="float32")
# 计算透视变换矩阵
M = cv2.getPerspectiveTransform(src, dst)
# 执行透视变换
warped = cv2.warpPerspective(image, M, (max_width, max_height))
return warped
def k_perspective_transform(image, src_points):
"""执行透视变换"""
# 将点排序为上、右、下、左
top, right, bottom, left = src_points
# 计算新图像的宽度(取左右边的最大值)
sub_zy = np.array(right) - np.array(left)
sub_sx = np.array(top) - np.array(bottom)
sub_x=sub_sx[0]/2
print("x差值",sub_sx[0])
sub_y = sub_zy[1] / 2
print("y差值", sub_sx[0])
# 定义目标点
dst = np.array([
[top[0]-sub_x, top[1]], # 左上角
[right[0], right[1]- sub_y], # 左上角
[bottom[0]+sub_x, bottom[1]], # 左上角
[left[0] , left[1]+ sub_y], # 左上角
], dtype="float32")
# 转换源点数组为numpy数组
src = np.array([top, right, bottom, left], dtype="float32")
# 计算透视变换矩阵
M = cv2.getPerspectiveTransform(src, dst)
print(f"矩阵M={M}")
# 执行透视变换
warped = cv2.warpPerspective(image, M, (1050, 900))
return warped
def main():
global img, img_copy, points
# 读取图像
img = cv2.imread("images/trans/subRawImg.jpg")
if img is None:
print("无法加载图像,请检查路径是否正确")
return
img_copy = img.copy()
# 创建窗口并设置鼠标回调
cv2.namedWindow("Select Points")
cv2.setMouseCallback("Select Points", mouse_callback)
print("请按顺序点击选择四个点:上、右、下、左")
print("选择完成后按任意键继续...")
while True:
cv2.imshow("Select Points", img_copy)
key = cv2.waitKey(1) & 0xFF
# 如果已经选择了4个点,按任意键继续
if len(points) == 4:
break
# 执行透视变换
warped = k_perspective_transform(img, points)
# 显示结果
cv2.imshow("Original Image", img)
cv2.imshow("Transformed", warped)
output_path="images/trans/_4point.jpg"
cv2.imwrite(output_path, warped)
print(f"图像已保存到 {output_path}")
cv2.waitKey(0)
cv2.destroyAllWindows()
if __name__ == "__main__":
main()