测试环境
opencv310
vs2022
算法源码获取:
链接:https://pan.baidu.com/s/1kVUA2YgRAxk7m1TYi-wsnQ?pwd=aax9 提取码:aax9
算法的实现主要是根据四个摄像头的安装位置、相机的的内外参数实现对图像的畸变矫正、视图的变换和全景的图像拼接、图像拼接的位置的平滑过度;
测试的输出效果图像
算法的实现过程
需要根据标定相机的外参数初始化相机旋转和平移矩阵
js_initAngle(Data->data_TOP_F, 90, 0, 0); js_initAngle(Data->data_0_F, 25, 0, 0); js_initAngleT(Data->data_TOP_F, Data->data_TOP_T_F);
js_initAngle(Data->data_TOP_B, 90, 0, 180); js_initAngle(Data->data_0_B, 25, 0, 0); js_initAngleT(Data->data_TOP_B, Data->data_TOP_T_B);
js_initAngle(Data->data_TOP_L, 90, -90, 0); js_initAngle(Data->data_0_L, 25, 0, 0); js_initAngleT(Data->data_TOP_L, Data->data_TOP_T_L);
js_initAngle(Data->data_TOP_R, 90, 90, 0); js_initAngle(Data->data_0_R, 25, 0, 0); js_initAngleT(Data->data_TOP_R, Data->data_TOP_T_R);
需要根据标定相机的内参参数初始化相机畸变矫正参数(当前测试的相机内参是相同的,所以使用相同的参数进行初始化)
for (int i = 0; i < 4; i++)
{
Data->Aa[i] = a[i];
Data->Fa[i] = a[i];
Data->Ba[i] = a[i];
Data->La[i] = a[i];
Data->Ra[i] = a[i];
}
创建拼接系数表的内存并初始化参数表
Data->Ftable = (float*)malloc(Dw * Dh * sizeof(float));
Data->Btable = (float*)malloc(Dw * Dh * sizeof(float));
Data->Ltable = (float*)malloc(Dw * Dh * sizeof(float));
Data->Rtable = (float*)malloc(Dw * Dh * sizeof(float));
初始化后的系数表可视化显示的结果
Dimg[3 * i + 0 + j * 3 * Dw] += (unsigned char)(Data->Ftable[i + j * Dw] * 255);
Dimg[3 * i + 1 + j * 3 * Dw] += (unsigned char)(Data->Ftable[i + j * Dw] * 255);
Dimg[3 * i + 2 + j * 3 * Dw] += (unsigned char)(Data->Ftable[i + j * Dw] * 255);
Dimg[3 * i + 0 + j * 3 * Dw] += (unsigned char)(Data->Btable[i + j * Dw] * 255);
Dimg[3 * i + 1 + j * 3 * Dw] += (unsigned char)(Data->Btable[i + j * Dw] * 255);
Dimg[3 * i + 2 + j * 3 * Dw] += (unsigned char)(Data->Btable[i + j * Dw] * 255);
Dimg[3 * i + 0 + j * 3 * Dw] += (unsigned char)(Data->Ltable[i + j * Dw] * 255);
Dimg[3 * i + 1 + j * 3 * Dw] += (unsigned char)(Data->Ltable[i + j * Dw] * 255);
Dimg[3 * i + 2 + j * 3 * Dw] += (unsigned char)(Data->Ltable[i + j * Dw] * 255);
Dimg[3 * i + 0 + j * 3 * Dw] += (unsigned char)(Data->Rtable[i + j * Dw] * 255);
Dimg[3 * i + 1 + j * 3 * Dw] += (unsigned char)(Data->Rtable[i + j * Dw] * 255);
Dimg[3 * i + 2 + j * 3 * Dw] += (unsigned char)(Data->Rtable[i + j * Dw] * 255);
前视系数表可视化的结果
后视系数表可视化的结果
左视系数表可视化的结果
右视系数表可视化的结果
各个视图的和系数表想成后的结果如下所示
前视图像和系数表相乘后的结果
后视图像和系数表相乘后的结果
左视图像和系数表相乘后的结果
右视图像和系数表相乘后的结果
融合拼接后的效果
获取四个摄像头的图像数据(本测试使用的是opencv读取图像的方式实现的)
CvCapture* C_img_F = cvCreateFileCapture("G:\\CSDN\\AVM\\Video\\Front.avi");
CvCapture* C_img_B = cvCreateFileCapture("G:\\CSDN\\AVM\\Video\\Back.avi");
CvCapture* C_img_L = cvCreateFileCapture("G:\\CSDN\\AVM\\Video\\Left.avi");
CvCapture* C_img_R = cvCreateFileCapture("G:\\CSDN\\AVM\\Video\\Right.avi");
img_F = cvQueryFrame(C_img_F)
img_B = cvQueryFrame(C_img_B);
img_L = cvQueryFrame(C_img_L);
img_R = cvQueryFrame(C_img_R);
算法实现函数
js_getAVM_TOP(&AVMData, img_AVM->imageData, img_F->imageData, img_B->imageData, img_L->imageData, img_R->imageData, img_F->width, img_F->height, img_AVM->width, img_AVM->height, img_AVM->nChannels);
输出图像的拼接函数
cvSetImageROI(img_AVM_all, cvRect(0, 0, 1280, 720));
cvCopy(img_F, img_AVM_all);
cvResetImageROI(img_AVM_all);
cvSetImageROI(img_AVM_all, cvRect(1280, 0, 1280, 720));
cvCopy(img_B, img_AVM_all);
cvResetImageROI(img_AVM_all);
cvSetImageROI(img_AVM_all, cvRect(0, 720, 1280, 720));
cvCopy(img_L, img_AVM_all);
cvResetImageROI(img_AVM_all);
cvSetImageROI(img_AVM_all, cvRect(1280, 720, 1280, 720));
cvCopy(img_R, img_AVM_all);
cvResetImageROI(img_AVM_all);
cvSetImageROI(img_AVM_all, cvRect(1280*2, 0, 1080, 1440));
cvCopy(img_AVM, img_AVM_all);
cvResetImageROI(img_AVM_all);
算法的图片的测试代码
// TODO: 在此添加控件通知处理程序代码
IplImage* img_AVM = cvCreateImage(cvSize(1080, 1920), 8, 3);
IplImage* img_AVM_resize = cvCreateImage(cvSize(404, 720), 8, 3);
IplImage* img_F = cvLoadImage("Front.png");
IplImage* img_B = cvLoadImage("Back.png");
IplImage* img_L = cvLoadImage("Left.png");
IplImage* img_R = cvLoadImage("Right.png");
IplImage* det_TOP_F = cvCreateImage(cvSize(img_F->width, img_F->height), img_F->depth, img_F->nChannels);
IplImage* det_TOP_B = cvCreateImage(cvSize(img_B->width, img_B->height), img_B->depth, img_B->nChannels);
IplImage* det_TOP_L = cvCreateImage(cvSize(img_L->width, img_L->height), img_L->depth, img_L->nChannels);
IplImage* det_TOP_R = cvCreateImage(cvSize(img_L->width, img_L->height), img_L->depth, img_L->nChannels);
js_AVM_obj AVMData;
js_init_avm(&AVMData, img_AVM->width, img_AVM->height);
js_getAVM_TOP(&AVMData,img_AVM->imageData, img_F->imageData, img_B->imageData, img_L->imageData, img_R->imageData, img_F->width, img_F->height, img_AVM->width, img_AVM->height, img_AVM->nChannels);
cvWaitKey(0);
算法视频测试代码
// TODO: 在此添加控件通知处理程序代码
IplImage* img_AVM_all = cvCreateImage(cvSize(1280*2+1080, 1440), 8, 3);
IplImage* img_AVM = cvCreateImage(cvSize(1080, 1440), 8, 3);
IplImage* img_AVM_resize = cvCreateImage(cvSize(1200, 480), 8, 3);
IplImage* det_TOP_F = cvCreateImage(cvSize(1280, 720), 8, 3);
IplImage* det_TOP_B = cvCreateImage(cvSize(1280, 720), 8, 3);
IplImage* det_TOP_L = cvCreateImage(cvSize(1280, 720), 8, 3);
IplImage* det_TOP_R = cvCreateImage(cvSize(1280, 720), 8, 3);
CvVideoWriter* writer = cvCreateVideoWriter("G:\\CSDN\\AVM\\Video\\AVM_Result.avi", CV_FOURCC('X', 'V', 'I', 'D'), 25, cvSize(1280 * 2 + 1080, 1440));
cvNamedWindow("视频播放", CV_WINDOW_AUTOSIZE);
CvCapture* C_img_F = cvCreateFileCapture("G:\\CSDN\\AVM\\Video\\Front.avi");
CvCapture* C_img_B = cvCreateFileCapture("G:\\CSDN\\AVM\\Video\\Back.avi");
CvCapture* C_img_L = cvCreateFileCapture("G:\\CSDN\\AVM\\Video\\Left.avi");
CvCapture* C_img_R = cvCreateFileCapture("G:\\CSDN\\AVM\\Video\\Right.avi");
IplImage* img_F, *img_B, *img_L, *img_R;
js_AVM_obj AVMData;
js_init_avm(&AVMData, img_AVM->width, img_AVM->height);
while (img_F = cvQueryFrame(C_img_F))
{
img_B = cvQueryFrame(C_img_B);
img_L = cvQueryFrame(C_img_L);
img_R = cvQueryFrame(C_img_R);
js_getAVM_TOP(&AVMData, img_AVM->imageData, img_F->imageData, img_B->imageData, img_L->imageData, img_R->imageData, img_F->width, img_F->height, img_AVM->width, img_AVM->height, img_AVM->nChannels);
cvSetImageROI(img_AVM_all, cvRect(0, 0, 1280, 720));
cvCopy(img_F, img_AVM_all);
cvResetImageROI(img_AVM_all);
cvSetImageROI(img_AVM_all, cvRect(1280, 0, 1280, 720));
cvCopy(img_B, img_AVM_all);
cvResetImageROI(img_AVM_all);
cvSetImageROI(img_AVM_all, cvRect(0, 720, 1280, 720));
cvCopy(img_L, img_AVM_all);
cvResetImageROI(img_AVM_all);
cvSetImageROI(img_AVM_all, cvRect(1280, 720, 1280, 720));
cvCopy(img_R, img_AVM_all);
cvResetImageROI(img_AVM_all);
cvSetImageROI(img_AVM_all, cvRect(1280*2, 0, 1080, 1440));
cvCopy(img_AVM, img_AVM_all);
cvResetImageROI(img_AVM_all);
cvWriteFrame(writer, img_AVM_all);
cvResize(img_AVM_all, img_AVM_resize);
cvShowImage("视频播放", img_AVM_resize);
char c = cvWaitKey(1);
if (c == 27)break;
}
cvReleaseVideoWriter(&writer);
cvReleaseCapture(&C_img_F);
cvReleaseCapture(&C_img_B);
cvReleaseCapture(&C_img_L);
cvReleaseCapture(&C_img_R);
cvDestroyWindow("视频播放");
输出的测试视频
https://www.bilibili.com/video/BV1ab4y1N7pM/