Morevec算子特征提取 opencv C++ CSU

承接实验一

实验配置 C++ vs2017 opencv

实验2 Morevec算子特征提取

一、实验目的

  • 编写Morevec算子特征提取程序,掌握特征提取方法,用标准图像进行测试

二、实验内容与要求

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

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

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

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

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

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

三、设计与实现

3.1类的设计

在这里插入图片描述

3.2代码及其属性

在这里插入图片描述

按钮IDCADPTION对应函数
IDOK打开并显示灰度图像OnBnClickedOk()
IDC_read2二值化图像OnBnClickedread2()
IDC_read3Guass滤波/opencv的Guass滤波图像OnBnClickedread3()
IDC_read5Moravec算子OnBnClickedread5()
IDC_read4帮助OnBnClickedread4()
IDCANCEL取消

3.3主要代码

这里仅展示涉及到Moravec算子相关功能的代码。

3.3.1文件 < zrxCFeatureVector.h >
#pragma once
/***************************************************************************
类:zrxCFeatureVector
作用:Moraavec算子类 外接函数:Moravec()
Welcome to my Github and my CSDN blog , more information will be available about the project!
Github:https://github.com/Yiqingde
CSDN Blog:https://me.csdn.net/weixin_42348202
历史:**日期**         **理由**            **签名**
	  2019年9月26日        创建              ***
/**************************************************************************/
#include <opencv2/opencv.hpp>
#include <vector>
#include <string>
using namespace cv;
using namespace std;
class zrxCFeatureVector
{
private:
	CString strOut;//存储输出txt中内容
	void find(float a[], int m, float &max, float &min);//最大最小值
	float Moravec_core(Mat m_srcimg, int Moravecsize, int i, int j);//Moravec_core滑动窗口
	void Moravec_core2(Mat &m_srcimgrgb,int Moravecsize2, Mat &Morvec, vector<Point3i> &f);//Moravec_core2局部抑制函数
public:
	zrxCFeatureVector();
	~zrxCFeatureVector();
	void Reporttxt(CString temp);//输出至txt函数
	void Moravec(Mat m_srcimg, Mat &m_srcimgrgb, int Moravecsize, int Moravecsize2, Mat &Morvec);//Moravec主要函数,调用上面的两个函数
};
3.3.2文件 < zrxCFeatureVector.cpp >
#include "stdafx.h"
#include "zrxCFeatureVector.h"


zrxCFeatureVector::zrxCFeatureVector()
{
}


zrxCFeatureVector::~zrxCFeatureVector()
{
}

/***************************************************************************
函数:Reporttxt()
作用:输出结果至txt,用到该类中变量strOut
参数:无
返回值:无
历史:**日期**         **理由**            **签名**
	  2019年9月26日        创建              ***
/**************************************************************************/
void zrxCFeatureVector::Reporttxt(CString runtime)

{
	if (strOut == _T("")) { AfxMessageBox(_T("请先输入数据!")); }
	else {
		CFileDialog dlg(false, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, _T("Txt Files(*.txt)|*.txt|All Files(*.*)|*.*|"), AfxGetMainWnd());
		CString strPath;
		if (dlg.DoModal() == IDCANCEL) return;
		else
		{
			strPath = dlg.GetPathName();

			if (strPath.Find(_T(".txt")) < 0)
			{
				if (strPath.Find(_T(".dat")) < 0)
				{
					strPath += _T(".txt");//默认储存为txt模式
				}
			}
		}
		TRY
		{
			CString cs;
			CStdioFile file(strPath, CFile::shareExclusive | CFile::modeWrite | CFile::modeCreate);
			setlocale(LC_CTYPE, ("chs")); //设置中文输出
			file.WriteString(runtime);
			file.WriteString(strOut);
			file.Close();
			CString temp;
			temp.Format(_T("%s%s"),_T("点位信息已导出至"),strPath);
			AfxMessageBox(temp);
		}
			CATCH_ALL(e)
		{
			e->ReportError();
			return;
		}
		END_CATCH_ALL
	}
}

/***************************************************************************
函数:find()
作用:寻找数组的最大值 最小值
参数:float a[]  数组
      int m 数组前m个元素
	  float &max 最大值
	  float &min 最小值
返回值:无
历史:**日期**         **理由**            **签名**
	  2019年9月26日        创建              ***
/**************************************************************************/
void zrxCFeatureVector::find(float a[], int m, float &max, float &min)
{
	min = a[0];
	max = a[0];
	for (int i = 0; i < m; i++)
	{
		if (a[i] > max)
		{
			max = a[i];
			continue;
		}
		else if (a[i] < min)
		{
			min = a[i];
			continue;
		}
	}
}


