【问题标题】:How to increase pixel intensity difference more in image processing?如何在图像处理中更多地增加像素强度差异?
【发布时间】:2014-03-28 18:28:21
【问题描述】:

我有一个如附图所示的图像。 有时,数字的黑色强度与其相邻像素相差不大,我无法提取这些数字(例如,设置阈值效率不高,因为黑色的强度由于反射或聚焦不佳而接近灰色的强度在图像捕获期间)。我喜欢让它在黑色和背景灰色之间有更大的区别,这样我就可以在没有太多噪音的情况下提取数字。我所做的是使用OpenCV 中的addWeighted 函数增加差异。 color 是原始 RGB 图像。这对我的处理有意义还是有更有效的方法?

Mat blur_img = new Mat(color.size(), color.type());
org.opencv.core.Size size = new Size(9,9);
Imgproc.GaussianBlur(color, blur_img, size, 2);
Mat sharpened = new Mat(color.size(), CvType.CV_32FC3);
Core.addWeighted(color, 1.5, blur_img, -0.5, 0, sharpened);

【问题讨论】:

  • 对我来说看起来不错。也可以考虑使用Laplacian Filter
  • 我感觉不是很靠谱,一些抓拍的图片效果不错。但对某些人来说,它并没有真正起作用。

标签: image opencv image-processing


【解决方案1】:

您需要进行局部阈值处理(bernsen、sauvola、local otsu 等),opencv 也恰好具有adaptiveThreshold 功能。这是一个例子。只需确保使用参数即可。

自适应阈值

伯恩森

代码

#include <opencv2/opencv.hpp>
using namespace cv;

Mat thresh_bernsen(Mat& gray,int ksize,int contrast_limit)
{
    Mat ret = Mat::zeros(gray.size(),gray.type());
    for(int i=0;i<gray.cols;i++ )
    {
        for(int j=0;j<gray.rows;j++ )
        {
            double mn=999,mx=0;
            int ti=0,tj=0;
            int tlx=i-ksize/2;
            int tly=j-ksize/2;
            int brx=i+ksize/2;
            int bry=j+ksize/2;
            if(tlx<0) tlx=0;
            if(tly<0) tly=0;
            if(brx>=gray.cols) brx=gray.cols-1;
            if(bry>=gray.rows) bry=gray.rows-1;

            minMaxIdx(gray(Rect(Point(tlx,tly),Point(brx,bry))),&mn,&mx,0,0);
            /* this does the above
            for(int ik=-ksize/2;ik<=ksize/2;ik++)
            {
                for(int jk=-ksize/2;jk<=ksize/2;jk++)
                {
                    ti=i+ik;
                    tj=j+jk;
                    if(ti>0 && ti<gray.cols && tj>0 && tj<gray.rows)
                    {
                        uchar pix = gray.at<uchar>(tj,ti);
                        if(pix<mn) mn=pix;
                        if(pix>mx) mx=pix;
                    }
                }
            }*/
            int median = 0.5 * (mn+mx);
            if(median<contrast_limit)
            {
                ret.at<uchar>(j,i)=0;
            }else
            {
                uchar pix = gray.at<uchar>(j,i);
                ret.at<uchar>(j,i) = pix>median?255:0;
            }
        }
    }
    return ret;
}
int main()
{
    Mat gray = imread("c:/data/number.jpg",0);
    gray=255-gray;
    Mat adaptthresh,bernsen;
    adaptiveThreshold(gray,adaptthresh,255,ADAPTIVE_THRESH_GAUSSIAN_C,THRESH_BINARY,41,1);
    bernsen=thresh_bernsen(gray,25,40);
    imshow("gray",gray);
    imshow("adaptthresh",adaptthresh);
    imshow("bernsen",bernsen);
    waitKey(0);
}

【讨论】:

  • bernsen 有更好的结果,但速度很慢,尤其是对于我的移动应用程序。
  • ya..实现需要一些加速:(。也许某处有一个霓虹灯实现......失败了,你可以试试 imagej。它实现了一堆本地阈值方法。也许其中一个对您来说足够快且足够好。您还可以尝试调整adaptivethreshold的参数,例如在adaptivethreshold之前增加图像的块大小或中值模糊。或者您可以在传递给bernsen之前缩小图像(需要减小ksize对于较小的图像)以使其更快。
【解决方案2】:

简单的阈值处理不考虑图像中的光照变化,自适应阈值处理不利用连接区域。

目前提取此类细分市场的领导者是 MSER。它遍历所有可能的阈值并找到连接的最稳定区域(跨越所有阈值)。不要重新发明自行车,使用经过验证的最佳功能和开源,例如 openCV MSER. 堆栈溢出还有更多 links

【讨论】:

  • 但是 OpenCV 中的 MSER 代码不是用于检测关键点吗?您是否还可以提供参考文章/代码来展示如何在这种情况下使用它来执行分割,因为您提供的那些是用于检测关键点而不是分割本身,并且如何进行修改并不明显。我认为看看这个会很有趣。谢谢。
  • 这用于检测像 CC(连接组件)这样的区域,但更稳定。按照上面的链接查找代码,这些是我能找到的最好的。 MSER 现在广泛用于文本检测。另请参见示例 src 的 c 文件夹中的 mser_sample.cpp。
  • mser 可能无法处理不均匀的照明...vlfeat 也有一个 mser 实现,我认为它们会给出不同的结果(vlfeat 似乎更好)..不妨尝试一下
【解决方案3】:

编辑:在 Vlad 的 cmets 之后,我在 OpenCV 的 3.0 开发分支上找到了以下链接:http://docs.opencv.org/trunk/modules/objdetect/doc/erfilter.html。 这似乎是使用 Vlad 提到的用于检测关键点的原始 MSER 算法的修改来检测文本的技术。似乎 OpenCV 可能很快就会有它。此技术的详细信息在上面链接中的 2 篇论文中进行了描述。谢谢弗拉德。

如果您在使用 Zaw 提到的算法对图像进行阈值处理之前使用非局部方法去噪,则可以减少一些噪声:

fastNlMeansDenoising(gray, gray, 3, 5, 15);

上面 Zaw 描述的自适应阈值(使用相同的参数):

Zaw 描述的伯恩森阈值(使用相同的参数):

调整阈值和去噪的参数可能会给您带来更好的结果。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-05-19
    • 1970-01-01
    • 1970-01-01
    • 2014-05-30
    • 2017-06-27
    • 2011-06-17
    • 2019-02-06
    • 1970-01-01
    相关资源
    最近更新 更多