Reputation: 2176
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.
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:
Here is zip with test frames: https://dl.dropboxusercontent.com/u/47015140/testFrames.rar
Upvotes: 14
Views: 2841
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.
Upvotes: 4
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.
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
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