/***************************************************************************
函数:Moravec_core()
作用:滑动窗口 求"*"状最小值
参数:Mat m_srcimg 原始图像
	  int Moravecsize 窗口大小
	  int i_x 像素(x,y)中的x
	  int j_y 像素(x,y)中的y
返回值:最小值
历史:**日期**         **理由**            **签名**
	  2019年9月26日        创建              ***
/**************************************************************************/
float zrxCFeatureVector::Moravec_core(Mat m_srcimg, int Moravecsize, int i_x, int j_y)
{
	int halfsize = (Moravecsize) / 2;//定义小半个窗口大小
	float temp4[4];//创立四个方向的数组来进行"*"型的平方和
	//数组初始化
	for (int i = 0; i < 4; i++)
	{
		temp4[i] = 0;
	}
	//累加*求平方和
	for (int i = 0; i < Moravecsize; i++)
	{
		float l = m_srcimg.at<uchar>(i_x - halfsize + i, j_y);//    | x方向 即北南
		temp4[0] += pow(m_srcimg.at<uchar>(i_x - halfsize + i, j_y) - m_srcimg.at<uchar>(i_x - halfsize + i + 1, j_y), 2);//    | x方向 即北南
		temp4[1] += pow(m_srcimg.at<uchar>(i_x, j_y - halfsize + i) - m_srcimg.at<uchar>(i_x, j_y - halfsize + i + 1), 2);//    - y方向
		temp4[2] += pow(m_srcimg.at<uchar>(i_x - halfsize + i, j_y - halfsize + i) - m_srcimg.at<uchar>(i_x - halfsize + i + 1, j_y - halfsize + i + 1), 2);//   \ 方向
		temp4[3] += pow(m_srcimg.at<uchar>(i_x - halfsize + i, j_y + halfsize - i) - m_srcimg.at<uchar>(i_x - halfsize + i + 1, j_y + halfsize - i - 1), 2);//   / 方向
	}
	float min, max;//定义两个极大值 极小值
	find(temp4, 4, max, min);//给极小值赋值
	return min;//返回极小值
}


/***************************************************************************
函数:Moravec_core2()
作用:局部抑制 并开始画图
参数:Mat m_srcimgrgb 原始彩色图像
	  int Moravecsize2 局部抑制窗口大小
	  Mat &Morvec 经之前Moravec窗口操作后并经过阈值后的图像
	  vector<Point3i> &f 用来存储展点
返回值:无
历史:**日期**         **理由**            **签名**
	  2019年9月26日        创建              ***
/**************************************************************************/
void zrxCFeatureVector::Moravec_core2( Mat &m_srcimgrgb,int Moravecsize2, Mat &Morvec, vector<Point3i> &f)
{
	int halfMoravecsize2 = Moravecsize2 / 2;//定义小半个窗口大小
	//四层循环作用:针对窗口除了边框的每一个点来确保以它为中心,只要存在有一个值不小于它的值 即给它做一个标记0 用来排除小于极大值的值
	for (int i = halfMoravecsize2; i < Morvec.rows - halfMoravecsize2 - 1; i++)
	{
		for (int j = halfMoravecsize2; j < Morvec.cols - halfMoravecsize2 - 1; j++)
		{
			//int tag = 0;
			float temp1 = Morvec.at<float>(i, j);
			for (int m = 0; m < Moravecsize2; m++)
			{

				for (int n = 0; n < Moravecsize2; n++)
				{
					float temp2 = Morvec.at<float>(i - halfMoravecsize2 + m, j - halfMoravecsize2 + n);
					if (temp1 < temp2)
					{
						Morvec.at<float>(i, j) = 0;
						//Morvec.at<float>(i - halfMoravecsize2 + m, j - halfMoravecsize2 + n) = -1;
						n = Moravecsize2;
						m = Moravecsize2;
					}

				}
				//if (tag = 1) { break; }
			}
		}
	}
	//开始进行存储至 vector<Point3i> &f 中
	for (int i = halfMoravecsize2; i < Morvec.rows - halfMoravecsize2 - 1; i++)
	{
		for (int j = halfMoravecsize2; j < Morvec.cols - halfMoravecsize2 - 1; j++)
		{

			if (Morvec.at<float>(i, j) > 0)
			{
				Point3i temp;
				temp.x = i;
				temp.y = j;
				temp.z = Morvec.at<float>(i, j);
				f.push_back(temp);
			}
		}
	}
	
	//开始删除同意一窗口值一样的重复点,尽管出现概率较小,但较大的图像往往某些窗口中会存在好几个数值相等的极大值
	for (int i = 0; i < f.size() - 1; i++)
	{
		for (int j = i + 1; j < f.size(); j++)
		{
			if ((f.at(i).z == f.at(j).z))
			{
				if (abs(f.at(i).x - f.at(j).x) < Moravecsize2 || abs(f.at(i).y - f.at(j).y) < Moravecsize2)
				{
					f.erase(f.begin() + j);
					i = 0;
					break;
				}
			}
		}
	}
	/*
	//*********************冒泡排序
	for (int i = 0; i < f.size()-1; i++) {
		int tem = 0;
		// 内层for循环控制相邻的两个元素进行比较
		for (int j = i + 1; j < f.size(); j++) {
			if (f.at(i).z < f.at(j).z) {
				tem = f.at(j).z;
				f.at(j).z = f.at(i).z;
				f.at(i).z = tem;
			}
		}
	}
	*/
	/*********************以下注释的D部分 本来是为了修改显示的值 如果大于50 只显示前50个最大值,须于冒泡排序结合使用,但是效果不太好
	*/
	CString temp;
	temp.Format(_T("%s%d%s\n%s\n"),_T("*************************一共提取出:"),f.size(),_T("个点*************************"),_T("X坐标,Y坐标,Morevec后的值"));
	strOut += temp;
	
	//*D int tag2 = (f.size() > 50) ? 50 : f.size();
	for (size_t i = 0; i < f.size(); i++)
	{
		circle(m_srcimgrgb, Point(int(f.at(i).y), int(f.at(i).x)), 5, Scalar(0, 0, 255),1.67);
		temp.Format(_T("%d,%d,%d\n"), int(f.at(i).x), int(f.at(i).y), int(f.at(i).z));
		strOut += temp;
	}
}


