C++ OpenCV实战之标记点检测的实现

 更新时间:2022年03月22日 15:36:08   作者:光电的一只菜鸡  
这篇文章主要介绍了如何利用C++ OpenCV实现关键点的检测,文中的示例代码讲解详细,对我们学习OpenCV有一定帮助,感兴趣的小伙伴可以了解一下

在实际应用中,能够直接利用霍夫圆检测这些理想方法的应用场景是非常少的,更多的是利用拟合的办法去寻找圆形。

大致思路如下,首先先选择要处理的ROI部分,记录下该图的左上点在原图的坐标,如果原图过大,要先进行等比例缩放;然后利用自适应阈值和Canny边缘提取进行处理,再进行闭运算与轮廓检测,计算点集面积,通过筛选面积阈值去除杂点,最后进行轮廓检测,拟合椭圆,效果如下:

1.导入原图:

2.截取ROI

3.进行自适应阈值化与Canny边缘提取

4.进行闭运算,然后轮廓检测,然后计算点集面积,通过面积阈值去除杂点

5.再次进行轮廓检测,拟合椭圆

代码如下:

#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include <opencv2\core\core.hpp>
#include <iostream>

#define scale 2//图像缩放因子
#define cannythreshold 80

typedef struct _ROIStruct
{
	cv::Point2d ROIPoint;
	cv::Mat ROIImage;
}ROIStruct;

ROIStruct getROI(cv::Mat src,bool flag = false)
{
	ROIStruct ROI_Struct;
	cv::Rect2d ROIrect = selectROI(src);
	ROI_Struct.ROIPoint = ROIrect.tl();//获取ROI区域左上角的点
	ROI_Struct.ROIImage = src(ROIrect);

	if (flag == true)
	{
		cv::imshow("ROI", ROI_Struct.ROIImage);
	}

	return ROI_Struct;
}
int main()
{
	cv::Mat srcImage = cv::imread("7.jpg");//读取待处理的图片
	cv::resize(srcImage, srcImage, cv::Size(srcImage.cols / scale, srcImage.rows / scale));//图像缩放,否则原来图像会在ROI时显示不下
	
	ROIStruct ROI = getROI(srcImage);//选择ROI区域
	
	cv::Mat DetectImage, thresholdImage;
	ROI.ROIImage.copyTo(DetectImage);
	cv::imshow("ROI", DetectImage);
	cv::cvtColor(DetectImage, thresholdImage, CV_RGB2GRAY);
	cv::adaptiveThreshold(thresholdImage, thresholdImage, 255, CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY,11,35);//自适应阈值
	cv::Canny(thresholdImage, thresholdImage, cannythreshold, cannythreshold * 3, 3);
	
	cv::imshow("thresholdImage", thresholdImage);
	
	std::vector<std::vector<cv::Point>> contours1;
	std::vector<cv::Vec4i> hierarchy1;
	cv::Mat element = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(3, 3));
	cv::morphologyEx(thresholdImage, thresholdImage, cv::MORPH_CLOSE, element,cv::Point(-1,-1),2);
	cv::Mat findImage = cv::Mat::zeros(thresholdImage.size(), CV_8UC3);

	cv::findContours(thresholdImage, contours1, hierarchy1,CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE);

	for (int i = 0; i <contours1.size();i++)
	{
		double area = cv::contourArea(contours1[i]);
		//std::cout << i << "点集区域面积:" << area << std::endl;
		
		if (area < 120)
		{
			continue;
		}

		else
		{
			drawContours(findImage, contours1, i, cv::Scalar(255, 255, 255), -1, 8, cv::Mat(), 0, cv::Point());
		}

	}

	cv::imshow("drawing", findImage);

	cv::Mat CircleImage(findImage.size(),CV_8UC1);
	findImage.copyTo(CircleImage);
	cv::cvtColor(CircleImage, CircleImage, CV_RGB2GRAY);
	
	std::vector<std::vector<cv::Point>> contours2;
	std::vector<cv::Vec4i> hierarchy2;

	cv::Mat resultImage(CircleImage.size(), CV_8UC3);
	cv::findContours(CircleImage, contours2, hierarchy2, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE);
	std::vector<cv::Point> points1, points2;
	
	cv::Mat compareImage;
	DetectImage.copyTo(compareImage);

	for (int j = 0; j <contours2.size();j++)
	{
		cv::RotatedRect box = cv::fitEllipse(contours2[j]);
		points1.push_back(box.center);
		ellipse(resultImage, box, cv::Scalar(0, 0, 255), 1, CV_AA);
		ellipse(compareImage, box, cv::Scalar(0, 0, 255), 1, CV_AA);
	}
	
	for (int i = 0; i < points1.size(); i++)
	{
		cv::Point ans;
		ans.x = ROI.ROIPoint.x + points1[i].x;
		ans.x = ans.x*scale;
		ans.y = ROI.ROIPoint.y + points1[i].y;
		ans.y = ans.y*scale;
		points2.push_back(ans);
	}

	std::cout << points1 << std::endl;
	std::cout << ROI.ROIPoint << std::endl;
	std::cout << points2 << std::endl;

	cv::imshow("resultImage", resultImage);
	cv::imshow("compareImage", compareImage);
	cv::waitKey(0);
	return 0;
}

