使用OpenCV去除噪声并检测聚光灯中的圆形

huangapple go评论59阅读模式
英文:

Removing Noise and Detecting Circle in Spotlight Using OpenCV

问题

我一直在尝试使用OpenCV在聚光灯图像中检测圆圈,并且有各种我正在处理的图片,通常看起来像这四张图片之一:

使用OpenCV去除噪声并检测聚光灯中的圆形
使用OpenCV去除噪声并检测聚光灯中的圆形
使用OpenCV去除噪声并检测聚光灯中的圆形
使用OpenCV去除噪声并检测聚光灯中的圆形

经过一些图像处理(使用阈值、模糊化),我已经让图片看起来像这样:

使用OpenCV去除噪声并检测聚光灯中的圆形

然而,尝试使用HoughCircles函数,即使在玩弄了一段时间后似乎也无法正常工作。在使用HoughCircles时,我是不是忽略了什么,或者有没有比使用HoughCircles更好的方法来检测这些圆圈?

我的当前代码:

import cv2 as cv 
import numpy as np 

img = cv.imread('image.jpg', cv.IMREAD_GRAYSCALE)
img = cv.medianBlur(img,33)
assert img is not None, "file could not be read, check with os.path.exists()"
image = cv.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,
            cv.THRESH_BINARY,73,2)
blur = cv.blur(image,(5,5))
circles = cv.HoughCircles(blur,cv.HOUGH_GRADIENT,1,20,
                            param1=50,param2=30,minRadius=30)
circles = np.uint16(np.around(circles))
for i in circles[0,:]:
    # draw the outer circle
    cv.circle(circles,(i[0],i[1]),i[2],(0,255,0),2)
    # draw the center of the circle
    cv.circle(circles,(i[0],i[1]),2,(0,0,255),3)

cv.imshow('Objects Detected',blur)
cv.waitKey(0)
英文:

I have been trying to detect circles in spotlight images using OpenCV and have a variety of pictures I am working with, generally looking something like these 4 images:

使用OpenCV去除噪声并检测聚光灯中的圆形
使用OpenCV去除噪声并检测聚光灯中的圆形
使用OpenCV去除噪声并检测聚光灯中的圆形
使用OpenCV去除噪声并检测聚光灯中的圆形

Following some image processing (using a threshold, blurring) I have gotten the images to look something like this:
使用OpenCV去除噪声并检测聚光灯中的圆形

However, trying to use the HoughCircles function, even after playing around with it for a while seems to not work. Is there something that I am glossing over while using Hough Cicles, or is there a better way to detect the circles than using HoughCircles?

My current code:

import cv2 as cv 
import numpy as np 

img = cv.imread('image.jpg', cv.IMREAD_GRAYSCALE)
img = cv.medianBlur(img,33)
assert img is not None, "file could not be read, check with os.path.exists()"
image = cv.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,\
            cv.THRESH_BINARY,73,2)
blur = cv.blur(image,(5,5))
circles = cv.HoughCircles(blur,cv.HOUGH_GRADIENT,1,20,
                            param1=50,param2=30,minRadius=30)
circles = np.uint16(np.around(circles))
for i in circles[0,:]:
    # draw the outer circle
    cv.circle(circles,(i[0],i[1]),i[2],(0,255,0),2)
    # draw the center of the circle
    cv.circle(circles,(i[0],i[1]),2,(0,0,255),3)

cv.imshow('Objects Detected',blur)
cv.waitKey(0)

答案1

得分: 1

。结果的示例(注意:我使用了缩小尺寸的图像作为输入):

  • 阈值 = 167
  • 二值化结果以下图中的红色部分表示。

使用OpenCV去除噪声并检测聚光灯中的圆形

英文:

If you can't use fix threshold value, one of the simplest way is to try possible thresholds and choose the one that looks good.

In following sample code(C++), threshold value are tried in ascending order until the binalization result shape became "enoughly circle".

