krzych
krzych

Reputation: 2176

Low contrast image segmentation

I have problem with low contrast image segmentation. Task is to find surface defects. They are visible (defects are always dark areas) but the contrast of image is very low. Below two samples.

1 2

I have tried enhance contrast and then tresholding:

Mat tmp1 = imread("C:\\framesRoi\\311.bmp",0);
stretchContrast(tmp1);
threshold(tmp1,tmp1,75,255,THRESH_BINARY);

where stretch contrast impl:

int minValue = 255, maxValue = 0;
const int l = sourceImg.cols * sourceImg.rows * sourceImg.channels();
if(sourceImg.isContinuous())
{
    uchar* ptr = sourceImg.ptr<uchar>(0);
    for(int i = 0; i < l; ++i)
    {
        if(ptr[i] < minValue)
        {
            minValue = ptr[i];
        }
        if(ptr[i] > maxValue)
        {
            maxValue = ptr[i];
        }
    }
}
cout<<"min: "<<minValue<<";"<<"max value: "<<maxValue<<endl;

const int  magicThreshold = 10;
if(sourceImg.isContinuous())
{
    uchar* ptr = sourceImg.ptr<uchar>(0);
    for(int i = 0; i < l; ++i)
    {
        ptr[i] = 255 * (ptr[i]-minValue)/(maxValue - minValue);
    }
}

But this approach failed. There are many false detections and not all defects are detected: 3

Here is zip with test frames: https://dl.dropboxusercontent.com/u/47015140/testFrames.rar

Upvotes: 14

Views: 2841

Answers (3)

Zaw Lin
Zaw Lin

Reputation: 5708

I think you should try adaptiveThreshold function with a large window.

#include "opencv2/opencv.hpp"
using namespace cv;
int main(int argc,char** argv )
{

    Mat im = imread("c:/data/img1.png",0);
    cv::namedWindow("ctrl");
    int win=62;
    int th=2100;
    cv::createTrackbar( "win", "ctrl", &win, 500);
    cv::createTrackbar( "th", "ctrl", &th, 10000);
    while(true)
    {
        Mat thresh;
        medianBlur(im,thresh,15);//helps smooth out smaller noises, which you could also remove by size instead of this way
        adaptiveThreshold(thresh,thresh,255,ADAPTIVE_THRESH_MEAN_C,THRESH_BINARY,win*2+1,(    th/1000.));
        imshow("thresh",thresh);
        if(waitKey(1)==27)
            exit(0);
    }
}

all results here (http://www.datafilehost.com/d/99e3d86c) You might also want to take a look at imagej which implements a bunch of auto-threshold algorithms. I think what you need is something that takes local image information into account.

enter image description here enter image description here

Upvotes: 4

dhanushka
dhanushka

Reputation: 10682

Try clustering the image by gray level using a clustering method such as kmeans. Below I've used kmeans directly on the images without any gray level transformations (using 3 clusters gave me better results). You should be able to improve results by clustering a preprocessed image using methods outlined in the comments.

enter image description here enter image description here

Shape of the clusters may slightly vary due to the randomness of kmeans.

Now if you take connected components of the clustered image and calculate the average gray level of those regions, the defects should have a lower average than the other regions.

I did clustering part in Matlab.

im = imread('r2SOV.png');%Uy1Fq r2SOV
gr = im;
size = size(gr);

% perform closing using a 5x5 circular structuring element
sel = strel('disk', 2, 4);
mcl = imclose(gr, sel);
% cluster gray levels using kmeans: using 3 clusters
x = double(mcl(:));
idx = kmeans(x, 3);
cl = reshape(idx, size);

figure, imshow(label2rgb(cl))

Upvotes: 9

Alto
Alto

Reputation: 522

As people said in your comment, you can change the brightness in a negative way and push up the contrast.

Moreover, the sharpen filter is also very useful for your case. You can do this in OpenCV.

Upvotes: 4

Related Questions