小言_互联网的博客

智能车图像处理去畸变+逆透视教程

326人阅读  评论(0)

逆透视请参考:智能车逆透视教程(含上位机、源码)_LoseHu的博客-CSDN博客

去畸变请参考:智能车去畸变教程(含上位机、源码)_LoseHu的博客-CSDN博客

逆透视+去畸变:如下

1.简介

        在前两个博文中已经分别说明了单独去畸变、逆透视的方法。为了同时实现畸变+逆透视,利用之前博文的教程分两步求取矩阵,进行变换。原图以及效果图:

 正如逆透视以及去畸变那样,这种综合的方法自然是保留了两者的特点,例如可以去除图像的畸变,仍然可以利用透视更改图片缩放、图片大小、视野大小。。。。

2.优点

        兼具了去畸变与逆透视的优点

3.原理

        参考去畸变与逆透视的原理

4.通过上位机求取变换参数

        通过上位机分两步完成,具体每一步请参考:

        1.逆透视:智能车逆透视教程(含上位机、源码)_LoseHu的博客-CSDN博客

        2.去畸变:智能车去畸变教程(含上位机、源码)_LoseHu的博客-CSDN博客

去畸变+逆透视演示

        如视频中的那样,每一步都需要将剪切板中的参数保存下来,如


  
  1. double cameraMatrix[ 3][ 3]={{ 296.482019, 0.000000, 152.664982},{ 0.000000, 286.375269, 104.540031},{ 0.000000, 0.000000, 1.000000}};
  2. double distCoeffs[ 5]={ -0.459946, 0.283675, 0.002304, 0.002566, -0.109265};
  3. int move_xy[ 2]={ 55, 32};
  4. double change_un_Mat[ 3][ 3] ={{ -1.762057, 1.446330, -48.051135},{ 0.111681, 0.215732, -90.406315},{ 0.000404, 0.006296, -1.003619}};

注意事项:

        1.每一步注意事项参考对应的博客

        2.记得保存去畸变后用于逆透视的图片与两步的参数

5.在智能车上完成去畸变+逆透视

        使用时,只需在图像初始化中调用一次ImageChange_Init()函数即可,如去畸变与逆透视一样,这个初始化函数在整个程序中应该只被调用一次。后续使用ImageUsed获取图像像素值。

        记得替换其中的参数

