从图像中找出小缺陷
find small defects from the image
我有一张图像,每个角包含四个圆圈,其中一个圆圈中存在缺陷,请问如何识别它。我有很多带有大大小小的缺陷的图像。
我正在调整图像大小,因为图像大小 1920*1080
到 960*540
。
我试过对图像进行标准化,然后应用阈值和精巧的边缘,但我不知道如何识别或识别图像。
我正在使用 OpenCV C++,我是初学者,所以我不知道要应用哪种算法。
我的图片是:你可以清楚地看到缺陷出现在左上角的圆圈中,其他圆圈都没有缺陷。
精明后我的形象是这样的:
到目前为止,我已经尝试了以下代码:
//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);
为什么要采用调整大小和模糊等过程?
我认为他们的工作方向是掩盖缺陷。
切出四个区域中的每一个并对其进行logPolar(),我认为将帮助您找到缺陷。
这是使用 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();
社区机器人说“不清楚”,所以我试着把这个故事写成代码。
结果,这段代码的结果看起来很差。
需要考虑检测部分。
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;
}
准确定位圆心(找到孔的轮廓很容易);
展开图像以拉直圆环;
在小 windows 上使用模板匹配来检测与干净部分的偏差。或者,只是图像差异。
备注:
拉直360°以上,确保模板处处试穿;
要获得模板,一个好的方法是将展开图像上的所有轮廓平均,然后重复它以获得方形图像。
我有一张图像,每个角包含四个圆圈,其中一个圆圈中存在缺陷,请问如何识别它。我有很多带有大大小小的缺陷的图像。
我正在调整图像大小,因为图像大小 1920*1080
到 960*540
。
我试过对图像进行标准化,然后应用阈值和精巧的边缘,但我不知道如何识别或识别图像。
我正在使用 OpenCV C++,我是初学者,所以我不知道要应用哪种算法。
我的图片是:你可以清楚地看到缺陷出现在左上角的圆圈中,其他圆圈都没有缺陷。
精明后我的形象是这样的:
到目前为止,我已经尝试了以下代码:
//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);
为什么要采用调整大小和模糊等过程? 我认为他们的工作方向是掩盖缺陷。
切出四个区域中的每一个并对其进行logPolar(),我认为将帮助您找到缺陷。
这是使用 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();
社区机器人说“不清楚”,所以我试着把这个故事写成代码。 结果,这段代码的结果看起来很差。 需要考虑检测部分。
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;
}
准确定位圆心(找到孔的轮廓很容易);
展开图像以拉直圆环;
在小 windows 上使用模板匹配来检测与干净部分的偏差。或者,只是图像差异。
备注:
拉直360°以上,确保模板处处试穿;
要获得模板,一个好的方法是将展开图像上的所有轮廓平均,然后重复它以获得方形图像。