英文:
Removing Noise and Detecting Circle in Spotlight Using 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:
Following some image processing (using a threshold, blurring) I have gotten the images to look something like this:
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
- 二值化结果以下图中的红色部分表示。
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论