低对比度图像分割

14

我在低对比度图像分割方面遇到了问题。任务是找出表面缺陷。它们是可见的(缺陷总是暗区域),但是图像的对比度非常低。下面是两个样例。

1 2

我尝试了增强对比度,然后进行二值化:

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

拉伸对比度实现的位置:

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

但是这种方法失败了。有许多虚假检测,并且并没有检测到所有缺陷:3

这里是包含测试帧的压缩文件:https://dl.dropboxusercontent.com/u/47015140/testFrames.rar


1
当您基于图像内容进行对比度拉伸时,会丢失选择有用阈值所必需的上下文。 - Mark Ransom
2
如果您知道缺陷总是很暗,您可以调整亮度而不改变对比度,以使明亮的区域保持一致。您可以使用最大值来实现这一点,但是使用90th百分位数或类似方法则较不容易受到噪声的影响。 - Mark Ransom
2
简单的加减法。 - Mark Ransom
2
你尝试过其他对比度增强技术吗?伽马校正呢?直方图均衡化呢? - rayryeng
对比度拉伸没有任何用处:当传输函数是单调的时候,二值化具有完全相同的效果。(x > a 当且仅当 f(x) > f(a))。 - user1196549
显示剩余4条评论
3个回答

9
尝试使用聚类方法(如kmeans)按灰度级对图像进行聚类。下面我直接在图像上使用kmeans而没有进行任何灰度级转换(使用3个聚类给出了更好的结果)。您应该能够通过使用注释中概述的方法对预处理图像进行聚类来改进结果。
聚类形状可能会因kmeans的随机性而略有变化。
现在,如果您获取聚类图像的连通组件并计算这些区域的平均灰度级,则缺陷的平均值应低于其他区域的平均值。
我在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))

目前为止最佳答案。我会等待悬赏结束并接受最佳答案。 - krzych

4

如您在评论中所说,您可以采用反向方式调节亮度并提高对比度。

此外,锐化滤镜 对于您的情况也非常有用。您可以在 OpenCV 中进行此操作


4
我建议你尝试使用带有大窗口的adaptiveThreshold函数。
#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);
    }
}

所有结果在这里 (http://www.datafilehost.com/d/99e3d86c)。您可能还想看一下实现了许多自动阈值算法的ImageJ。我认为您需要的是考虑局部图像信息的东西。

输入图像描述 输入图像描述


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接