I am having problem to detect scratch on these images. Actually, it is very easy to see by human eyes. However, when applying some algorithms, there are a lot of noise and I couldn't extract the scratch only.
Here are these images:
At present, I tried some kinds of filter (smoothing, average, median, Gaussian filter or Sobel edge detector) to erase noise and detect scratch but they don't help much. Could you suggest some idea? Some tools or algorithms that I should consider?
This is my implementation for the defect detection, its a very simple yet effective approach, i have implemented this code in MATLAB, but there is not any difficulty to port it on any language because its use basic image processing operations.
clc
clear all
close all
im1 = imresize(imread('scratch.jpg'),0.5);
gray = rgb2gray(im);
gSize = 15;
gray = imfilter(gray,fspecial('gaussian',[gSize,gSize],gSize/2),'replicate');
[~,~,mg,~] = ImageFeatures.Gradients(gray);
`mgBw = mg > 0.3*max(mg(:));
mgBw = imclose(mgBw,strel('disk',1));
mgBw = bwareaopen(mgBw,500);
mgBw = imclose(mgBw,strel('disk',2));
mgBw = imfill(mgBw,'holes');
Try Above procedure on your images hope it will work
Thank You
Values For Gaussian Mask are Given below i have just copied as it is, you can only use values 4 places after decimal and one more thing before convolution scale your image values between 0 and 1:
0.00253790859361804,0.00284879446220838,0.00314141610419987,0.00340305543986557,0.00362152753952273,0.00378611472031542,0.00388843599983945,0.00392315394879368,0.00388843599983945,0.00378611472031542,0.00362152753952273,0.00340305543986557,0.00314141610419987,0.00284879446220838,0.00253790859361804;
0.00284879446220838,0.00319776287779517,0.00352622975612324,0.00381991909245893,0.00406515334132644,0.00424990193722614,0.00436475725361032,0.00440372804277458,0.00436475725361032,0.00424990193722614,0.00406515334132644,0.00381991909245893,0.00352622975612324,0.00319776287779517,0.00284879446220838;
0.00314141610419987,0.00352622975612324,0.00388843599983945,0.00421229243210782,0.00448271658130972,0.00468644212981339,0.00481309512122034,0.00485606890058492,0.00481309512122034,0.00468644212981339,0.00448271658130972,0.00421229243210782,0.00388843599983945,0.00352622975612324,0.00314141610419987;
0.00340305543986557,0.00381991909245893,0.00421229243210782,0.00456312191696750,0.00485606890058492,0.00507676215263394,0.00521396370030743,0.00526051663974220,0.00521396370030743,0.00507676215263394,0.00485606890058492,0.00456312191696750,0.00421229243210782,0.00381991909245893,0.00340305543986557;
0.00362152753952273,0.00406515334132644,0.00448271658130972,0.00485606890058492,0.00516782273108746,0.00540268422664802,0.00554869395001131,0.00559823553262373,0.00554869395001131,0.00540268422664802,0.00516782273108746,0.00485606890058492,0.00448271658130972,0.00406515334132644,0.00362152753952273;
0.00378611472031542,0.00424990193722614,0.00468644212981339,0.00507676215263394,0.00540268422664802,0.00564821944786971,0.00580086485975791,0.00585265795345929,0.00580086485975791,0.00564821944786971,0.00540268422664802,0.00507676215263394,0.00468644212981339,0.00424990193722614,0.00378611472031542;
0.00388843599983945,0.00436475725361032,0.00481309512122034,0.00521396370030743,0.00554869395001131,0.00580086485975791,0.00595763557555571,0.00601082839853353,0.00595763557555571,0.00580086485975791,0.00554869395001131,0.00521396370030743,0.00481309512122034,0.00436475725361032,0.00388843599983945;
0.00392315394879368,0.00440372804277458,0.00485606890058492,0.00526051663974220,0.00559823553262373,0.00585265795345929,0.00601082839853353,0.00606449615428972,0.00601082839853353,0.00585265795345929,0.00559823553262373,0.00526051663974220,0.00485606890058492,0.00440372804277458,0.00392315394879368;
0.00388843599983945,0.00436475725361032,0.00481309512122034,0.00521396370030743,0.00554869395001131,0.00580086485975791,0.00595763557555571,0.00601082839853353,0.00595763557555571,0.00580086485975791,0.00554869395001131,0.00521396370030743,0.00481309512122034,0.00436475725361032,0.00388843599983945;
0.00378611472031542,0.00424990193722614,0.00468644212981339,0.00507676215263394,0.00540268422664802,0.00564821944786971,0.00580086485975791,0.00585265795345929,0.00580086485975791,0.00564821944786971,0.00540268422664802,0.00507676215263394,0.00468644212981339,0.00424990193722614,0.00378611472031542;
0.00362152753952273,0.00406515334132644,0.00448271658130972,0.00485606890058492,0.00516782273108746,0.00540268422664802,0.00554869395001131,0.00559823553262373,0.00554869395001131,0.00540268422664802,0.00516782273108746,0.00485606890058492,0.00448271658130972,0.00406515334132644,0.00362152753952273;
0.00340305543986557,0.00381991909245893,0.00421229243210782,0.00456312191696750,0.00485606890058492,0.00507676215263394,0.00521396370030743,0.00526051663974220,0.00521396370030743,0.00507676215263394,0.00485606890058492,0.00456312191696750,0.00421229243210782,0.00381991909245893,0.00340305543986557;
0.00314141610419987,0.00352622975612324,0.00388843599983945,0.00421229243210782,0.00448271658130972,0.00468644212981339,0.00481309512122034,0.00485606890058492,0.00481309512122034,0.00468644212981339,0.00448271658130972,0.00421229243210782,0.00388843599983945,0.00352622975612324,0.00314141610419987;
0.00284879446220838,0.00319776287779517,0.00352622975612324,0.00381991909245893,0.00406515334132644,0.00424990193722614,0.00436475725361032,0.00440372804277458,0.00436475725361032,0.00424990193722614,0.00406515334132644,0.00381991909245893,0.00352622975612324,0.00319776287779517,0.00284879446220838;
0.00253790859361804,0.00284879446220838,0.00314141610419987,0.00340305543986557,0.00362152753952273,0.00378611472031542,0.00388843599983945,0.00392315394879368,0.00388843599983945,0.00378611472031542,0.00362152753952273,0.00340305543986557,0.00314141610419987,0.00284879446220838,0.00253790859361804;
Sobel Mask:
1, 2, 1;
0, 0, 0;
-1,-2, 1;
and
1, 0,-1;
2, 0,-2;
1, 0,-1;
Sobel Gradient Magnitude Code(ImageFeatures.Gradient):
function [gx,gy,mag,phi] = Gradients(gray)
gray = double(gray);
horzmask = fspecial('sobel');
% vertmask = horzmask';
gx = imfilter(gray,horzmask,'replicate');
gy = imfilter(gray,horzmask','replicate');
phi = (atan2((gy),(gx)));
mag = mat2gray(sqrt(gx.^2+gy.^2));
end
I tried the following procedure for detection. The output looks moderate, but still I thought of sharing.
apply median blur with different window sizes, then take the absolute difference: I'm doing this to enhance the scratch marks and at the same time achieve illumination flattening. Shown below are the difference images obtained this way.
use Gaussian Mixture based background/foreground segmentation to segment the scratch marks in the difference image. Idea here is, we can extract m x n windows from this image and train. As the scratch marks don't occupy a large area in the difference image, we can think the learned background should approximate the region outside scratch marks. This method worked better for both difference images than applying a threshold to the difference image. This method did not work well when I fed the downsampled image directly. I think this is due to the nonuniform nature of the pixel color values in regions. So I used the illumination flattened difference image. Below are the segmented images. This procedure is slow as it checks every possible m x n window in the image.
use probabilistic Hough transform to detect lines in the segmented image. Using the line density in regions or using morphological filtering for lines, I think it's possible to arrive at a reasonable guess as to where the scratch marks are.
Here's the code
background segmentation code:
Mat threshold_mog(Mat& im, Size window)
{
BackgroundSubtractorMOG2 bgModel;
Mat fgMask;
Mat output = Mat::ones(im.rows, im.cols, CV_8U);
for (int r = 0; r < im.rows - window.height; r++)
{
for (int c = 0; c < im.cols - window.width; c++)
{
bgModel.operator()(im(Rect(c, r, window.width, window.height)), fgMask);
}
}
for (int r = 0; r < im.rows - window.height; r++)
{
for (int c = 0; c < im.cols - window.width; c++)
{
Mat region = im(Rect(c, r, window.width, window.height));
bgModel.operator()(region, fgMask, 0);
fgMask.copyTo(output(Rect(c, r, window.width, window.height)));
}
}
return output;
}
main:
Mat rgb = imread("scratch_2.png.jpg");
pyrDown(rgb, rgb);
Mat med, med2, dif, bw;
medianBlur(rgb, med, 3);
medianBlur(rgb, med2, 21);
absdiff(med2, med, dif);
bw = threshold_mog(dif, Size(15, 15));
Mat dst = bw.clone();
vector<Vec4i> lines;
HoughLinesP(dst, lines, 1, CV_PI/180, 8, 10, 20);
for( size_t i = 0; i < lines.size(); i++ )
{
Vec4i l = lines[i];
line(rgb, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0,0,255), 1, CV_AA);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With