【问题标题】:image binarization using newer Algorithms in opencv在 opencv 中使用较新的算法进行图像二值化
【发布时间】:2015-10-20 06:06:38
【问题描述】:

我想对低质量的图像进行二值化,发现现有的解决方案或程序实现了全局和局部二值化技术,如 Sauvola 方法、NiBlack 方法等,并没有多大用处。

我确实找到了一些关于更好方法的好论文,比如论文中给出的方法: 1)http://www.ski.org/sites/default/files/publications/wacv11-display-reader.pdf#cite.adap-binar 2)https://www.jstage.jst.go.jp/article/elex/1/16/1_16_501/_pdf

但我之前没有在图像处理方面做过很多工作,所以我想知道如何继续实现它以及实现这些算法需要哪些知识

【问题讨论】:

  • 您应该首先以易于编码的方式实现它(以便有一个可比较的解决方案),然后再关注优化。从论文中你只需要知道如何计算子图像的均值和方差。
  • 但是提到的矩阵呢?我如何从源图像构建它?
  • 您只是对二值化 (2.1) 感兴趣吗?
  • 是的,但是二值化需要阈值处理,实习生需要 martix 来获取像素值或类似的东西吗?
  • 你的意思是图像和子图像?

标签: opencv image-processing adaptive-threshold


【解决方案1】:

我在大约 10 分钟内实现了第一篇论文的二值化(比处理第二张图像的时间短) - 不能保证它是正确的,最好自己看看公式:

int main()
{
    //cv::Mat input = cv::imread("../inputData/Lenna.png");
    cv::Mat input = cv::imread("../inputData/LongLineColor.jpg");

    cv::Mat gray;
    cv::cvtColor(input,gray,CV_BGR2GRAY);


    cv::Mat binaryImage = cv::Mat::zeros(gray.rows, gray.cols, CV_8UC1);

    // binarization:

    // TODO: adjust to your application:
    int smallWindowSize = 17; // suggested by the paper
    int bigWindowSize = 35; // suggested by the paper

    // TODO: adjust to your application
    double minTau =  10 ;

    // create roi relative to (0,0)
    cv::Rect roiTemplate1 = cv::Rect(-smallWindowSize/2,-smallWindowSize/2, smallWindowSize, smallWindowSize);
    cv::Rect roiTemplate2 = cv::Rect(-bigWindowSize/2,-bigWindowSize/2, bigWindowSize, bigWindowSize);

    cv::Rect imgROI = cv::Rect(0,0, gray.cols, gray.rows);

    for(int y=0; y<gray.rows; ++y)
    {
        std::cout << y << std::endl;
        for(int x=0; x<gray.cols; ++x)
        {
            double pixelThreshold = 255;

            // small roi
            cv::Rect cROIs = roiTemplate1 + cv::Point(x,y);
            // test whether ROI is inside the image. Reduce otherwise:
            cROIs = cROIs & imgROI;
            if(cROIs.width == 0 || cROIs.height == 0)
                continue;   // ignore this pixel

            // large roi
            cv::Rect cROIl =  roiTemplate2 + cv::Point(x,y);
            cROIl = cROIl & imgROI;
            if(cROIl.width == 0 || cROIl.height == 0)
                continue;   // ignore this pixel

            cv::Mat subSmall = gray(cROIs);
            cv::Mat subLarge = gray(cROIl);

            // evaluate subimages:
            // standard deviations
            double stdDevS =0;
            double stdDevL =0;
            // mean value
            double meanS =0;
            double minL =DBL_MAX;
            double meanL =0;

            // mean of small region
            for(int j=0; j<subSmall.rows; ++j)
                for(int i=0; i<subSmall.cols; ++i)
                {
                    meanS += subSmall.at<unsigned char>(j,i);
                }
            meanS = meanS/ (double)(subSmall.cols*subSmall.rows);


            // stddev of small region
            for(int j=0; j<subSmall.rows; ++j)
                for(int i=0; i<subSmall.cols; ++i)
                {
                    double diff = subSmall.at<unsigned char>(j,i) - meanS;
                    stdDevS += diff*diff;
                }
            stdDevS = sqrt(stdDevS/(double)(subSmall.cols*subSmall.rows));



            // mean and min of large region
            for(int j=0; j<subLarge.rows; ++j)
                for(int i=0; i<subLarge.cols; ++i)
                {
                    if(subLarge.at<unsigned char>(j,i)  < minL)
                    {
                        minL = subLarge.at<unsigned char>(j,i);
                        meanL += subLarge.at<unsigned char>(j,i);
                    }
                }
            meanL = meanL/ (double)(subLarge.cols*subLarge.rows);

            // stddef of large region
            for(int j=0; j<subLarge.rows; ++j)
                for(int i=0; i<subLarge.cols; ++i)
                {
                    double diff = subLarge.at<unsigned char>(j,i) - meanL;
                    stdDevL += diff*diff;
                }
            stdDevL = sqrt(stdDevL/(double)(subLarge.cols*subLarge.rows));

            // formula (2)
            double tau = ((meanS - minL) * (1-stdDevS/stdDevL))/2.0;
            // minimum
            if(tau < minTau) tau = minTau;

            // formula (1)
            double Threshold = meanS - tau;


            // for debugging:
            /*
            std::cout << "    meanS:" << meanS << std::endl;
            std::cout << "    std S:" << stdDevS << std::endl;
            std::cout << "    min L:" << minL << std::endl;
            std::cout << "    meanL:" << meanL << std::endl;
            std::cout << "    std L:" << stdDevL << std::endl;
            std::cout << "  threshold: " << Threshold << std::endl;
            */


            unsigned char pixelVal = gray.at<unsigned char>(y,x);
            if(pixelVal >= Threshold)
                binaryImage.at<unsigned char>(y,x) = 255;
            else
                binaryImage.at<unsigned char>(y,x) = 0;
        }
    }



    cv::imshow("input", input);
    cv::imshow("binary", binaryImage);
    //cv::imwrite("../outputData/binaryCustom.png", binaryImage);
    cv::waitKey(0);
    return 0;
}

给我这些结果:

它很慢,但根本没有优化或封装;) 结果不是那么好恕我直言。可能您必须将 windowSizes 调整为您的应用程序/任务/objectSize

【讨论】:

  • 我试过这个,对于 m 用例,它肯定会给出更好的结果,但与我的要求相去甚远。此外,它需要大量优化,因为它非常慢。我可能不得不一起寻找替代解决方案(即不遵循二值化方法)。感谢您的帮助。
猜你喜欢
  • 2021-02-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-20
  • 2015-09-01
  • 1970-01-01
  • 2014-10-29
  • 2011-01-09
相关资源
最近更新 更多