//Circle fitting (Simple Least Square)
void FitCircle( const std::vector<cv::Point> &Ps, cv::Point2f &C, float &r )
{
	cv::Mat A( (int)Ps.size(), 3, CV_32F );
	cv::Mat B( (int)Ps.size(), 1, CV_32F );
	for( int i=0; i<Ps.size(); ++i )
	{
		const auto &P = Ps[i];
		A.at<float>( i,0 ) = (float)P.x;
		A.at<float>( i,1 ) = (float)P.y;
		A.at<float>( i,2 ) = 1.0f;
		B.at<float>( i ) = (float)(P.x*P.x + P.y*P.y);
	}
	cv::Mat X;
	cv::solve( A,B, X, cv::DECOMP_SVD );
	C.x = X.at<float>(0) * 0.5f;
	C.y = X.at<float>(1) * 0.5f;
	r = sqrt( X.at<float>(2) + C.x*C.x + C.y*C.y );
}

int main()
{
	//Load image as gray-scale
	cv::Mat SrcImg = cv::imread( "SpotLight.png", cv::IMREAD_GRAYSCALE );
	if( SrcImg.empty() )return 0;
	cv::imshow( "Src", SrcImg );

	//Decide threshold value range [Min,Max) to try
	int Min=0, Max=255;
	{
		unsigned int Hist[256] = { 0 };
		for( int y=0; y<SrcImg.rows; ++y )
		{
			const unsigned char *p = SrcImg.ptr<unsigned char>(y);
			for( int x=0; x<SrcImg.cols; ++x, ++p )
			{	++Hist[ *p ];	}
		}
		{//Decide Min
			unsigned int Thresh = cvRound( SrcImg.rows * SrcImg.cols * 0.9 );
			unsigned int Sum = 0;
			while( Sum < Thresh ){	Sum += Hist[Min];	++Min;	}
		}
		//Decide Max
		while( Hist[Max]==0 ){	--Max;	}
	}
	
	//Try for each threshold
	for( int Thresh=Min; Thresh<Max-1; ++Thresh )
	{
		//Binalize
		cv::Mat Bin;
		cv::threshold( SrcImg, Bin, Thresh, 255, cv::THRESH_BINARY );

		//Fit circle to largest contour
		//to evaluate how close the binalization result shape is to a circle
		cv::Point2f Center;
		float Radius;
		double FittingErr = 0;
		{
			//Extract Largest Contour
			std::vector< std::vector<cv::Point> > Conts;
			cv::findContours( Bin, Conts, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE );
			if( Conts.empty() )continue;
			int iLargestCont = 0;
			double MaxArea = 0;
			for( int i=0; i<Conts.size(); ++i )
			{
				double Area = cv::contourArea( Conts[i] );
				if( Area >= MaxArea ){	MaxArea = Area;	iLargestCont = i;	}
			}
			//Fit circle to the Contour and evaluate the fitting result
			FitCircle( Conts[iLargestCont], Center, Radius );
			for( const auto &P : Conts[iLargestCont] )
			{
				double dx = (double)P.x - Center.x;
				double dy = (double)P.y - Center.y;

				double e = fabs( sqrt(dx*dx + dy*dy) - Radius );
				FittingErr += e;
			}
			FittingErr /= Conts[iLargestCont].size();
		}
		//Check if Contour shape is "enoughly circle"
		if( FittingErr <= 0.5 )
		{	//Show Result
			cv::Mat Show;
			std::cout << "Thresh = " << Thresh << std::endl;
			cv::cvtColor( SrcImg, Show, cv::COLOR_GRAY2BGR );
			Show.setTo( cv::Scalar(0,0,255), Bin );
			cv::imshow( "Result", Show );
			cv::waitKey();
			return 0;
		}
	}

	//
	std::cout << "(All try Failed)" << std::endl;
	return 0;
}

Result of this sample (Note : I used shrinked size image to input) :

  • Threshold value = 167
  • Binalized Result is represented as Red color part in below.

使用OpenCV去除噪声并检测聚光灯中的圆形

huangapple
  • 本文由 发表于 2023年5月28日 11:03:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/76349775.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定