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
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()
|