基于opencv的Morevec算子特征提取(数字摄影测量)

一、程序内容

1.以灰度的形式读入图像;

2.开辟和图像大小的矩阵,用于保存兴趣值;

3.计算每个像元的兴趣值;

4.用阈值对分割兴趣值,获取候选点,

5.对候选点抑制局部极值。

6.将特征提取结果输出到文本,并将特征点画在原始图像上。

二、设计思路

1.CMoravec类的设计

私有数据成员:兴趣值矩阵,兴趣值计算窗口大小(默认5X5),抑制局部非最大窗口大小(默认5X5),兴趣经验阈值(默认200)。

私有成员函数:将算法的每一步设计为一个函数:计算兴趣值矩阵,选择候选点,抑制局部极值,标记特征点。

共有成员函数:Moravec算法主函数(在主函数中进行影像的高斯滤波,并调用私有成员函数)。

三、主要代码

//Moravec.h:头文件
#pragma once
#include "opencv2\highgui\highgui.hpp"
using namespace cv;
 
class CMoravec
{
public:
   CMoravec(void);
   ~CMoravec(void);
private:
   Mat Interest;         //兴趣值矩阵
   int IVwindowsize;     //兴趣值计算窗口大小
   int NMSwindowsize;    //抑制局部非最大窗口大小
   int intvalueT;        //兴趣阈值
private:
   void InterestValue(const Mat srcimg);   //计算兴趣值
   void CandidatePoint();                  //选择候选点
   void FeaturePoint ();                   //抑制局部非最大
   void Mark (Mat &dstimg);                //标记特征点
public:
   void Moravec(const Mat srcimg,Mat &dstimg);// Moravec算法主函数
};
//Moravec.cpp: 实现文件
#include "StdAfx.h"
#include "Moravec.h"
#include "math.h"
#include "ZQLImgPro.h"
CMoravec::CMoravec(void)
{
   IVwindowsize=5;
   NMSwindowsize=5;
   intvalueT=200;
}
 
 
CMoravec::~CMoravec(void)
{
}
//计算兴趣值
void CMoravec::InterestValue(const Mat srcimg)
{
   Interest.create(srcimg.rows,srcimg.cols,CV_32S);
   int rows=srcimg.rows;
   int cols=srcimg.cols;
   for (int i=0;i<rows;i++)
   {
      for (int j=0;j<cols;j++)
      {
         Interest.at<int>(i,j)=0;
         //将兴趣值矩阵初始化为零矩阵
      }
   }
   int k=int(IVwindowsize/2);
   for (int r=k;r<rows-k;r++)
   {
      for (int c=k;c<cols-k;c++)
      {
         int v1=0;
         int v2=0;
         int v3=0;
         int v4=0;
         for (int i=-k;i<k;i++)
         {
            v1+=(srcimg.at<uchar>(r,c+i)-srcimg.at<uchar>(r,c+i+1))*
               (srcimg.at<uchar>(r,c+i)-srcimg.at<uchar>(r,c+i+1));
            v2+=(srcimg.at<uchar>(r+i,c+i)-srcimg.at<uchar>(r+i+1,c+i+1))*
               (srcimg.at<uchar>(r+i,c+i)-srcimg.at<uchar>(r+i+1,c+i+1));
            v3+=(srcimg.at<uchar>(r+i,c)-srcimg.at<uchar>(r+i+1,c))*
               (srcimg.at<uchar>(r+i,c)-srcimg.at<uchar>(r+i+1,c));
            v4+=(srcimg.at<uchar>(r-i,c+i)-srcimg.at<uchar>(r-i-1,c+i+1))*
               (srcimg.at<uchar>(r-i,c+i)-srcimg.at<uchar>(r-i-1,c+i+1));
         }
         Interest.at<int>(r,c)=min(min(min(v1,v2),v3),v4);
         //取v1,v2,v3,v4中的最小值作为兴趣值
      }
   }
}
//选择候选点
void CMoravec::CandidatePoint()
{
   for (int i=0;i<Interest.rows;i++)
   {
      for (int j=0;j<Interest.cols;j++)
      {
         //选择特征值大于经验阈值的点作为候选点
         if (Interest.at<int>(i,j)<=intvalueT)
            Interest.at<int>(i,j)=0;
      }
   }
}
//抑制局部非最大
void CMoravec::FeaturePoint()
{
   int halfw=NMSwindowsize/2;
   for (int i=halfw;i<Interest.rows-halfw;i++)
   {
      for (int j=halfw;j<Interest.cols-halfw;j++)
      {
         for (int m=-halfw;m<halfw+1;m++)
         {
            for (int n=-halfw;n<halfw+1;n++)
            {
               //抑制局部极值
               if (Interest.at<int>(i,j)<Interest.at<int>(i+m,j+n))
                  Interest.at<int>(i,j)=0;
            }
         }
      }
   }
}
//标记特征点
void CMoravec::Mark(Mat &dstimg)
{
   FILE *fp=fopen("result.txt","w");
   if (fp == NULL)
   {
      return;
   }
   fprintf(fp,"%s\t%s\n","像素位置","兴趣值");
   Point2f pt;
   for (int i=3;i<Interest.rows-3;i++)
   {
      for (int j=3;j<Interest.cols-3;j++)
      {
         if (Interest.at<int>(i,j)!=0)
         {
            circle(dstimg,Point(j,i),1,cvScalar(0,0,255),-1);
            //将特征点标记为实心点
            fprintf(fp,"(%1i,\t%1i)\t%1i\n",i,j,Interest.at<int>(i,j));
                //特征提取结果输出到文件
         }
      }
   }
   fclose(fp);
   //显示影像
   imshow(_T("结果影像"),dstimg);
   cvWaitKey(0);
}
//Moravec算法主函数
void CMoravec::Moravec(const Mat srcimg,Mat &dstimg)
{
   CZQLImgPro CIP(3,1.5);
   Mat Gauss;
   CIP.Gaussianfilter(srcimg,Gauss);// 高斯滤波
   InterestValue(Gauss);
   CandidatePoint();
   FeaturePoint();
   Mark(dstimg);
}
// ZQL_0107150120_2Dlg.h : 头文件
//
 
