引言
利用OpenCV的v2.getPerspectiveTransform()、cv2.warpPerspective()函数,实现图片的鸟瞰转换。
OpenCV 和 Python版本满足:Python 2.7/Python 3.4+ 和 OpenCV 2.4.X/OpenCV 3.0+.
代码地址:https://github.com/wangwangwang97/GitProject/tree/master/get-perspective-transform-example
示例
之前的文章:构建真实Pokedexhttps://pyimagesearch.com/2014/05/05/building-pokedex-python-opencv-perspective-warping-step-5-6/提到了用透视变换来获得图像的自顶向下的‘鸟瞰图’,前提是找到参考点。
本篇文章:继续对图像的自上而下的‘鸟瞰’进行讨论,但这次会分享进行四点转换时的代码。
代码1:order_points函数
将四个点坐标表示为有序列表的形式
- 代码2-3行:导入所需的包,numpy包用于数值计算,cv2包用于绑定OpenCV。
- 代码第5行:定义order_points函数,这个函数只有一个参数,即pts,它包含矩形的四个(x,y)形式点的坐标。
- 代码第10行:创建一个有序列表rect用于有序的存储四个矩形点坐标(列表中矩形点的顺序很重要,事实上在实际项目中只要保持顺序一致即可,个人喜欢的顺序为左上、右上、右下和左下)
- 代码14-16行:在矩形中,左上角点会有最小的x+y总和,右下角点会有最大的x+y总和,通过这个信息为有序列表添加左上角rect[0]和右下角rect[2]元素。
- 代码第21行:计算点的差异,即(x-y),这一操作可以通过np.diff实现。
- 代码第22-23行:差异最小的是右上角的点,差异最大的是左下角,通过这个信息为有序列表添加右上角rect[1]和左下角rect[3]元素
- 代码第26行:返回原始点(pts)的有序列表
代码2:four_point_transform函数
透视图转鸟瞰图
- 代码第28行:定义four_point_transform函数,需要两个参数,image和pts。image是我们将要应用透视变换的图像,pts是我们想要转换的图像中的感兴趣区域的四个点列表。
- 代码第31-32行:调用代码1的函数,将pts中的坐标点变为有序,并获取每个点的坐标。
- 代码第37-39行:确定新图像的宽度,其中宽度是右下角和左下角x坐标或右上角和左上角x坐标的距离,选择最大距离为新图像的宽。
- 代码第44-46行:确定新图像的高度,其中高度是左上角和左下角y坐标或右上角和右下角y坐标之间的最大距离,选择最大距离为新图像的高。
- 代码第53-57行:定义四个点组成的列表dst,代表自顶向下表示的图像。第一个元素为(0,0)代表左上角,第二个元素为(maxWidth - 1, 0)代表右上角坐标,第三个元素为(maxWidth - 1, maxHeight - 1)代表右下角,第四个元素为(0, maxHeight - 1)代表左下角。
- 代码第60行:使用cv2.getPerspectiveTransform函数,此函数需要两个参数:rect(四个感兴趣点坐标组成的列表),dst(想让四个感兴趣点转换后的坐标位置组成的列表)。这个函数将返回一个转换矩阵M.
- 代码第61行:使用cv2.warpPerspective函数,参数为:图像、转换矩阵M、输出图片的宽度和高度。
- 代码第64行:返回自顶向下的视图。
代码3:驱动代码
图片调用转换函数的驱动代码
- 代码第2行:导入我们定义的four_point_transform函数。
- 代码第3-5行:导入其他所需要的包,NumPy用于数组功能, argparse 用于解析命令行参数, cv2 用于OpenCV绑定。
- 代码第8-12行:解析命令行参数,使用两个开关:–image表示我们将要转换的图像,–coords是四个点的列表,这些点代表我们想要获得鸟瞰视角的图像区域的坐标点。
- 代码第19行:加载图像
- 代码第20行:加载坐标点,并转换为numpy数组形式。
- 代码第24行:应用透视变换
- 代码第27-29行:展示原图和透视变换后的图。
本文中需要自己选择需要透视变换的四个点的坐标(即感兴趣区域的四个点坐标,rect)有一些自动确定透视变换所需4个点的方法(如角点检测、边缘检测等),而无需人工操作,这里就不进行陈述。
代码运行
在shell中执行:
python transform_example.py --image images/example_03.png --coords "[(63, 242), (291, 110), (361, 252), (78, 386)]"