逆透视请参考:智能车逆透视教程(含上位机、源码)_LoseHu的博客-CSDN博客
去畸变请参考:智能车去畸变教程(含上位机、源码)_LoseHu的博客-CSDN博客
逆透视+去畸变:如下
1.简介
在前两个博文中已经分别说明了单独去畸变、逆透视的方法。为了同时实现畸变+逆透视,利用之前博文的教程分两步求取矩阵,进行变换。原图以及效果图:
编辑编辑
正如逆透视以及去畸变那样,这种综合的方法自然是保留了两者的特点,例如可以去除图像的畸变,仍然可以利用透视更改图片缩放、图片大小、视野大小。。。。
2.优点
兼具了去畸变与逆透视的优点
3.原理
参考去畸变与逆透视的原理
4.通过上位机求取变换参数
通过上位机分两步完成,具体每一步请参考:
1.逆透视:智能车逆透视教程(含上位机、源码)_LoseHu的博客-CSDN博客
2.去畸变:智能车去畸变教程(含上位机、源码)_LoseHu的博客-CSDN博客
如视频中的那样,每一步都需要将剪切板中的参数保存下来,如
double cameraMatrix[3][3]={{296.482019,0.000000,152.664982},{0.000000,286.375269,104.540031},{0.000000,0.000000,1.000000}};
double distCoeffs[5]={-0.459946,0.283675,0.002304,0.002566,-0.109265};
int move_xy[2]={55,32};
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获取图像像素值。
记得替换其中的参数
代码如下:
// // Created by RUPC on 2022/10/29. // #define RESULT_ROW 100 //结果图的行列 #define RESULT_COL 114 #define USED_ROW 120 //用于变换图的行列 #define USED_COL 188 typedef unsigned char uint8_t; // 无符号 8 bits uint8_t *PerImg_ip[RESULT_ROW][RESULT_COL]; #define PER_IMG mt9v03x_image_dvp//mt9v03x_image_dvp:用于透视变换的图像 也可以使用二值化图 #define ImageUsed *PerImg_ip//*PerImg_ip定义使用的图像,ImageUsed为用于巡线和识别的图像 static uint8_t BlackColor = 255; //无内容部分像素值 /******************变换参数******************************/ //去畸变参数 double cameraMatrix[3][3] = {{296.482019, 0.000000, 152.664982}, {0.000000, 286.375269, 104.540031}, {0.000000, 0.000000, 1.000000}}; double distCoeffs[5] = {-0.459946, 0.283675, 0.002304, 0.002566, -0.109265}; int move_xy[2] = {10, 0}; //逆透视参数 double change_un_Mat[3][3] = {{2.936703, 0.314530, -60.814898}, {-0.263326, 2.308885, -108.340381}, {-0.000835, 0.000896, 0.969316}}; /*******************************************************/ void find_xy(int x, int y, int local[2]) { double fx = cameraMatrix[0][0] , fy = cameraMatrix[1][1] , ux = cameraMatrix[0][2] , uy = cameraMatrix[1][2] , k1 = distCoeffs[0] , k2 = distCoeffs[1] , k3 = distCoeffs[4] , p1 = distCoeffs[2] , p2 = distCoeffs[3]; double xCorrected = (x - ux) / fx; double yCorrected = (y - uy) / fy; double xDistortion, yDistortion; double r2 = xCorrected * xCorrected + yCorrected * yCorrected; double deltaRa = 1. + k1 * r2 + k2 * r2 * r2 + k3 * r2 * r2 * r2; double deltaRb = 1 / (1.); double deltaTx = 2. * p1 * xCorrected * yCorrected + p2 * (r2 + 2. * xCorrected * xCorrected); double deltaTy = p1 * (r2 + 2. * yCorrected * yCorrected) + 2. * p2 * xCorrected * yCorrected; xDistortion = xCorrected * deltaRa * deltaRb + deltaTx; yDistortion = yCorrected * deltaRa * deltaRb + deltaTy; xDistortion = xDistortion * fx + ux; yDistortion = yDistortion * fy + uy; if (yDistortion >= 0 && yDistortion < USED_ROW && xDistortion >= 0 && xDistortion < USED_COL) { local[0] = (int) yDistortion; local[1] = (int) xDistortion; } else { local[0] = -1; local[1] = -1; } } void find_xy1(int x, int y, int local[2]) { int local_x = (int) ((change_un_Mat[0][0] * x + change_un_Mat[0][1] * y + change_un_Mat[0][2]) / (change_un_Mat[2][0] * x + change_un_Mat[2][1] * y + change_un_Mat[2][2])); int local_y = (int) ((change_un_Mat[1][0] * x + change_un_Mat[1][1] * y + change_un_Mat[1][2]) / (change_un_Mat[2][0] * x + change_un_Mat[2][1] * y + change_un_Mat[2][2])); if (local_x >= 0 && local_y >= 0) { local[0] = local_y; local[1] = local_x; } else { local[0] = -1; local[1] = -1; } } void ImageChange_Init() { for (int i = 0; i < RESULT_ROW; i++) { for (int j = 0; j < RESULT_COL; j++) { int local_xy[2] = {-1}; find_xy1(j, i, local_xy); if (local_xy[0] != -1 && local_xy[0] != -1) { int local_xy1[2] = {-1}; find_xy(local_xy[1] - move_xy[0], local_xy[0] - move_xy[1], local_xy1); if (local_xy1[0] != -1 && local_xy1[1] != -1) { PerImg_ip[i][j] = &mt9v03x_image_dvp[local_xy1[0]][local_xy1[1]]; } else PerImg_ip[i][j] = &BlackColor; } else PerImg_ip[i][j] = &BlackColor; } } } /*ImageUsed[0][0]代表图像左上角的值*/ /*完成摄像头初始化后,调用一次ImagePerspective_Init,此后,直接调用ImageUsed 即为去畸变结果*/
屏幕显示去畸变+逆透视后的灰度图DEMO:
int main(void) { All_Init();//屏幕、摄像头、以及其他外设初始化 ImageChange_Init(); while(1) { if (mt9v03x_finish_flag_dvp == 1) { uint8_t show[RESULT_ROW][RESULT_COL]; for(int i=0;i<RESULT_ROW;i++) { for(int j=0;j<RESULT_COL;j++) { show[i][j]=ImageUsed[i][j]; } } ips114_show_gray_image(0,0,show[0],RESULT_COL,RESULT_ROW,RESULT_COL,RESULT_ROW,0); mt9v03x_finish_flag_dvp = 0; } } }
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 融合两种方法,修复保存图像色彩错误问题
标签:教程,int,透视,畸变,图像处理,double,local,change From: https://www.cnblogs.com/RUBO/p/16854009.html