#pragma once
#include "opencv2\core\core.hpp"
#include "opencv2\highgui\highgui.hpp"
#include "Moravec.h"
using namespace cv;
using namespace std;
 
// CZQL_0107150120_2Dlg 对话框
class CZQL_0107150120_2Dlg : public CDialogEx
{
public:
   bool bRead;             //判断是否读取影像文件
   Mat m_srcimg;           //原始影像灰度矩阵
   Mat m_dstimg;           //结果影像矩阵
   CString str_srcimgfile; //原始影像路径
   CString str_dstimgfile; //结果影像路径
 
   afx_msg void OnBnClickedBtnMoravec();  //Moravec算法特征点提取
   afx_msg void OnBnClickedBtnOpen();     //打开影像
   afx_msg void OnBnClickedBtnSave();     //保存结果影像
   afx_msg void OnBnClickedCancel();      //退出对话框
};
// ZQL_0107150120_2Dlg.cpp : 实现文件
void CZQL_0107150120_2Dlg:: OnBnClickedBtnMoravec ()
{
   // TODO: 在此添加控件通知处理程序代码
   UpdateData(TRUE);
   if (bRead!=TRUE)
   {
      MessageBox(_T("请读入影像文件"));
      return;
   }
   CMoravec CM;
   CM.Moravec(m_srcimg,m_dstimg);
}
 
 
void CZQL_0107150120_2Dlg::OnBnClickedBtnOpen()
{
   // TODO: 在此添加控件通知处理程序代码
   UpdateData(TRUE);
   CFileDialog FileDlg(TRUE,"*.jpg;*.bmp","*.jpg;*.bmp",OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT," 影像文件()");
   if (FileDlg.DoModal()!=IDOK)
   {
      return;
   }
   str_srcimgfile=FileDlg.GetPathName();
   bRead=TRUE;         //标记已经读入影像
   UpdateData(FALSE);  //将影像名字显示到对话框中
   m_srcimg=imread(str_srcimgfile.GetBuffer(),CV_LOAD_IMAGE_GRAYSCALE); //打开影像
   m_dstimg=imread(str_srcimgfile.GetBuffer(),CV_LOAD_IMAGE_COLOR); //打开影像
   imshow(_T("原始影像"),m_srcimg); //图像显示
   cvWaitKey();  
   //等待鼠标响应
}
 
void CZQL_0107150120_2Dlg::OnBnClickedBtnSave()
{
   // TODO: 在此添加控件通知处理程序代码
   CFileDialog FileDlg(FALSE,"*.jpg;*.bmp","*.jpg;*.bmp",OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT," 影像文件()");
   if (FileDlg.DoModal()!=IDOK)
   {
      return;
   }
   str_dstimgfile=FileDlg.GetPathName();   //用于保存结果
   if (str_dstimgfile!="")
   {
      imwrite(str_dstimgfile.GetBuffer(),m_dstimg);// 将结果影像写入文件
   }
   UpdateData(FALSE);
   m_dstimg.release();
 
}
 
 
void CZQL_0107150120_2Dlg::OnBnClickedCancel()
{
   // TODO: 在此添加控件通知处理程序代码
   CDialogEx::OnCancel();
}

四、运行结果

对话框

阈值40

阈值200

阈值200


五、注意事项

 

1.Morevec算法会提取出影像中的噪声,在进行特征提取前,先进行高斯滤波处理,降低噪声,得到平滑的影像。

2.以灰度的形式读取原始影像的同时,再以彩色的形式读取一次影像,在该影像上进行标记,便可以显示彩色标记。

3.经过高斯平滑后的影像进行特征提取时,会在影像边缘出现特征点。进行高斯滤波时,在影像边缘填充了灰度值为0的像素,导致特征提取算法提取到了错误的特征点。

解决办法:设高斯滤波的窗口大小为windowsize,进行特征点标记时,循环从int(windowsize/2)+1开始,

到rows-(int(windowsize/2)+1)或cols-(int(windowsize/2)+1)结束。 

  • 3
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值