美文网首页
openCV全局二值化和局域二值化比较

openCV全局二值化和局域二值化比较

作者: 古界族邪神 | 来源:发表于2019-11-29 16:26 被阅读0次

    作者:鸭大楚春秋 老师:曾老师

    对图像二值化有全局阈值化和局部二值化。全局二值化比较典型的就是大津法

    全局二值化对光照非常敏感,局部二值化好一些

    #include <opencv.hpp>
    #include <iostream>
    #include <time.h>
    #include <opencv2/imgproc/types_c.h>
    #include <sstream>
    
    using namespace std;
    using namespace cv;
    
    
    
    int main()
    {
        
        String imgLoad = "4.jpg";
        Mat image = imread(imgLoad);
    
        cvtColor(image, image, CV_RGB2GRAY);
        //局部二值化
        int blockSize = 25;
        int constValue = 10;
        cv::Mat local;
        //cv::threshold(image, local, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
        cv::adaptiveThreshold(image, local, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, blockSize, constValue);
    
        //基于形态学去噪:腐蚀和膨胀
        int element_size = 1;//3
        //创建结构元
        int s = element_size * 2 + 1;//必须是奇数
        Mat structureElement = getStructuringElement(MORPH_RECT, Size(s, s), Point(-1, -1));
        Mat dst;
        
        
        //两次闭运算,先膨胀后腐蚀
        dilate(local, dst, structureElement, Point(-1, -1), 1);
        erode(dst, dst, structureElement);
        dilate(dst, dst, structureElement, Point(-1, -1), 1);
        erode(dst, dst, structureElement);
    
        //两次开运算,先腐蚀后膨胀
        erode(dst, dst, structureElement);
        dilate(dst, dst, structureElement, Point(-1, -1), 1);
        erode(dst, dst, structureElement);
        dilate(dst, dst, structureElement, Point(-1, -1), 1);
    
    
        
    
        namedWindow("去噪后图像", 0);
        imshow("去噪后图像", dst);
    
        cv::waitKey(0);
        //String imgWrite = "result3.jpg";
        //imwrite(imgWrite, dst);
    
        
    }
    

    原图片


    4.jpg

    局部二值化


    result4.jpg
    全局二值化
    result4_1.jpg

    二值化以后可以发现:有很多“椒盐噪声”
    可以使用形态学的方法去除
    两个基本操作:腐蚀和膨胀


    erode.png

    组合运算:开运算和闭运算


    open.png
    经过尝试,进行闭运算,再进行开运算效果更好
    同时开运算闭运算的次数影响不大,但是结构元大小影响很大,建议是3(最小)。
    先开运算后闭运算
    result1.jpg

    先闭运算再开运算:可惜容易误伤边界


    result1.jpg
    这是我实现的大津法
    输入图像,返回全局阈值
    {
        int th;//最佳分割阈值
        const int GrayScale = 256;//图像的灰度级数
        int pixCount[GrayScale] = { 0 };//每个灰度值所占像素个数
        int pixSum = src.cols*src.rows;//图像总像素点
        double pixPro[GrayScale] = { 0 };
        
    
        for (int i = 0; i < src.rows; i++)
        {
            for (int j = 0; j < src.cols; j++)
            {
                pixCount[src.at<uchar>(i, j)]++;//统计每个灰度级的像素的个数
            }
        }
    
        for (int i = 0; i < GrayScale; i++)
        {
            pixPro[i] = pixCount[i] * 1.0 / pixSum;//计算每个灰度级的像素数目占整幅图像的比例  
        }
    
        //遍历所有从0到255灰度级的阈值T(分割),比较哪一个的类间方差最大
        double w0, w1, u0tmp, u1tmp, u0, u1, deltaTmp;
        double deltaMax = 0;
        for (int i = 0; i < GrayScale; i++)
        {
            w0 = w1 = u0tmp = u1tmp = u0 = u1 = deltaTmp = 0;
            for (int j = 0; j < GrayScale; j++)
            {
                //前景
                if (j <= i)
                {
                    w0 += pixPro[j];
                    u0tmp += j * pixPro[j];
                }
                else//背景
                {
                    w1 += pixPro[j];
                    u1tmp += j * pixPro[j];
                }
            }
    
            u0 = u0tmp / w0;
            u1 = u1tmp / w1;
            deltaTmp = w0 * w1*pow((u0 - u1), 2);
            if (deltaTmp> deltaMax)
            {
                deltaMax = deltaTmp;
                th = i;
            }
        }
    
        return th;
    }
    

    我的原本思路是按照局部二值化后的结果,进行倾斜校正。
    根据我阅读的论文,应该采用顶点链编码的方法。但是顶点链编码难度有点大,我先完成一个可以运行的系统,采用比如霍夫变换等比较成熟的方法,然后再试试顶点链编码的效果。

    相关文章

      网友评论

          本文标题:openCV全局二值化和局域二值化比较

          本文链接:https://www.haomeiwen.com/subject/domwwctx.html