目录
一、前言
本文主要讲解智能车赛中逆透视应用和实现。
注:本文逆透视文件即源码接来自于b站开源博主“__苏格拉没有底___”,此处仅是讲解其用法
二、逆透视
1.逆透视讲解 (个人理解)
逆透视具体原理不需理解很透彻,因摄像头斜视(─━ _ ─━✧),导致所获得的图像并非是实际的图像,当我们需要实际的真实图像时,可对原图像进行逆透视变换,即将原斜视图像变换为上帝视角,可以在一定程度上精确元素判断。
同时可获得变换3 * 3矩阵,可以直接对拐点进行逆透视,然后求出实际角度,对锐角,直角,钝角判定有很好的效果。
示例:
2、逆透视数组获取
1. 首先要确定自己要处理的图像大小,之后尽量不做更改。
2. 先下载MATLAB,内存有点大,至于收费问题,懂的都懂(可以去b站找)整套操作不需要MATLAB基础。
3. 按照路径:求逆透视相关—>透视处理—>图像透视处理2,打开文件中图像透视处理法2(文件可由文章附带文件下载,若平台收费,可在b站找“__苏格拉没有底___”下载文件)
4.在安装好MATLAB的前提下,jiaozhen文件会变为MATLAB可读文件,双击它打开:
5.之后打开 “图像透视处理法1” 文件,同时点开step1,step2,即和jiaozhen一同在MATLAB页面内, 如下所示(注意图像路径更改)
6.左侧会有 图像透视处理法1 中的所有照片,其中huandao1,shizi1,wandao1是作者本人导入的实际图片,可将这三个图片替换为自己的照片,在后面有介绍图片获得方式
7.然后在文件“jiaozhen.m”和“Step2.m”中更改你的测试图片路径(以下为“jiaozhen.m”文件的路径,另一文件与此相同) 注意照片格式要和文件中一致
8.然后先调数组大小,要将文件内所有的60,80改为自己图像的Image_Y,Image_X。快速更改方法:双击60,按“Ctrl + F”调出查找替换框,选中“全字匹配”,将替换框内搞好自己的数值后,点击“全部替换”。另一数值重复此操作。
9.之后就是调参(参数全部在“jiaozhen.m”文件中),首先是 桶形畸变 因为使用总钻风130无畸变摄像头,故不存在桶形畸变,根据注释将k1,k2设为0即可
10.接着是梯形畸变矫正 虽然是无畸变摄像头,但是有梯形畸变,具体可以查阅资料,然后这里有三个参数:
① h: 单位是米,将自己车放到平地上,拿尺子测摄像头高度,不需那么准确,但越准确越好,将得到的值替换h,我这里是30.5cm
②alpha:注释里的东西不用管,这个参数可以自己调出来,先大致调,再细调,自己试一下,随着数加一减一变化都很明显,可以 很快得到最适合的值,那么什么时候合适呢,就是你看着图像的高最顺眼的时候(黑色无效区域较少,原图像内东西大多存在),这个没有难度,每调一次,按F5运行一次,看输出的图像
补充一下:正确运行代码会得到三张输出结果,其中Figure1为桶形畸变矫正结果,因为值为0,所以和原图像无异;Figure3为逆透视图像,是重点关注图像;Figure4为反逆透视图像(将逆透视后图像再次运算,反向求出原图像),可以和原图像比对
③beta:注释里东西也不用管,和alpha方法相同,几下就能调出来,也是看着最顺眼的时候就可以
11.接下来调整拉展与平移,也是自己调,调一次运行一次看看效果,很快就能调出来,也是自己看着最顺眼的时候就可以了
3、样图
这里放入我最终输出的几张样图:
逆透视不可避免的会丢失部分信息,同时会出现三角黑边 。此时我已经调好参数,得到观感较好的逆透视图像,调试上述三个参数时可以参考我的效果。
三、灰度图像获得
方法有很多,但都必须有上位机,将自己摄像头的图像发送到上位机上,截屏,修改尺寸(尺寸与循迹时处理的图像长宽一致 。如本人代码中就是Find_Line_Image,长为80,宽为60),WIFI图传我在另一文档有介绍,本人使用逐飞WiFi图传模块搭配逐飞助手获取图像。
然后从上位机获得如下图像(自己推着车去实地取图),注意截屏时一定要细致,不可多不可少,就描着传过来的图像截屏,不要截到多余外部,然后进行压缩。
样例:
还是再补充下压缩图像吧:
①找到你的截图,双击打开
②右键,选择“改尺寸”
③选择“等比缩放”,配置好相关参数,然后点保存,就获得了一个摄像头原图像,将此图像导入MATLAB(即放入”图像透视处理法2“文件)
四、逆透视数组使用
1、实现逆透视
根据上述流程调试好参数,运行代码后,会在文件“图像透视处理1”中得到四个数组文件:
四个数组为:逆透视X坐标变换矩阵、逆透视Y坐标变换矩阵、返逆透视X坐标变换矩阵、返逆透视Y坐标变换矩阵。
打开车赛开发软件,新建文件,并定义两个数组存放得到的逆透视坐标变换矩阵:
之后写函数进行逆透视变换即可:
/**
* 函数功能: 求逆透视图像
* 特殊说明: 使用MATLAB中得到的逆透视矩阵实现
* 形 参: uint8(*source_image)[Image_X] 要进行逆透视变换的矩阵
* uint8 (*target_image)[Image_X] 逆透视变换后的图像
*
* 示例: Get_Inverse_Perspective_Image(Find_Line_Image, I_Perspective_Image);
* 返回值: 无
*/
void Get_Inverse_Perspective_Image(uint8(*source_image)[Image_X], uint8 (*target_image)[Image_X]) //835us
{
uint8 i = 0, j = 0;
for(j = 0; j < Image_Y; j ++)
{
for(i = 0; i < Image_X; i ++)
{
target_image[j][i] = source_image[Inverse_Matrix_Col[j * Image_X + i]][Inverse_Matrix_Row[j * Image_X + i]];
}
}
}
反逆透视变换:
//求逆透视的反逆透视图像
/**
* 函数功能: 求逆透视的反逆透视图像
* 特殊说明: 使用MATLAB中得到的反逆透视矩阵实现
* 形 参: uint8(*Source_Image)[Image_X] 要进行反逆透视的逆透视图像
* uint8(*target_image)[Image_X] 存储反逆透视变换后的图像
*
* 示例: Get_Back_Inverse_Perspective_Image(I_Perspective_Image, Back_I_Perspective_Image);
* 返回值: 无
*/
void Get_Back_Inverse_Perspective_Image(uint8(*Source_Image)[Image_X], uint8(*target_image)[Image_X])
{
uint8 i = 0, j = 0;
for(j = 0; j < Image_Y; j ++)
{
for(i = 0; i < Image_X; i ++)
{
target_image[j][i] = Source_Image[Back_Inverse_Matrix_Col[j * Image_X + i]][Back_Inverse_Matrix_Row[j * Image_X + i]];
}
}
}
这里要注意逆透视矩阵在数组内的定位。
2、逆透视求实际角度
求原图像拐角的实际角度(将角三点逆透视过来求角度)
//-------------------------------------------------------------------------------------------------------------------
// @brief 逆透视知三点求形成的角度
// @param Ax,Ay 下边点
// @param Bx,By 要求角度的一点
// @param Cx,Cy 上边点
// @return
// @since v1.0
// Sample usage:
// 注:使用时传入原图像的三个点,不可传入逆透视图像的三个点
//-------------------------------------------------------------------------------------------------------------------
float Get_Turn_Point_Angle(uint8 Ax, uint8 Ay, uint8 Bx, uint8 By, uint8 Cx, uint8 Cy)
{
float BA = 0.00;//向量BA的模
float BC = 0.00;
float SBA_BC = 0.00;//向量点乘的值
float Angle = 0.00;
uint8 AX = Back_Inverse_Matrix_Row[Ay * Image_X + Ax];
uint8 AY = Back_Inverse_Matrix_Col[Ay * Image_X + Ax];
uint8 BX = Back_Inverse_Matrix_Row[By * Image_X + Bx];
uint8 BY = Back_Inverse_Matrix_Col[By * Image_X + Bx];
uint8 CX = Back_Inverse_Matrix_Row[Cy * Image_X + Cx];
uint8 CY = Back_Inverse_Matrix_Col[Cy * Image_X + Cx];
BA = sqrt((float)((AX-BX)*(AX-BX)+(AY-BY)*(AY-BY)));
BC = sqrt((float)((CX-BX)*(CX-BX)+(CY-BY)*(CY-BY)));
SBA_BC = (float)((AX-BX)*(CX-BX)+(AY-BY)*(CY-BY));
Angle = acos(SBA_BC * 1.00/ (BA * BC));
return Angle * 57.3f;
}
逆透视图相关拐点求角度:
//逆透视后的图像拐点求角度
float I_Get_Turn_Point_Angle(uint8 Ax, uint8 Ay, uint8 Bx, uint8 By, uint8 Cx, uint8 Cy)
{
float BA = 0.00;//向量BA的模
float BC = 0.00;
float SBA_BC = 0.00;//向量点乘的值
float Angle = 0.00;
BA = sqrt((float)((Ax-Bx)*(Ax-Bx)+(Ay-By)*(Ay-By)));
BC = sqrt((float)((Cx-Bx)*(Cx-Bx)+(Cy-By)*(Cy-By)));
SBA_BC = (float)((Ax-Bx)*(Cx-Bx)+(Ay-By)*(Cy-By));
Angle = acos(SBA_BC * 1.00/ (BA * BC));
return Angle * 57.3f;
}
以上方法求出来的角度并非百分百准确,而是要有一定误差范围,比如找九十度直角,那么80° ~ 110°都可认为是直角。
3、逆透视图像处理元素
逆透视不论是对于拐点找寻还是元素判断等,其实与原图像的判断、找寻、处理方法类似,属于触类旁通了。对于原图像的元素判断和处理等,会在后续文章讲解。
4、边线逆透视变换
也是使用得到的逆透视变换矩阵进行处理,可将原图像得到的边线进行逆透视变换得到实际的赛道边线。处理方式与图像逆透视极其相似,只是将每个图像点的遍历更改为每个边线点的遍历,所以就不过多讲述,理解上述代码后相必很快自己就能敲出来这部分代码。
这样变换会存在噪点和断点,至于怎么处理,就需读者自行发挥了。
五、对于逆透视的观点
对于车赛来说,其实逆透视并不是必须的,特别是对于逆透视后的图像来说,赛道边线会存在非常多噪点,使用爬线算法提取会遇到非常多的问题。同时这些噪点的干扰并非简单的处理就可以解决的。使用高斯模糊等又会消耗非常多的算力。之前本人有尝试将高斯模糊与自适应迷宫算法相结合,即只将需要使用的点进行高斯模糊处理,效果也不甚理想。
对于逆透视图像,更适合最长白直列向左右扫线求取边线的算法。
但本人并没有过多尝试逆透视的应用和处理,至于怎样达到更好的效果,需要读者花费更多时间精力去探索,对于车赛来说,处理原图像绝对是够用的。
标签:Inverse,透视,Image,float,uint8,开源,图像,摄像头 From: https://blog.csdn.net/lh66969696/article/details/143098606