代码如下:


  
  1. //
  2. // Created by RUPC on 2022/10/29.
  3. //
  4. #define RESULT_ROW 100 //结果图的行列
  5. #define RESULT_COL 114
  6. #define USED_ROW 120 //用于变换图的行列
  7. #define USED_COL 188
  8. typedef unsigned char uint8_t; // 无符号 8 bits
  9. uint8_t *PerImg_ip[RESULT_ROW][RESULT_COL];
  10. #define PER_IMG mt9v03x_image_dvp//mt9v03x_image_dvp:用于透视变换的图像 也可以使用二值化图
  11. #define ImageUsed *PerImg_ip//*PerImg_ip定义使用的图像,ImageUsed为用于巡线和识别的图像
  12. static uint8_t BlackColor = 255; //无内容部分像素值
  13. /******************变换参数******************************/
  14. //去畸变参数
  15. double cameraMatrix[ 3][ 3] = {{ 296.482019, 0.000000, 152.664982},
  16. { 0.000000, 286.375269, 104.540031},
  17. { 0.000000, 0.000000, 1.000000}};
  18. double distCoeffs[ 5] = { -0.459946, 0.283675, 0.002304, 0.002566, -0.109265};
  19. int move_xy[ 2] = { 10, 0};
  20. //逆透视参数
  21. double change_un_Mat[ 3][ 3] = {{ 2.936703, 0.314530, -60.814898},
  22. { -0.263326, 2.308885, -108.340381},
  23. { -0.000835, 0.000896, 0.969316}};
  24. /*******************************************************/
  25. void find_xy(int x, int y, int local[2]) {
  26. double fx = cameraMatrix[ 0][ 0]
  27. , fy = cameraMatrix[ 1][ 1]
  28. , ux = cameraMatrix[ 0][ 2]
  29. , uy = cameraMatrix[ 1][ 2]
  30. , k1 = distCoeffs[ 0]
  31. , k2 = distCoeffs[ 1]
  32. , k3 = distCoeffs[ 4]
  33. , p1 = distCoeffs[ 2]
  34. , p2 = distCoeffs[ 3];
  35. double xCorrected = (x - ux) / fx;
  36. double yCorrected = (y - uy) / fy;
  37. double xDistortion, yDistortion;
  38. double r2 = xCorrected * xCorrected + yCorrected * yCorrected;
  39. double deltaRa = 1. + k1 * r2 + k2 * r2 * r2 + k3 * r2 * r2 * r2;
  40. double deltaRb = 1 / ( 1.);
  41. double deltaTx = 2. * p1 * xCorrected * yCorrected + p2 * (r2 + 2. * xCorrected * xCorrected);
  42. double deltaTy = p1 * (r2 + 2. * yCorrected * yCorrected) + 2. * p2 * xCorrected * yCorrected;
  43. xDistortion = xCorrected * deltaRa * deltaRb + deltaTx;
  44. yDistortion = yCorrected * deltaRa * deltaRb + deltaTy;
  45. xDistortion = xDistortion * fx + ux;
  46. yDistortion = yDistortion * fy + uy;
  47. if (yDistortion >= 0 && yDistortion < USED_ROW && xDistortion >= 0 && xDistortion < USED_COL) {
  48. local[ 0] = ( int) yDistortion;
  49. local[ 1] = ( int) xDistortion;
  50. } else {
  51. local[ 0] = -1;
  52. local[ 1] = -1;
  53. }
  54. }
  55. void find_xy1(int x, int y, int local[2]) {
  56. int local_x = ( int) ((change_un_Mat[ 0][ 0] * x
  57. + change_un_Mat[ 0][ 1] * y + change_un_Mat[ 0][ 2])
  58. / (change_un_Mat[ 2][ 0] * x + change_un_Mat[ 2][ 1] * y
  59. + change_un_Mat[ 2][ 2]));
  60. int local_y = ( int) ((change_un_Mat[ 1][ 0] * x
  61. + change_un_Mat[ 1][ 1] * y + change_un_Mat[ 1][ 2])
  62. / (change_un_Mat[ 2][ 0] * x + change_un_Mat[ 2][ 1] * y
  63. + change_un_Mat[ 2][ 2]));
  64. if (local_x
  65. >= 0 && local_y >= 0) {
  66. local[ 0] = local_y;
  67. local[ 1] = local_x;
  68. } else {
  69. local[ 0] = -1;
  70. local[ 1] = -1;
  71. }
  72. }
  73. void ImageChange_Init() {
  74. for ( int i = 0; i < RESULT_ROW; i++) {
  75. for ( int j = 0; j < RESULT_COL; j++) {
  76. int local_xy[ 2] = { -1};
  77. find_xy1(j, i, local_xy);
  78. if (local_xy[ 0] != -1 && local_xy[ 0] != -1) {
  79. int local_xy1[ 2] = { -1};
  80. find_xy(local_xy[ 1] - move_xy[ 0], local_xy[ 0] - move_xy[ 1], local_xy1);
  81. if (local_xy1[ 0] != -1 && local_xy1[ 1] != -1) {
  82. PerImg_ip[i][j] = &mt9v03x_image_dvp[local_xy1[ 0]][local_xy1[ 1]];
  83. } else PerImg_ip[i][j] = &BlackColor;
  84. } else PerImg_ip[i][j] = &BlackColor;
  85. }
  86. }
  87. }
  88. /*ImageUsed[0][0]代表图像左上角的值*/
  89. /*完成摄像头初始化后,调用一次ImagePerspective_Init,此后,直接调用ImageUsed 即为去畸变结果*/

  屏幕显示去畸变+逆透视后的灰度图DEMO:


  
  1. int main(void)
  2. {
  3. All_Init(); //屏幕、摄像头、以及其他外设初始化
  4. ImageChange_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<RESULT_ROW;i++)
  10. {
  11. for( int j= 0;j<RESULT_COL;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.资源文件

        其中包含了测试图包

        CSDN:https://download.csdn.net/download/wu58430/86399773

        推荐github:https://github.com/wu58430/RUBO-IPM

        如果只使用用途,下载github中Release即可。

        现在已经完成了逆透视、去畸变、逆透视+去畸变的操作,除非程序有重大bug,后续不会考虑更新。此三种只是图片处理方法,如此软件只适用于简化和降低操作的门槛,以便大家共同进步,图像处理方法无好坏之分,但确实有精妙与粗糙之别。

版权声明:

        此软件仅用于竞赛、学习交流,禁止任何商业用途,包括有营利性的、商业的教学指导活动。

7.更新日志

        2022.8.23        修复了不同版本windows兼容问题

        2022.8.27        修复中文路径、视图大小异常问题,缩小程序体积

        2022.9.23        增加了彩色图像显示,输出格式改为数组

        2022.10.7        代码迁移至QT6.3.1环境,加入去畸变,加入保存图片功能
        2022.10.29        融合两种方法,修复保存图像色彩错误问题


转载:https://blog.csdn.net/wu58430/article/details/127592501
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场