在opencv中使用更新的算法进行图像二值化

时间:2015-10-20 06:06:38

标签: opencv image-processing adaptive-threshold

我想要对低质量图像进行二值化,并发现现有的解决方案或程序是全局和局部二值化技术的实现,例如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

但是之前我还没有进行过图像处理,所以我想知道如何继续实现它以及我需要哪些知识来实现​​这些算法

1 个答案:

答案 0 :(得分: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;
}

给我这些结果:

enter image description here enter image description here

enter image description here enter image description here

速度很慢,但根本没有优化或封装;) 并且结果不是那么好的imho。您可能需要将windowSizes调整为您的application / task / objectSize