opencv图像处理学习(九)——阈值化

一幅图像包括目标、背景及噪声,想要直接提取出目标物体,通常采用灰度变换阈值化操作。图像的阈值化操作就是利用图像像素点分布规律,设定阈值进行像素点分割,进而得到二值化图像。图像阈值化操作方法有很多,常用经典的有OTUS、固定阈值、自适应阈值、双阈值及半阈值化操作。

<1>OTUS

其算法步骤如下:

(1)统计灰度级中每一个像素在整幅图像中的个数

(2)计算每个像素在整幅图像的概率分布

(3)对灰度级进行遍历搜索,计算当前灰度值下前景背景类间概率

(4)通过目标函数计算出类内与类间方差下对应的阈值

e.g:

#include <stdio.h>
#include <string>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\opencv.hpp>

using namespace std;
using namespace cv;

int OTUS(Mat srcImage)//Image应该是一个8U的图像
{
    int nCols = srcImage.cols;
    int nRows = srcImage.rows;
    int threshold = 0;

    //初始化统计参数

    int nSumPix[256];//像素个数
    float nProDis[256];//概率分布

    for (int i = 0; i < 256; i++)
    {
        nSumPix[i] = 0;
        nProDis[i] = 0;
    }

    //统计灰度级中每个像素在整幅图像中的个数
    for (int i = 0; i < nCols; i++)
    {
        for (int j = 0; j < nRows; j++)
        {
            nSumPix[(int)srcImage.at<uchar>(i, j)]++;
        }
    }

    //统计每个灰度级占图像中的概率分布
    for (int i = 0; i < 256; i++)
    {
        nProDis[i] = (float)nSumPix[i] / (nCols * nRows);
    }

    //遍历灰度级[0,255],计算出最大类间方差下的阈值
    float w0, w1, u0_temp, u1_temp, u0, u1, delta_temp;
    double delta_max = 0.0;

    for (int i = 0; i < 256; i++)
    {
        w0 = w1 = u0_temp = u1_temp = u0 = u1 = delta_temp = 0;
        
        for (int j = 0; j < 256; j++)
        {
            //背景部分
            if ( j <= i)
            {
                //当前i为分割阈值,第一类总概率
                w0 += nProDis[j];
                u0_temp += j * nProDis[j];
            }

            //前景部分
            else
            {
                //当前i为分割阈值,第一类总概率
                w1 += nProDis[j];
                u1_temp += j * nProDis[j];

            }
        }

        //分别计算各类的平均灰度
        u0 = u0_temp / w0;
        u1 = u1_temp / w1;
        delta_temp = (float)( w0 * w1 * pow((u0 - u1), 2));

        //依次找到最大类间方差下的阈值
        if (delta_temp > delta_max)
        {
            delta_max = delta_temp;
            threshold = i;
        }
    }

    return threshold;
}

int main()
{
    Mat srcImage = imread("u=497076178,1248191674&fm=26&gp=0.jpg");
    
    if (!srcImage.data)
    {
        return -1;
    }

    Mat srcGray;
    cvtColor(srcImage, srcGray,CV_RGB2GRAY);
    imshow("srcGray", srcGray);

    int outThreshold = OTUS(srcGray);
    std::cout << outThreshold << std::endl;

    Mat otusResultImage = cv::Mat::zeros(srcGray.rows, srcGray.cols,CV_8UC1);

    //调用OTUS函数
    for (int i = 0; i < srcGray.rows; i++)
    {
        for (int j = 0; j < srcGray.cols; j++)
        {
            if (srcGray.at<uchar>(i,j) > outThreshold)
            {
                otusResultImage.at<uchar>(i, j) = 255;

            }

            else
            {
                otusResultImage.at<uchar>(i, j) = 0;
            }
        }
    }

    imshow("otusResultImage", otusResultImage);
    waitKey(0);
    return 0;
}

PS:这个程序有个bug没找到,有哪个大神愿意试一下说一下问题的

<2>其他阈值化

opencv中提供的阈值化为 double threshold(InputArray src,Output dst,double thresh,double maxval,int type);

其中参数src表示源图像,dst表示输出图像,thresh表示阈值设置,maxval表示预设最大值,使用THRESH_BINARY或THRESH_BINARY_INY类型;type表示阈值化处理的类型设置。

PS:该函数应用在单通道图像中固定阈值化处理,通常是为了得到二值化图像或除去噪声。

对于THRESH_BINARY二进制阈值化为dst(x,y)=\left\{\begin{matrix} maxval src(x,y)>thresh \\ 0 other \end{matrix}\right.

对于THRESH_BINARY_INV反二进制阈值化为dst(x,y)=\left\{\begin{matrix} max val src(x,y)\leq thresh \\ 0 other \end{matrix}\right.

对于THRESH_TRUNC截断阈值化为dst(x,y)=\left\{\begin{matrix} threshold src(x,y)>thresh \\ src(x,y) other \end{matrix}\right.

对于THRESH_TOZERO阈值化为0为dst(x,y)=\left\{\begin{matrix} src(x,y) src(x,y)>thresh \\ 0 other \end{matrix}\right.

对于THRESH_TOZERO_INV反阈值化为0为dst(x,y)=\left\{\begin{matrix} threshold src(x,y)>thresh \\ src(x,y) other \end{matrix}\right.

对于双阈值化为dst(x,y)=\left\{\begin{matrix} max val thresh2>src(x,y)>thresh1 \\ 0 other \end{matrix}\right.

对于半阈值化为dst(x,y)=\left\{\begin{matrix} src(x,y) src(x,y)>thresh \\ 0 other \end{matrix}\right.

<3>自适应阈值化

在opencv中,其函数名为adaptiveThreshold.

void adaptiveThreshold(InputArray src,OutputArray dst, double maxval,int adaptiveMethod,int thresholdTpye,int blocksize,double C);

PS:大部分人对这个常数C很懵,我们下面来具体讲解

其中src表示源图像;dst表示输出图像;maxval表示预设满足条件的最大值;adaptiveMethod表示自适应阈值算法的选择,一共有两种;ThresholdType表示阈值类型;参数blockSize表示邻域块大小;C表示常数。

首先blockSize必须为奇数(3,5,7……),这个拿来做掩膜(PS:后面再讲),这个参数小则具有边缘检测的效果,大则达到二值化效果。

现在我们来看看常数C到底干嘛的。PS:有的帖子说是控制边缘的类型和粗细。

上面提到了自适应阈值化的两种方法,其分别为ADAPTIVE_THRESH_MEAN_C和ADAPTIVE_THRESH_GAUSSIAN_C

对于ADAPTIVE_THRESH_MEAN_C,其数学运算为:领域块内所有像素-blocksize*常数C,其阈值是区域内的均值。

对于ADAPTIVE_THRESH_GAUSSIAN_C,其数学运算为:blocksize*((领域块内所有像素-C)交叉相关高斯窗的加权总和),其阈值是加权平均值,权重是区域内的高斯值,权重随着距离减小。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值