/***************************************************************************
函数:Moravec()
作用:Moeavec主函数 调用以上函数
参数:Mat m_srcimg 原始图像
      Mat m_srcimgrgb 原始彩色图像
	  int Moravecsize  * 型窗口大小
	  int Moravecsize2 局部抑制窗口大小
	  Mat &Morvec 经之前Moravec窗口操作后并经过阈值后的图像
返回值:无
历史:**日期**         **理由**            **签名**
	  2019926日        创建              ***
/**************************************************************************/
void zrxCFeatureVector::Moravec(Mat m_srcimg, Mat &m_srcimgrgb, int Moravecsize, int Moravecsize2,Mat &Morvec)
{
	//****************************存储点的信息 查bug用
	vector<Point3i> f;
	GaussianBlur(m_srcimg, m_srcimg, Size(5, 5), 0, 0);//使用opencv自带高斯滤波预处理
	Morvec.create(m_srcimg.rows, m_srcimg.cols, CV_32FC1);//开辟空间
	float sum = 0;
	for (int i = 5; i < m_srcimg.rows - 5; i++)
	{
		for (int j = 5; j < m_srcimg.cols - 5; j++)
		{
			float min = Moravec_core(m_srcimg, Moravecsize, i, j);
			Morvec.at<float>(i, j) = min;
			sum += min;
		}
	}
	//****************************对小于阈值的置为零
	float mean = sum / (Morvec.rows*Morvec.cols);
	//if (mean < 60) { mean = 300; }
	for (int i = 0; i < Morvec.rows; i++)
	{
		for (int j = 0; j < Morvec.cols; j++)
		{
			if (Morvec.at<float>(i, j) < mean)
			{
				Morvec.at<float>(i, j) = 0;
			}
		}
	}
	//****************************局部抑制并显示
	Moravec_core2(m_srcimgrgb, Moravecsize2, Morvec, f);
	Morvec.convertTo(Morvec, CV_8UC1);
	//Morvec2.convertTo(Morvec2, CV_8UC1);
}
3.3.3文件 < CBasic.h >
#pragma once
/***************************************************************************
类:CBasic
作用:封装图像操作函数,仅储存按钮操作功能 调用相应其他图片处理类来完成图片操作
Welcome to my Github and my CSDN blog , more information will be available about the project!
Github:https://github.com/Yiqingde
CSDN Blog:https://me.csdn.net/weixin_42348202
历史:**日期**         **理由**            **签名**
	  2019年9月26日        创建              ***
/**************************************************************************/
#include "time.h"
#include "zrxCImgPro.h"
#include "zrxCFeatureVector.h"
class CBasic
{
public:
	CBasic();
	~CBasic();
	Mat m_srcimg;//原始灰度图像
	Mat m_srcimgrgb;//RGB颜色的图像
	bool tag;//鲁棒性
	zrxCImgPro function1;//创建zrxCImgPro图像处理操作对象
	zrxCFeatureVector function2;//创建zrxCFeatureVector图像处理操作对象
public://********************************存储按钮功能函数
	void OpenImg();//实现按钮功能,打开图像
	void Button_binaryImg();//实现按钮功能,显示二值图像
	void Button_GaussImg();//实现按钮功能,包括显示自写与opencv的gauss图像,并显示运行时间
	void Button_Help(); //实现按钮功能,help
	void Button_Moravec();//Moravec按钮
};
3.3.4文件 < CBasic.cpp >
#include "stdafx.h"
#include "CBasic.h"


