逆透视请参考:智能车逆透视教程(含上位机、源码)_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 融合两种方法,修复保存图像色彩错误问题
转载:https://blog.csdn.net/wu58430/article/details/127592501