到此这篇关于C++ OpenCV实战之标记点检测的实现的文章就介绍到这了,更多相关C++ OpenCV标记点检测内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • c++ 深入理解归并排序的用法

    c++ 深入理解归并排序的用法

    归并排序是典型分治思想的代表——首先把原问题分解为两个或多个子问题,然后求解子问题的解,最后使用子问题的解来构造出原问题的解
    2022-03-03
  • C语言怎么获得进程的PE文件信息

    C语言怎么获得进程的PE文件信息

    这篇文章主要介绍了C语言怎么获得进程的PE文件信息的相关代码,需要的朋友可以参考下
    2016-01-01
  • C++ Qt利用GPU加速计算的示例详解

    C++ Qt利用GPU加速计算的示例详解

    这篇文章主要为大家详细介绍了在 C++ 和 Qt 中如何利用GPU加速计算,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-03-03
  • C++ LeetCode0547题解省份数量图的连通分量

    C++ LeetCode0547题解省份数量图的连通分量

    这篇文章主要为大家介绍了C++ LeetCode0547题解省份数量图的连通分量示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • 浅谈c++的编译和运行

    浅谈c++的编译和运行

    下面小编就为大家带来一篇浅谈c++的编译和运行。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-05-05
  • C语言系统日期和时间实例详解

    C语言系统日期和时间实例详解

    我们在写C语言程序的时候,有的时候会用到读取本机的时间和日期,下面这篇文章主要给大家介绍了关于C语言系统日期和时间的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2022-06-06
  • C语言实现的排列组合问题的通用算法、解决方法

    C语言实现的排列组合问题的通用算法、解决方法

    这篇文章主要介绍了C语言实现的排列组合问题的通用算法、解决方法,本文使用C语言实现在程序中解决这个问题,需要的朋友可以参考下
    2014-08-08
  • C++如何实现字符串的部分复制

    C++如何实现字符串的部分复制

    这篇文章主要介绍了C++如何实现字符串的部分复制问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-08-08
  • 关于在C程序中处理UTF-8文本的方法详解

    关于在C程序中处理UTF-8文本的方法详解

    这篇文章主要给大家介绍了关于在C程序中处理UTF-8文本的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起看看吧。
    2017-11-11
  • C语言中队列的结构和函数接口的使用示例

    C语言中队列的结构和函数接口的使用示例

    队列只允许一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO的性质;队列可用数组和链表 的方法实现,使用链表的结构实现更优一些,因为如果使用数组节,出队列时删去首元素需要将整个数组前移,效率比较低
    2023-02-02

最新评论