CBasic::CBasic()
{
	this->tag = 0;//鲁棒
}


CBasic::~CBasic()
{
}
/***************************************************************************
函数:OpenImg()
作用:实现按钮功能,打开图像并显示灰度图像,存储到 m_srcimg中; tag是标签、增加程序鲁棒性
参数:无
返回值:无
历史:**日期**         **理由**            **签名**
	  2019年9月20日        创建              ***
/**************************************************************************/
void CBasic::OpenImg()
{
	CFileDialog FileDlg(TRUE, "*.jpg;*.bmp", "*.jpg;*.bmp", OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, "影像文件()");
	if (FileDlg.DoModal() != IDOK)
	{
		return;
	}
	CString strImgName = FileDlg.GetPathName();
	//打开影像	
	m_srcimg = imread(strImgName.GetBuffer(), IMREAD_GRAYSCALE);//IMREAD_GRAYSCALE  以灰度形式打开
	m_srcimgrgb = imread(strImgName.GetBuffer(), IMREAD_COLOR);//IMREAD_COLOR  以灰度形式打开
	//resize(m_srcimg, m_srcimg, Size(m_srcimg.cols * 800 / m_srcimg.rows, 800), 0, 0, INTER_CUBIC);//自适应调整图像大小
	//resize(m_srcimgrgb, m_srcimgrgb, Size(m_srcimgrgb.cols * 800 / m_srcimgrgb.rows, 800), 0, 0, INTER_CUBIC);//自适应调整图像大小
	imshow("原始图像", m_srcimgrgb); //显示
	tag = 1;
}


/***************************************************************************
函数:Button_binaryImg()
作用:实现按钮功能,显示二值图像
参数:无
返回值:无
历史:**日期**         **理由**            **签名**
	  2019年9月20日        创建              ***
/**************************************************************************/
void CBasic::Button_binaryImg()
{
	if (tag == 0)
	{
		AfxMessageBox(_T("需首先打开影像才能进行操作!"));
		return;
	}
	//二值化操作
	Mat m_binary;
	function1.BinaryImage(m_srcimg, 100, m_binary);
	imshow("图像二值化结果", m_binary); //显示
	waitKey();
}


/***************************************************************************
函数:Button_GaussImg()
作用:实现按钮功能,包括显示自写与opencv的gauss图像,并显示运行时间
参数:无
返回值:无
历史:**日期**         **理由**            **签名**
	  2019年9月20日        创建              ***
/**************************************************************************/
void CBasic::Button_GaussImg()
{
	if (tag == 0)
	{
		AfxMessageBox(_T("需首先打开影像才能进行操作!"));
		return;
	}
	Mat distImg;
	clock_t start, finish;
	double totaltime;
	clock_t start1, finish1;
	double totaltime1;
	start = clock();
	function1.Gaussianfilter(m_srcimg, 5, 1.0, distImg);
	//namedWindow("ss", 1);
	imshow("高斯滤波结果", distImg); //显示
	finish = clock();
	totaltime = (double)(finish - start) / CLOCKS_PER_SEC;

	waitKey(100); //等待操作,将窗口关闭\回车\ESC等操作会运行以下的程序
	//opencv自带高斯滤波
	Mat dstImage;
	start1 = clock();
	GaussianBlur(m_srcimg, dstImage, Size(5, 5), 0, 0);
	//显示效果图
	imshow("opencv自带高斯滤波效果图", dstImage);
	finish1 = clock();
	totaltime1 = (double)(finish1 - start1) / CLOCKS_PER_SEC;

	waitKey(3000);
	CString runtime;
	runtime.Format("%s%f%s\r\n%s%f%s",
		_T("自写Gauss滤波运行时间:"),
		totaltime,
		_T("s"),
		_T("opencvGauss滤波运行时间:"),
		totaltime1,
		_T("s")
	);
	AfxMessageBox(runtime);

}

