我想对低质量的图像进行二值化处理,发现使用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

但是我之前没有从事图像处理工作,所以我想知道如何继续实现它以及实现这些算法需要哪些知识

最佳答案

我在大约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;
}

给我这些结果:

opencv - opencv中使用更新算法的图像二值化-LMLPHP opencv - opencv中使用更新算法的图像二值化-LMLPHP



opencv - opencv中使用更新算法的图像二值化-LMLPHP opencv - opencv中使用更新算法的图像二值化-LMLPHP

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

关于opencv - opencv中使用更新算法的图像二值化,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/33229175/

10-11 19:11