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

一、程序内容

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

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

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

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

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

二、设计思路

  • 同名点结构体:

    struct MatchPt2i//同名点结构体
    
    {
        Point2i lpt;//左核线影像上的点
    
        Point2i rpt;//右核线影像上的点
    
    };

     

  • CFeatureMatch类设计

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

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

  • 影像匹配算法流程

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

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

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

  4. 在右影像的搜索区域内,以每一像素位置为中心,形成与模板窗口同样大小的搜索窗口,计算两个窗口的相关系数。搜索区域的确定:在核线影像中,同名点所在的同名核线的y坐标相同;x坐标在“视差±30”的范围内搜索。

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

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

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

三、注意事项

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

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

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

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

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

四、主要代码

//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);
}

 

五、运行结果

 

  • 12
    点赞
  • 107
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
相关系数(Correlation Coefficient)是一种常用的影像匹配,在OpenCV中也能够实现。 首先,我们需要准备两个待匹配影像,分别称为源影像(source image)和目标影像(template image)。接下来,我们可以使用OpenCV中的相关系数数`cv.matchTemplate()`进行匹配数使用的语如下: ``` result = cv.matchTemplate(source, template, method) ``` 其中,`source`是源影像,`template`是目标影像,`method`是指定使用的匹配。 常见的匹配有以下几种: - `cv.TM_CCORR`:相关系数匹配 - `cv.TM_CCORR_NORMED`:相关系数归一化匹配 - `cv.TM_CCOEFF`:相关系数系数匹配 - `cv.TM_CCOEFF_NORMED`:相关系数系数归一化匹配 - `cv.TM_SQDIFF`:平方差匹配 - `cv.TM_SQDIFF_NORMED`:平方差归一化匹配 例如,如果我们要使用相关系数进行匹配,可以选择`cv.TM_CCORR`方: ``` result = cv.matchTemplate(source, template, cv.TM_CCORR) ``` 匹配结果`result`是一个单通道灰度影像,其中每个像素值表示了对应位置的匹配度得分。我们可以通过寻找最高得分的位置来确定最佳匹配位置: ``` min_val, max_val, min_loc, max_loc = cv.minMaxLoc(result) ``` 其中,`max_val`表示最高得分,`max_loc`表示最高得分位置。 最后,我们可以在原始影像上标记出最佳匹配位置: ``` cv.rectangle(source, max_loc, (max_loc[0] + w, max_loc[1] + h), (0, 0, 255), 2) ``` 其中,`w`和`h`分别是目标影像的宽度和高度,`(0, 0, 255)`是画矩形的颜色,`2`是矩形线条的粗细。 通过以上步骤,我们就能够使用OpenCV实现相关系数影像匹配

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值