opencv 识别圆环

方法思路

大概的流程就是:	先对图像去噪声
			 	识别出轮廓
			 	找出自己想要的轮廓(重点)

涉及到的opencv方法

1 cv::GaussianBlur() //彩色图像转化成灰度图,并且去噪
2 cv::threshold() //图像二值化,用法以后会根据我的经验详解一次
3 cv::findContours() //找图像轮廓
4 cv::fitEllipse() //椭圆拟合
其实用到的opencv的封装方法还有很多,在这解释也没有必要,主要用这四个就能实现了,简单又方便。

关键代码

void markDetect(cv::Mat image, std::vector<cv::Point2f> &marks){
cv::Mat smoothed_gray_gpu, fd_x, fd_y, fd_mag, fd_mag_8bit_abs, edge, smoothed_gray, edge_;
cv::GaussianBlur(image, smoothed_gray_gpu, cv::Size(3, 3), 0);//彩色图像转化成灰度图
// smoothed_gray = smoothed_gray_gpu.clone();
// cv::Sobel(smoothed_gray_gpu, fd_x, CV_32F, 1, 0, 1);//边缘检测
// cv::Sobel(smoothed_gray_gpu, fd_y, CV_32F, 0, 1, 1);
// cv::magnitude(fd_x, fd_y, fd_mag);//梯度幅值
// fd_mag.convertTo(fd_mag_8bit_abs, CV_8UC1, 1);
cv::threshold(smoothed_gray_gpu, edge, 127, 255, cv::THRESH_TOZERO);

std::vector<std::vector<cv::Point> > contours;
cv::cvtColor(edge, edge_, CV_BGR2GRAY);
cv::findContours(edge_, contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);
cv::drawContours(image, contours, -1, cv::Scalar::all(255));


bool is_mark;
float ellipseness, eccenty, radius;
cv::RotatedRect ellipse;
cc_ellipse_.clear();
//std::cout <<"contours.size()="<< contours.size() << std::endl;
for (size_t i=0; i<contours.size(); i++) {//遍历轮廓,找圆
	if (contours[i].size() < 5)
		continue;
	if(cv::contourArea(contours[i]) < min_contour_area_)
	{
		continue;
	}
	ellipseness = FitEllipse(contours[i], ellipse);//和圆的相似程度
	if (!InsideImage(image, ellipse.center)) continue;
	radius = EllipseRadius(ellipse);//半径
	eccenty = EllipseEccentricity(ellipse);//圆心

	is_mark = (ellipseness <= max_ellipseness_
			&& radius >= min_radius_
			&& eccenty <= max_eccentricity_
	/*&& data >= min_center_grayscale_*/);
    std::cout<<"ismark="<<is_mark<<std::endl;
	if (is_mark) {
		UpateConcentricEllipse(ellipse);//更新满足要求的椭圆list,同心圆
		// std::cout<<"eccenty="<<eccenty<<std::endl;
		cv::ellipse(image, ellipse, cv::Scalar(0,0,255));
	}
}
std::cout <<"cc_ellipse_.size()"<<cc_ellipse_.size() << std::endl;
for (size_t i=0; i<cc_ellipse_.size(); i++)
{
	if (RecognizeMark(cc_ellipse_[i])){
		marks.push_back(cv::Point2f(cc_ellipse_[i].center()));
		std::cout << "push elli"<<cc_ellipse_[i].center() << std::endl;
		cv::circle(image, cc_ellipse_[i].center(), 5, cv::Scalar(255,0,0));
		std::cout << cc_ellipse_[i].center() << std::endl;
	}
}
}

float FitEllipse(const std::vector<cv::Point> &contour, cv::RotatedRect &ellipse)
 {//返回的数值代表和圆的相似度
float dist = 0;
std::vector<cv::Point> contourEllipse;

ellipse = cv::fitEllipse(contour);

cv::Size axes(0.5*ellipse.size.width, 0.5*ellipse.size.height);
cv::ellipse2Poly(ellipse.center, axes, ellipse.angle, 0, 360, 1, contourEllipse);

for (size_t i=0; i<contour.size(); i+=3)
	dist += std::abs((float)cv::pointPolygonTest(contourEllipse, contour[i], true));

return dist/contour.size();
}
bool InsideImage(const cv::Mat &image, const cv::Point &pt) {//点是否在轮廓内
cv::Rect rect(0, 0, image.cols, image.rows);
return rect.contains(pt);
}

