opencv--相关系数法影像匹配(数字摄影测量)

来源:互联网 发布:淘宝智能仓库 编辑:程序博客网 时间:2024/04/29 08:18

一、程序内容

1.以灰度的形式读入两副核线影像。

2.读入左影像提取的特征点。

3.沿核线在右影像上计算每个候选匹配点的相关系数值。

4.取极值点以及NCC大于阈值的点作为同名点。

5.输出同名点到文件中,将同名点画到影像上,并用直线连接同名点。

二、设计思路

1.同名点结构体:

struct MatchPt2i//同名点结构体

{

Point2i lpt;//左核线影像上的点

Point2i rpt;//右核线影像上的点

};

2.CFeatureMatch类设计

私有数据成员:左核线影像,右核线影像,模板窗口大小(默认11),相关系数的阈值,同名点的个数,保存同名点的结构体数组。

成员函数:计算相关系数,给结果影像分配内存,影像匹配主函数。

3.影像匹配算法流程

(1)以灰度的形式读入两张核线影像,同时以彩色的形式读入核线影像(用于显示彩色结果)。

(2)对左核线影像进行Moravec特征提取。

(3)以提取到的特征点为中心开辟11X11的模板窗口。

(4)在右影像的搜索区域内,以每一像素位置为中心,形成与模板窗口同样大小的搜索窗口,计算两个窗口的相关系数。

搜索区域的确定:在核线影像中,同名点所在的同名核线的y坐标相同;x坐标在“视差±30”的范围内搜索。

(5)将相关系数取得最大值并且大于阈值的点作为匹配到的同名点。

(6)将同名点保存在一个结构体数组中,比你高将结果输出到“match_pointtxt”文件中,第一行为点数,第二行开始为同名点坐标 x1 y1 x2 y2

(7)将两张彩色图像合并为一张影像,并将同名点用直线连起来。

三、注意事项

1.    在搜索匹配点时要注意的问题:

左影像的模板窗口中心的行号要从“5(窗口宽度的一半)”开始,到“影像的行数-5”结束,列号要从“530(视差大小加搜索范围)”开始,到“影像的行数-5”结束。

右影像的匹配窗口中心的行号和左影像保持一致,列号的搜索范围为“500(视差)±30”。

2.    显示结果为彩色的解决方法:

在以灰度的形式读入影像的同时,以彩色的形式再读入一张用于显示结果。

四、主要代码

