Detecting scratch on image with much noise

I tried the following procedure for detection. The output looks moderate, but still I thought of sharing.

  • downsample the color image.
  • 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. sample difference image sample difference image 2

  • 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. segmented segmented 2

  • 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. hough lones hough lines 2

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);
}

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

  1. Read Both the Images and downsample them(for fast calculation) by factor of 2.

im1 = imresize(imread('scratch.jpg'),0.5);

Scratch 1 enter image description here

  1. Convert them into gray scale.

gray = rgb2gray(im);

GrayImage enter image description here

  1. Apply a Gaussian filter of size 15 X 15.

gSize = 15;

gray = imfilter(gray,fspecial('gaussian',[gSize,gSize],gSize/2),'replicate');

enter image description here enter image description here

  1. Findout Gradient Magnitude of the Images using Sobel mask.

[~,~,mg,~] = ImageFeatures.Gradients(gray);

enter image description here enter image description here

  1. Threshold Gradient magnitude with a threshold of 30 percentile of max value.

`mgBw = mg > 0.3*max(mg(:));

enter image description here enter image description here

  1. Apply morpholgical operation Closing of binary image by a disk mask of 3 X 3.

mgBw = imclose(mgBw,strel('disk',1));

enter image description here enter image description here

  1. Apply Particle Analyze(CCL).

mgBw = bwareaopen(mgBw,500);

enter image description here enter image description here

  1. Again Close Image for joining Lines together.

mgBw = imclose(mgBw,strel('disk',2));

enter image description here enter image description here

  1. Fill Holes in the image.

mgBw = imfill(mgBw,'holes');

enter image description here enter image description here

  1. Final Annotations:

enter image description here enter image description here

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