Reputation: 644
I have an image which contains four circles in each corner and there is a defect present in one of the circles, so how to identify it. I have a lot of image with small and big defects.
I am resizing the image as the image is of size 1920*1080
to size 960*540
.
I have tried normalizing the image, then applying threshold and canny edge but I don't know how to identify or recognize the image.
I am working with OpenCV C++ and I am beginner so I don't know which algorithm to apply.
My image is :And you can clearly see that the defect is present in the top left circle and all other circles are without defects.
After canny my image looks like this:
Up till now I have tried the below code :
//resize image
Mat r_img;
resize(img, r_img, Size(img.cols / 2, img.rows / 2), 0, 0, INTER_LANCZOS4);
Mat gfilter;
cv::GaussianBlur(r_img, gfilter, Size(5, 5),2, 2);
//convert to grayscale
Mat gray_img;
cv::cvtColor(gfilter, gray_img, COLOR_BGR2GRAY);
double min, max;
cv::minMaxLoc(gray_img, &min, &max);
float sub = min;
float mult = 255.0f / (float)(max - sub);
cv::Mat normalized = gray_img - sub;
normalized = mult * normalized;
cv::imshow("normalized", normalized);
cv::Mat mask;
cv::threshold(normalized, mask, 127, 255, THRESH_BINARY)
Mat canny;
cv::Canny(normalized, canny, 50, 150, 3);
Upvotes: 1
Views: 285
Reputation: 1890
Why you employing the processes such as resizing and blurring? I think they work in the direction of obscuring defects.
Cut out each of the four areas and logPolar() them, will help you to find defects, I think.
This is simple sample using warpPolar().
//Circle Area Image.
// In this sample code, this image is created at here.
// In real, you must cut out the circle region from your source image.
cv::Mat TheSrcCircleImg = cv::Mat::zeros( 101, 101, CV_8UC3 );
cv::Point Center{ 50,50 }; //also, you must estimate this point.
{
//Draw some cielces
cv::circle( TheSrcCircleImg, Center, 48, cv::Scalar(8,96,16), -1 );
cv::circle( TheSrcCircleImg, Center, 35, cv::Scalar(0,128,0), -1 );
cv::circle( TheSrcCircleImg, Center, 22, cv::Scalar(255,32,0), 6 );
cv::circle( TheSrcCircleImg, Center, 29, cv::Scalar(100,100,100), 1 );
cv::circle( TheSrcCircleImg, Center, 10, cv::Scalar(0,0,0), -1 );
//Add "defects"
cv::line( TheSrcCircleImg, cv::Point(70,65), cv::Point(96,55), cv::Scalar(0,255,255), 2 );
cv::line( TheSrcCircleImg, cv::Point(45,32), cv::Point(30,30), cv::Scalar(0,255,255), 1 );
}
cv::imshow( "The Src", TheSrcCircleImg );
//I found that arguments of logPolar() is not explained in reference manual.
//So, I used werpPolar() intstead.
cv::Mat ResultImg;
cv::warpPolar( TheSrcCircleImg, ResultImg, cv::Size(50,360), Center, 50, cv::INTER_LINEAR+cv::WARP_POLAR_LINEAR );
cv::imshow( "Result", ResultImg );
cv::waitKey();
The Community Bot said "unclear", so I tried to write this story as code. As a result, result of this code seems poor. It will be necessary to consider the detection part.
std::vector< std::vector< cv::Point> > FindOutlines( const cv::Mat &SrcImg8U1C )
{
cv::Mat BinImg;
cv::threshold( SrcImg8U1C, BinImg, 16, 255, cv::THRESH_BINARY );
std::vector< std::vector< cv::Point> > Contours;
cv::findContours( BinImg, Contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE );
return Contours;
}
//Test Process for 1 Circle Region
void Proc( const cv::Mat &SrcImg8U1C, const std::vector<cv::Point> &Outline, const std::string &ShowWndName )
{
cv::RotatedRect FittingResult = cv::fitEllipse( Outline );
cv::Rect Region = cv::boundingRect( Outline );
FittingResult.center.x -= Region.x;
FittingResult.center.y -= Region.y;
cv::Mat RegionImg;
cv::Mat ShowImg;
{
cv::equalizeHist( SrcImg8U1C(Region), RegionImg );
cv::cvtColor( RegionImg, ShowImg, cv::COLOR_GRAY2BGR );
ShowImg *= 0.5;
cv::ellipse( ShowImg, FittingResult, cv::Scalar(0,0,255) );
cv::drawMarker( ShowImg, FittingResult.center, cv::Scalar(0,255,0), cv::MARKER_CROSS, 8 );
}
const double radius = (FittingResult.size.width + FittingResult.size.height) * 0.25;
cv::Mat LPImg;
cv::warpPolar( RegionImg, LPImg, cv::Size(cvRound(radius),180), FittingResult.center, radius, cv::INTER_LINEAR+cv::WARP_POLAR_LINEAR );
cv::Mat DetectionMask = cv::Mat::zeros( LPImg.size(), CV_8U );
{//Detection based on edge direction. (looks Poor)
cv::Mat SobelX, SobelY;
cv::Sobel( LPImg, SobelX, CV_32F, 1,0 );
cv::Sobel( LPImg, SobelY, CV_32F, 0,1 );
const float SqMagThresh = 200 * 200;
const float DetectionRateThresh = 0.5f;
for( int y=0; y<LPImg.rows; ++y )
{
const float *pSX = SobelX.ptr<float>(y);
const float *pSY = SobelY.ptr<float>(y);
unsigned char *pD = DetectionMask.ptr<unsigned char>(y);
for( int x=0; x<LPImg.cols; ++x, ++pSX,++pSY,++pD )
{
if( (*pSX * *pSX) + (*pSY * *pSY) < SqMagThresh )continue;
if( fabs(*pSY) >= fabs(*pSX)*DetectionRateThresh ){ *pD = 255; }
}
}
cv::Mat Morph;
cv::morphologyEx( DetectionMask, Morph, cv::MORPH_CLOSE, cv::Mat() );
cv::morphologyEx( Morph, Morph, cv::MORPH_OPEN, cv::Mat() );
cv::bitwise_and( Morph, DetectionMask, DetectionMask );
}
{//Draw Result : This inverse warp calculation is from Reference Manual.
const double Kangle = DetectionMask.rows / CV_2PI;
for( int y=0; y<DetectionMask.rows; ++y )
{
const double angleRad = y / Kangle;
const double Cos = cos(angleRad);
const double Sin = sin(angleRad);
const unsigned char *pD = DetectionMask.ptr<unsigned char>(y);
for( int x=0;x<DetectionMask.cols; ++x, ++pD )
{
if( !(*pD) )continue;
double Klin = DetectionMask.cols / radius;
double magnitude = x / Klin;
int x_reg = cvRound( FittingResult.center.x + magnitude*Cos );
int y_reg = cvRound( FittingResult.center.y + magnitude*Sin );
ShowImg.at<cv::Vec3b>(y_reg,x_reg) = cv::Vec3b(0,255,255);
}
}
}
cv::imshow( ShowWndName, ShowImg );
}
int main()
{
//The Image "ciecles.png" is copied from this Question.
cv::Mat SrcImg = cv::imread( "circles.png", cv::IMREAD_GRAYSCALE );
if( SrcImg.empty() )return 0;
std::vector< std::vector< cv::Point> > Outlines = FindOutlines( SrcImg );
for( size_t i=0; i<Outlines.size(); ++i ){ Proc( SrcImg, Outlines[i], std::string("Result")+char('0'+i) ); }
cv::waitKey();
return 0;
}
Upvotes: 4
Reputation:
locate the circles centers accurately (finding the outlines of the holes is easy);
unwind the images to straighten the rings;
use template matching on small windows to detect deviations from the clean part. Alternatively, just image differencing.
Remarks:
straighten on more than 360° to make sure that the template is tried everywhere;
to obtain the template, a good method can be to average all the profiles along the unwound image, then to repeat it to get a squarish image.
Upvotes: 0