float EllipseRadius(const cv::RotatedRect &ellipse) 
{
return (ellipse.size.width + ellipse.size.height) * 0.5f;
}

float EllipseEccentricity(const cv::RotatedRect &ellipse)
 {
float a = std::max(ellipse.size.width, ellipse.size.height) * 0.5f;
float b = std::min(ellipse.size.width, ellipse.size.height) * 0.5f;
return sqrt(1 - (b*b)/(a*a));
}
void UpateConcentricEllipse(const cv::RotatedRect &ellipse) {
for(size_t i=0; i<cc_ellipse_.size(); i++) {
	if (cc_ellipse_[i].Concentric(ellipse.center, cc_ellipse_range_)) {
		std::cout<<"ellipse.center="<<ellipse.center<<std::endl;
		cc_ellipse_[i].Add(ellipse);
		return;
	}
}

cc_ellipse_.push_back(ConcentricEllipse());
cc_ellipse_.back().Add(ellipse);
}

bool RecognizeMark(const ConcentricEllipse &cc_ellipse) 
{//判断是不是满足要求的圆环,看大圆和小圆的大小有没有超出要求
const ConcentricEllipse::EllipseSet &ellipse_set = cc_ellipse.ellipse();

if (ellipse_set.size() < 2) return false;

ConcentricEllipse::CEllipseSetIterator itr = ellipse_set.begin();
float min_r = EllipseRadius(*itr);
itr = ellipse_set.end();
--itr;
float max_r = EllipseRadius(*itr);
float r_ratio = min_r / max_r;
if (r_ratio < mark_min_cc_r_ratio_ || r_ratio > mark_max_cc_r_ratio_) return false;

return true;
}

在这里解释以下,被注释掉的梯度滤波可以发现更多更全面的轮廓,但是我这里圆环的
轮廓明显,可以使用更粗糙的滤波方式,具体对比我这里就不展现了。

效果实现

输入图片
环状物
输出图片在这里插入图片描述

总结

按照一般的处理过程处理直到识别出图像轮廓都没有问题,主要是按照自己的需求筛选出我们想要的轮廓,这就
要我们找轮廓特征然后结合合理的方法来筛选了。现在提供的代码只是部分,而且比较乱,之后会抽空整理一份完整的出来。
  • 6
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
OpenCV中进行摄像头圆环识别可以使用Hough Circle Transform算法。首先,你需要获取摄像头的视频流,并对每一帧进行处理。然后,你可以使用阈值化技术来提取图像中的圆环。你可以使用cv2.threshold函数来进行简单的阈值化,或者使用cv2.adaptiveThreshold函数进行自适应阈值化。\[2\]接下来,你可以使用HoughCircles函数来检测图像中的圆环。这个函数会返回检测到的圆环的圆心坐标和半径。你可以根据需要调整函数的参数来适应不同的场景。\[2\]在处理图像之前,你可能还需要将图像从RGB颜色空间转换为HSV颜色空间。这可以通过使用cv2.cvtColor函数来实现。HSV颜色空间可以更好地处理颜色信息。\[3\]通过将图像转换为HSV颜色空间,你可以使用特定颜色的阈值来提取圆环。例如,如果你想提取绿色的圆环,你可以将绿色的RGB值转换为HSV值,并使用阈值化技术来提取该颜色范围内的圆环。\[3\]最后,你可以根据检测到的圆环的位置和半径来进行进一步的处理,例如标记圆环或计算圆环的数量等。希望这些信息对你有帮助! #### 引用[.reference_title] - *1* *2* *3* [OpenCV识别圆(复杂背景下的圆)](https://blog.csdn.net/Castlehe/article/details/108020465)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值