• 智能车逆透视教程(含上位机、源码)


    1.简介

    对于初做车的同学,看见摄像头图像神奇的侧视角难免会有些烦躁,我刚开始也是如此,所以在此,想详细的分享一下我们的透视变换方案。(实战教学)

    先上各种效果图。

    优点:

            使用指针映射透视变换数组,只需要初始化映射一次,后续不需要时间

            通用性强,可移植性高

           

    2.摄像头环境

            硬件:总钻风摄像头(由于多车组使用沁恒芯片,修改过硬件适应dvp)

            镜头:140度镜头,畸变小于5%

            摄像头分辨率:120*188(长*宽)

            透视图分辨率:100*114(长*宽)

            摄像头高度:30cm左右

    总钻风是很常见的智能车摄像头,之所以选用140度镜头,是因为其角度大,且畸变率非常小,完全不影响图像处理,可以省去去畸变的烦恼,摄像头120*188是因为其比例可以使视野最大。

    3.逆透视简单原理

            众所周知,对于十字这个元素,标准赛道(不算路肩、黑胶带),它是一个宽度为45cm的标准正方形。但是因为摄像头角度问题,十字的正方形在图片中是一个梯形。

    那嚒我们所要做的,就是根据图片中的这一块梯形(实则是正方形),这一个信息,将图片进行拉伸变换,使之成为标准的俯视图。

     公式:

     w与w’在二维图中为1

     已知结果图中坐标,通过上述公式就能在原图中找到对应的坐标。

     那么这个3*3矩阵就是我们需要使用上位机求取的。

    4.通过上位机求取矩阵

    环境准备:

              拍摄的十字图像(或正方形图像),灰度与二值化图均可,要能完全展示出正方形部分,如:

     图像中可以显示出车头,因为在后续的透视过程中可以通过图像修改参数平移去除。

    那么,根据图中的假正方形,就可以进行后续操作。

    上位机操作:

     结果图宽高:得到的透视图像的宽高。

    方形中心距顶部像素:在结果图中,正方形的中心,距离图像最上端多少个像素行(值越大,图像越向下平移)。

    方形像素边长:在结果图中,正方形的边长相当于多少个像素(值越大,图片就会被放大更多,如果是45,就是一像素对应1cm距离)。

    四个XY值:图中方形四个顶点的坐标,通过鼠标右键在图中点击就可以自动输入(点击顺序:左下---右下---左上---右上)。

    逆透视上位机操作

         最终矩阵会复制到您的剪切板中,如:

    1. [0.1090909090909082, -0.1138807429130001, 9.053274682306874;
    2. -4.538883118873238e-017, 0.005865102639296149, 3.630498533724316;
    3. -7.131279423880243e-019, -0.001270772238514164, 0.2133919843597247]

    注意事项:

            1.图片经过逆透视操作后得到的结果图,因为对图片进行了拉伸,底边两个角落可能会出现无内容部分(如下图),使用时应当避免.可通过修改结果图大小,或者增大方形中心距顶部像素来对图形进行平移去除。

             2.鼠标点击顺序要符合左下---右下---左上---右上。

            3.图片路径不能为中文

    5.在智能车上使用矩阵:

    原理说明:

    求得矩阵后,就可根据矩阵,和结果图的坐标,计算出结果图中的某个点,在原图中的坐标。

    但如果每获取到一帧图像,都进行一次映射,非常耗费时间。所以我们使用指针。

    在初始化时只需要对指针地址进行一次映射,以后只需要调用指针数组,就可以获取到透视后的图。(需要注意的是,和图像一样的大的指针数组可能会导致您的内存溢出,所以建议将透视图尺寸缩小,即减小RESULT_ROW与RESULT_COL也可以避免黑边出现

    change_un_Mat[3][3] 是你通过上位机求取的矩阵,在您的剪切板中。

    ImageUsed[0][0]代表图像左上角的值

    PER_IMG    为用来透视变换的图片,如果使用灰度图,那么ImageUsed就是灰度图的逆透视图,

    如果使用二值化图,那么ImageUsed就是二值化的逆透视图

    BlackColor的值为没有内容部分的灰度值。

    只需要初始化时调用一次ImagePerspective_Init()函数,只需要初始化时调用一次!!!!一次就行!!!!!!!

    1. #define RESULT_ROW 100//结果图行列
    2. #define RESULT_COL 114
    3. #define USED_ROW 120 //用于透视图的行列
    4. #define USED_COL 188
    5. #define PER_IMG mt9v03x_image_dvp//mt9v03x_image_dvp:用于透视变换的图像 也可以使用二值化图
    6. #define ImageUsed *PerImg_ip//*PerImg_ip定义使用的图像,ImageUsed为用于巡线和识别的图像
    7. typedef unsigned char uint8_t; // 无符号 8 bits
    8. uint8_t *PerImg_ip[RESULT_ROW][RESULT_COL];
    9. void ImagePerspective_Init(void) {
    10. static uint8_t BlackColor = 0;
    11. double change_un_Mat[3][3] = { //114w*100h
    12. { -0.01609759704190238, 0.01932561893613478, -2.040617594981866 }, {
    13. 0.0004352209945470896, -0.000367865364438621,
    14. -0.7035606436969671 }, { 1.115951268069474e-005,
    15. 0.0001970185393508392, -0.03104642853440032 }, };
    16. for (int i = 0; i < RESULT_COL ;i++) {
    17. for (int j = 0; j < RESULT_ROW ;j++) {
    18. int local_x = (int) ((change_un_Mat[0][0] * i
    19. + change_un_Mat[0][1] * j + change_un_Mat[0][2])
    20. / (change_un_Mat[2][0] * i + change_un_Mat[2][1] * j
    21. + change_un_Mat[2][2]));
    22. int local_y = (int) ((change_un_Mat[1][0] * i
    23. + change_un_Mat[1][1] * j + change_un_Mat[1][2])
    24. / (change_un_Mat[2][0] * i + change_un_Mat[2][1] * j
    25. + change_un_Mat[2][2]));
    26. if (local_x
    27. >= 0&& local_y >= 0 && local_y < USED_ROW && local_x < USED_COL){
    28. PerImg_ip[j][i] = &PER_IMG[local_y][local_x];
    29. }
    30. else {
    31. PerImg_ip[j][i] = &BlackColor; //&PER_IMG[0][0];
    32. }
    33. }
    34. }
    35. }
    36. /*ImageUsed[0][0]代表图像左上角的值*/
    37. /*完成摄像头初始化后,调用一次ImagePerspective_Init,此后,直接调用ImageUsed 即为透视结果*/

    屏幕显示透视变换后的灰度图DEMO:

    1. int main(void)
    2. {
    3. All_Init();//屏幕、摄像头、以及其他外设初始化
    4. ImagePerspective_Init();
    5. while(1)
    6. {
    7. if (mt9v03x_finish_flag_dvp == 1) {
    8. uint8_t show[RESULT_ROW][RESULT_COL];
    9. for(int i=0;i
    10. {
    11. for(int j=0;j
    12. {
    13. show[i][j]=ImageUsed[i][j];
    14. }
    15. }
    16. ips114_show_gray_image(0,0,show[0],RESULT_COL,RESULT_ROW,RESULT_COL,RESULT_ROW,0);
    17. mt9v03x_finish_flag_dvp = 0;
    18. }
    19. }
    20. }

    效果显示: 

    6.资源文件

    智能车逆透视上位机以及代码-C文档类资源-CSDN下载

    代码以及上位机已上传,附带QT编写的上位机代码。

    若上位机打开提示缺少dll,将上位机.exe放入dll文件中打开即可。

  • 相关阅读:
    Spring面试题
    制作一个简单HTML旅游网站(HTML+CSS+JS)无锡旅游网页设计与实现8个页面
    LabVIEW应用开发——控件的使用(二)
    java实现给图片添加水印(文字水印或图片水印)
    ASP.NET CORE在docker中的健康检查(healthcheck)
    油猴Safari浏览器辅助插件:Tampermonkey for Mac中文版
    干了三年外包。。。忘了什么是CICD。。。
    Windows10上使用llama-recipes(LoRA)来对llama-2-7b做fine-tune
    【校招VIP】计算机网络之TCP/IP模型归纳
    使用华为eNSP组网试验⑹-组建基于BGP的网络
  • 原文地址:https://blog.csdn.net/wu58430/article/details/126317900