//FeatureMatch.h:头文件#pragma once#include "opencv2/highgui/highgui.hpp"#include "opencv2/core/core.hpp"#include "Moravec.h"using namespace cv;struct MatchPt2i//同名点结构体{Point2i lpt;//左核线影像上的点Point2i rpt;//右核线影像上的点};class CFeatureMatch{public:CFeatureMatch(void);~CFeatureMatch(void);private:Mat LeftImgEpi;  //左核线影像Mat RightImgEpi; //右核线影像int windowsize;  //模板窗口的大小double Threshold;//相关系数的阈值int num;         //匹配同名点个数MatchPt2i *Mpt2i;//同名点结构体数组private:double NCCScore(int lr,int lc,int rr,int rc);//计算相关系数void showresult(const Mat LeftImgColor,const Mat RightImgColor,Mat &ResultImg);//给结果影像分配内存public:void FeatureMatchMain(Mat LeftImg,Mat RightImg,Mat LeftImgColor,Mat RightImgColor);//影像匹配主函数};
//FeatureMatch.cpp:实现文件#include "StdAfx.h"#include "FeatureMatch.h"#include "math.h"#include "Moravec.h"CFeatureMatch::CFeatureMatch(void){windowsize=11;Threshold=0.7;Mpt2i=NULL;num=0;}CFeatureMatch::~CFeatureMatch(void){}void CFeatureMatch::showresult(const Mat LeftImgColor,const Mat RightImgColor,Mat &ResultImg){ResultImg.create(2*LeftImgColor.rows,LeftImgColor.cols,LeftImgColor.type());for (int i=0;i<LeftImgColor.rows;i++){for (int j=0;j<LeftImgColor.cols;j++){ResultImg.at<Vec3b>(i,j)=LeftImgColor.at<Vec3b>(i,j);}}for (int i=0;i<RightImgColor.rows;i++){for (int j=0;j<RightImgColor.cols;j++){ResultImg.at<Vec3b>(i+LeftImgColor.rows,j)=RightImgColor.at<Vec3b>(i,j);}}}double CFeatureMatch::NCCScore(int lr,int lc,int rr,int rc){double gLeftAverage=0;//左影像窗口灰度平均值double gRightAverage=0;//右影像窗口灰度平均值int halfsize=windowsize/2;for (int i=-halfsize;i<windowsize-halfsize;i++){for (int j=-halfsize;j<windowsize-halfsize;j++){gLeftAverage+=LeftImgEpi.at<uchar>(lr+i,lc+j);gRightAverage+=RightImgEpi.at<uchar>(rr+i,rc+j);}}gLeftAverage/=windowsize*windowsize;gRightAverage/=windowsize*windowsize;double a=0;double b=0;double c=0;for (int i=-halfsize;i<windowsize-halfsize;i++){for (int j=-halfsize;j<windowsize-halfsize;j++){double left_av=LeftImgEpi.at<uchar>(lr+i,lc+j)-gLeftAverage;double right_av=RightImgEpi.at<uchar>(rr+i,rc+j)-gRightAverage;a+=left_av*right_av;b+=left_av*left_av;c+=right_av*right_av;}}return a/sqrt(b*c);//返回相关系数的大小}void CFeatureMatch::FeatureMatchMain(Mat LeftImg,Mat RightImg,Mat LeftImgColor,Mat RightImgColor){LeftImgEpi=LeftImg;RightImgEpi=RightImg;Mat Result;showresult(LeftImgColor,RightImgColor,Result);//将两张彩色影像和合并1个Mat Interest;//兴趣矩阵CMoravec CM;int FeatureNum;//特征点个数CM.Moravec(LeftImgEpi,LeftImgColor,Interest,FeatureNum);//Moravec特征提取Mpt2i=new struct MatchPt2i[FeatureNum];//给同名点结构体数组分配内存空间int halfsize=windowsize/2;//搜索匹配点for (int i=halfsize;i<LeftImgEpi.rows-halfsize;i++){for (int j=530;j<LeftImgEpi.cols-halfsize;j++){if (Interest.at<int>(i,j)!=0)//特征点作为模板中心{double maxscore=0;for (int c=j-530;c<j-470;c++){double score=NCCScore(i,j,i,c);//计算相关系数if (score>maxscore){maxscore=score;//计算相关系数的最大值}} for (int c=j-530;c<j-470;c++){double score=NCCScore(i,j,i,c);if ((score==maxscore)&&(score>Threshold)){//用直线连接同名点line(Result,Point(j,i),Point(c,i+RightImgEpi.rows),cvScalar(0,0,255));//将匹配结果存入数组Mpt2i[num].lpt=Point(j,i);Mpt2i[num].rpt=Point(c,i);num+=1;}}}}}imwrite("result.jpg",Result);//将匹配结果写入文件FILE *fp=fopen("match_point.txt","w");if (fp == NULL){return;}fprintf(fp,"%1i\n",num);for (int i=0;i<num;i++){fprintf(fp,"%04d %04d %04d %04d\n",Mpt2i[i].lpt.x,Mpt2i[i].lpt.y,Mpt2i[i].rpt.x,Mpt2i[i].rpt.y);}fclose(fp);}
// ZQL_0107150120_3Dlg.h : 头文件//#pragma once#include "opencv2/highgui/highgui.hpp"#include "opencv2/core/core.hpp"using namespace cv;// CZQL_0107150120_3Dlg 对话框class CZQL_0107150120_3Dlg : public CDialogEx{public:Mat m_leftimg;            //左影像灰度矩阵Mat m_rightimg;           //右影像灰度矩阵Mat m_leftimgcolor;       //左影像彩色Mat m_rightimgcolor;      //右影像彩色CString strFileNameLeft;  //左影像文件路径CString strFileNameRight; //右影像文件路径bool bReadLeft;           //判断是否读入左影像bool bReadRight;          //判断是否读入右影像afx_msg void OnBnClickedBtnOpenimgleft(); //打开左影像afx_msg void OnBnClickedBtnOpenimgright();//打开右影像afx_msg void OnBnClickedCancel();         //退出对话框afx_msg void OnBnClickedBtnNccmatch();    //影像匹配};
// ZQL_0107150120_3Dlg.cpp : 实现文件//#include "stdafx.h"#include "ZQL_0107150120_3.h"#include "ZQL_0107150120_3Dlg.h"#include "afxdialogex.h"#include "FeatureMatch.h"#ifdef _DEBUG#define new DEBUG_NEW#endif// CZQL_0107150120_3Dlg 对话框CZQL_0107150120_3Dlg::CZQL_0107150120_3Dlg(CWnd* pParent /*=NULL*/): CDialogEx(CZQL_0107150120_3Dlg::IDD, pParent), strFileNameLeft(_T("")), strFileNameRight(_T("")), bReadLeft(FALSE), bReadRight(FALSE){m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);}void CZQL_0107150120_3Dlg::OnBnClickedBtnOpenimgleft(){// TODO: 在此添加控件通知处理程序代码UpdateData(TRUE);CFileDialog FileDlg(TRUE,"*.jpg;*.bmp","*.jpg;*.bmp",OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,"影像文件()");if (FileDlg.DoModal()!=IDOK){return;}strFileNameLeft=FileDlg.GetPathName();bReadLeft=TRUE;         //标记已经读入影像UpdateData(FALSE);  //将影像名字显示到对话框中m_leftimg=imread(strFileNameLeft.GetBuffer(),CV_LOAD_IMAGE_GRAYSCALE);//打开影像m_leftimgcolor=imread(strFileNameLeft.GetBuffer(),CV_LOAD_IMAGE_COLOR);//打开影像//imshow(_T("左影像"),m_leftimg); //图像显示cvWaitKey();  }void CZQL_0107150120_3Dlg::OnBnClickedBtnOpenimgright(){// TODO: 在此添加控件通知处理程序代码UpdateData(TRUE);CFileDialog FileDlg(TRUE,"*.jpg;*.bmp","*.jpg;*.bmp",OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,"影像文件()");if (FileDlg.DoModal()!=IDOK){return;}strFileNameRight=FileDlg.GetPathName();bReadRight=TRUE;         //标记已经读入影像UpdateData(FALSE);  //将影像名字显示到对话框中m_rightimg=imread(strFileNameRight.GetBuffer(),CV_LOAD_IMAGE_GRAYSCALE);//打开影像m_rightimgcolor=imread(strFileNameRight.GetBuffer(),CV_LOAD_IMAGE_COLOR);//打开影像//imshow(_T("右影像"),m_rightimg); //图像显示cvWaitKey();  }void CZQL_0107150120_3Dlg::OnBnClickedCancel(){// TODO: 在此添加控件通知处理程序代码CDialogEx::OnCancel();}void CZQL_0107150120_3Dlg::OnBnClickedBtnNccmatch(){// TODO: 在此添加控件通知处理程序代码if (bReadLeft==FALSE){MessageBox(_T("请读入左影像"));return;}if (bReadRight==FALSE){MessageBox(_T("请读入右影像"));return;} CFeatureMatch CFM;CFM.FeatureMatchMain(m_leftimg,m_rightimg,m_leftimgcolor,m_rightimgcolor);}

、运行结果