2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > 图像矫正--python_OpenCV实现透视变换

图像矫正--python_OpenCV实现透视变换

时间:2023-01-06 02:54:30

相关推荐

图像矫正--python_OpenCV实现透视变换

透视变换(Perspective Transform)和仿射变换(Affine Transform)在图像还原、局部变化处理方面有重要意义。通常,在2D平面中,仿射变换的应用比较多;在3D平面中,透视变换占领地位较高。两种变换原理相似,结果也相似,可以针对不同场合选择适合方法。

两者的计算方法就是矩阵运算,即,坐标向量和变换矩阵的乘积。

仿射变换是基于图像的3个固定顶点进行变换,如下图:

透视变换:利用透视中心、像点、目标点三点共线,按照透视旋转定律使承影面(透视面or原始图)绕迹线(透视轴)旋转某一角度,破坏原有的投影光线束,仍能保持承影面上需要投影的集合图像不变。

透视变换常用于视觉导航研究中,由于摄像机(or声呐等摄影设备)和地面(or海底)之间有倾斜角,不是直接垂直朝下进行的正向投影,有的工程应用希望将图像矫正为正向投影,就需要利用透视变换。

透视变换基于图像的4个顶点,如下图:

透视变换的python实现:

"""首先顺时针点击需要矫正部分的左上,右上,右下,左下四个角点来对其进行图像矫正;然后随机点击键盘任意按键得到矫正后的图像;最后随机点击键盘任意按键退出。"""import numpy as npimport cv2def order_points(pts):# 初始化坐标点rect = np.zeros((4,2), dtype='float32')# 获取左上角和右下角坐标点s = pts.sum(axis=1) # 每行像素值进行相加;若axis=0,每列像素值相加rect[0] = pts[np.argmin(s)] # top_left,返回s首个最小值索引,eg.[1,0,2,0],返回值为1rect[2] = pts[np.argmax(s)] # bottom_left,返回s首个最大值索引,eg.[1,0,2,0],返回值为2# 分别计算左上角和右下角的离散差值diff = np.diff(pts, axis=1) # 第i+1列减第i列rect[1] = pts[np.argmin(diff)]rect[3] = pts[np.argmax(diff)]return rectdef four_point_transform(image, pts):# 获取坐标点,并将它们分离开来rect = order_points(pts)(tl, tr, br, bl) = rect# 计算新图片的宽度值,选取水平差值的最大值widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))maxWidth = max(int(widthA), int(widthB))# 计算新图片的高度值,选取垂直差值的最大值heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))maxHeight = max(int(heightA), int(heightB))# 构建新图片的4个坐标点,左上角为原点dst = np.array([[0, 0],[maxWidth - 1, 0],[maxWidth - 1, maxHeight - 1],[0, maxHeight - 1]], dtype = "float32")# 获取透视变换矩阵并应用它M = cv2.getPerspectiveTransform(rect, dst)# 进行透视变换warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))# 返回变换后的结果return warpeddef on_mouse(event, x, y, flags, param):"""鼠标在原图像点击,获取矩形的四个边角点坐标"""global timg, pointsimg2 = timg.copy()p0 = (0,0) # 初始化if event == cv2.EVENT_LBUTTONDOWN:p1 = (x,y)points.append([x,y])print(p1)# 在点击图像处绘制圆# cv2.circle(image, center_coordinates, radius, color, thickness)cv2.circle(img2, p1, 4, (0,255,0), 4)cv2.imshow('origin', img2)return p0if __name__ =="__main__":global points, timgxscale, yscale = 0.5,0.5 # 通过放大图像使点击位置更加精确points = []img = cv2.imread('C:/Users/W1998/Desktop/photo/card.jpg')shape = img.shapetimg = cv2.resize(img, (int(shape[1]/xscale), int(shape[0]/yscale))) # 放大图像print(timg.shape)cv2.imshow('origin', timg)cv2.setMouseCallback('origin', on_mouse) # 此处设置显示的图片名称一定要和上一句以及on_mouse函数中设置的一样cv2.waitKey(0) # 四个角点点击完后,随机按键盘结束操作cv2.destroyAllWindows()# 还原像素位置points = np.array(points, dtype=np.float32)points[:,0] *= shape[1] / int(shape[1]/xscale) points[:,1] *= shape[0] / int(shape[0]/yscale)warped = four_point_transform(img, points)cv2.imshow('results', warped)cv2.waitKey(0)cv2.destroyAllWindows()

初始图:

经透视变换矫正后的结果图:

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。