/***************************************************************************
函数:Button_Help()
作用:实现按钮功能,help
参数:无
返回值:无
历史:**日期**         **理由**            **签名**
	  2019年9月20日        创建              ***
/**************************************************************************/
void CBasic::Button_Help()
{
	CString help;
	help.Format("%s\r\n%s\r\n%s\r\n\r\n%s\r\n%s\r\n%s\r\n", _T("感谢您使用本程序!提示:"), _T("需首先打开影像才能进行操作!"), _T("自写Gauss滤波代码、Moravec运行较慢,请耐心等待!"),
		_T("Welcome to my Github and my CSDN blog , more information will be available about the project!"),
		_T("Github : https://github.com/Yiqingde"),
		_T("CSDN Blog : https://me.csdn.net/weixin_42348202"));
	AfxMessageBox(help);
}
/***************************************************************************
函数:Button_Moravec()
作用:实现按钮功能,Moravec
参数:无
返回值:无
历史:**日期**         **理由**            **签名**
	  2019年9月26日        创建              ***
/**************************************************************************/
void CBasic::Button_Moravec()
{
	if (tag == 0)
	{
		AfxMessageBox(_T("需首先打开影像才能进行操作!"));
		return;
	}
	Mat MoravecImg;
	clock_t start, finish;
	start = clock();
	function2.Moravec(m_srcimg, m_srcimgrgb, 5, 20,MoravecImg);//调用函数
	finish = clock();
	double totaltime = (double)(finish - start) / CLOCKS_PER_SEC;
	CString runtime;
	runtime.Format(_T("%s%4f%s\n"),_T("************************* Morevec算子运行时间:"), totaltime,_T("s *************************"));
	imshow("Moravec单独显示", MoravecImg); //显示
	waitKey();
	imshow("Moravec彩色显示", m_srcimgrgb); //显示
	function2.Reporttxt(runtime);//输出txt
}
3.3.5文件 < ZRX0107170110Dlg.cpp >(仅展示部分)
/***************************************************************************
类:ZRX0107170110Dlg
作用:按钮实现文件
历史:**日期**         **理由**            **签名**
	  2019年9月20日        创建              ***
/**************************************************************************/
CBasic t;//全局变量
/*************************************************
按钮:读取图像函数
*************************************************/
void CZRX0107170110Dlg::OnBnClickedOk()
{
	// TODO: 在此添加控件通知处理程序代码
	//CDialogEx::OnOK();
	t.OpenImg();
}


/*************************************************
按钮:进行二值化显示
*************************************************/
void CZRX0107170110Dlg::OnBnClickedread2()
{
	// TODO: 在此添加控件通知处理程序代码
	t.Button_binaryImg();
}


/*************************************************
按钮:进行自写gauss显示与opencv显示且比较时间
*************************************************/
void CZRX0107170110Dlg::OnBnClickedread3()
{
	// TODO: 在此添加控件通知处理程序代码
	t.Button_GaussImg();
}

/*************************************************
按钮:help
*************************************************/
void CZRX0107170110Dlg::OnBnClickedread4()
{
	// TODO: 在此添加控件通知处理程序代码
	t.Button_Help();
}

/*************************************************
按钮:Moravec按钮显示  
*************************************************/
void CZRX0107170110Dlg::OnBnClickedread5()
{
	// TODO: 在此添加控件通知处理程序代码
	t.Button_Moravec();
}

3.4运行结果

3.4.1界面

在这里插入图片描述

3.4.2 Moravec算子运算结果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

总结

实现Morevec算子的实现过程,遇到的主要问题是局部抑制。
采取的方法是四层循环:
① 针对窗口除了边框的每一个点来确保以它为中心,只要存在有一个值不小于它的值,即给它做一个标记0,进行下一个点。
② 排除窗口边框的点和边框内小于零的点,然后存储至 vector &f 中
③ 删除同一窗口值一样的重复点,尽管出现概率较小,但较大的图像往往某些窗口中会存在好几个数值相等的极大值
④ 尝试了冒泡排序,最后取vector中最大的50个值,但是效果不好,随注释。
亮点:类的设计较好,层次较分明、功能独立。
不足:拙于MFC控件功底,又让步于界面简洁,以至于阈值内定,MFC灵活性不强。另外循环多、运算速度比较慢。

代码虽多不要贪杯~

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值