OpenCV3学习(4.1)——图像阈值操作(Threshold,AdaptiveThreshold)

本文深入讲解图像处理中的阈值分割技术,包括固定阈值、自适应阈值、OTSU算法等,探讨不同方法在图像分割中的应用及效果对比。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

阈值分割的作用 
阈值分割其实就是图像分离,对于阈值内的你想如何操作,一个最简单的例子就是二值图像。

所謂的二值化是將影像進行區分,分成我們感興趣的部分(前景),以及不感興趣的部分(背景),通常將某個強度當作分割的標準,這個強度稱作閾值(threshold),通常以強度超過閾值的像素當作前景,反之則為背景。

閾值的算法主要分兩類:

固定閾值:程式或使用者直接給定一個灰階值當閾值,再用這個閾值進行二值化。

自適應閾值:輸入影像,程式依這影像計算出較合適的閾值,再用這個閾值進行二值化

接下来我们看下方法: 
threshold   —— 简单的阈值操作 
adaptiveThreshold —— 自适应阈值操作

threshold—— 简单的阈值操作 

CV_EXPORTS_W double threshold( InputArray src, OutputArray dst,
                               double thresh, double maxval, int type );

第一个参数,InputArray类型的src,输入数组,填单通道 , 8或32位浮点类型的Mat即可。

第二个参数,OutputArray类型的dst,函数调用后的运算结果存在这里,即这个参数用于存放输出结果,且和第一个参数中的Mat变量有一样的尺寸和类型。

第三个参数,double类型的thresh,阈值的具体值。

第四个参数,double类型的maxval,当第五个参数阈值类型type取 THRESH_BINARY 或THRESH_BINARY_INV阈值类型时的最大值.

第五个参数,int类型的type,阈值类型,有以下几种类型:

enum ThresholdTypes {
    THRESH_BINARY     = 0,//二进制阈值化 -> 大于阈值为1 小于阈值为0 
    THRESH_BINARY_INV = 1,//反二进制阈值化 -> 大于阈值为0 小于阈值为1
    THRESH_TRUNC      = 2,//截断阈值化 -> 大于阈值为阈值,小于阈值不变 
    THRESH_TOZERO     = 3,//阈值化为0 -> 大于阈值的不变,小于阈值的全为0
    THRESH_TOZERO_INV = 4,//反阈值化为0 -> 大于阈值为0,小于阈值不变
    THRESH_MASK       = 7,
    THRESH_OTSU       = 8,
    THRESH_TRIANGLE   = 16
};

具体运算规则: 

 注意:

THRESH_OTSU和THRESH_TRIANGLE是作为优化算法配合THRESH_BINARY、THRESH_BINARY_INV、THRESH_TRUNC、THRESH_TOZERO以及THRESH_TOZERO_INV来使用的。

当使用了THRESH_OTSU和THRESH_TRIANGLE两个标志时,输入图像必须为单通道。
生成关系:

 

这里着重讲一下OTSU算法

      Otsu法(最大类间方差法,有时也称之为大津算法)使用的是聚类的思想,把图像的灰度数按灰度级分成2个部分,使得两个部分之间的灰度值差异最大,每个部分之间的灰度差异最小,通过方差的计算来寻找一个合适的灰度级别来划分。所以可以在二值化的时候采用otsu算法来自动选取阈值进行二值化。otsu算法被认为是图像分割中阈值选取的最佳算法,计算简单,不受图像亮度和对比度的影响。因此,使类间方差最大的分割意味着错分概率最小。
     该算法的理论依据是:假定图像包含两类像素(前景像素和背景像素),直方图为双峰直方图,然后计算使得两类像素能分开的最佳阈值(类内方差),或等价的间类间方差最大。

Otsu算法原理:

    对于图像 I(x,y),前景(即目标)和背景的分割阈值记作 T,属于前景的像素点数占整幅图像的比例记为 ω0,平均灰度为 μ0;背景像素点数占整幅图像的比例为 ω1,平均灰度为 μ1;整幅图像的平均灰度记为μ,类间方差记为g。
    假设图像大小为M×N,图像中像素的灰度值小于阈值 T 的像素个数为 N0,像素灰度大于阈值T的像素个数为 N1,那么:
 wo: 分开后  前景像素点数占图像的比例     ω0=N0/ M×N                      (1)   
 w1:分开后  被景像素点数占图像的比例      ω1=N1/ M×N                      (2)
 u:图像总平均灰度                                          μ=ω0*μ0+ω1*μ1                 (3)                                                                      其中:uo表示分开后,前景像素点的平均灰度;u1表示分开后,被景像素点的平均灰度。

      从L个灰度级遍历T,使得T为某个值的时候,前景和背景的方差最大, 则这个T 值便是我们要求得的阈值。

其中,方差的计算公式如下:               g=wo * (uo - u) * (uo - u) + w1 * (u1 - u) * (u1 - u)

此公式计算量较大,可以采用:           g = wo * w1 * (uo - u1) * (uo - u1)

采用遍历的方法使得类间方差g最大的阈值T,即为所求。Ostu方法可以形象地理解为:求取直方图有两个峰值的图像中那两个峰值之间的低谷值 T 。

Otsu流程:

  • 先計算影像的直方圖
  • 把直方圖強度大於閾值的像素分成一組,把小於閾值的像素分成另一組。
  • 分別計算這兩組的組內變異數,並把兩個組內變異數相加。
  • 將0~255依序當作閾值來計算組內變異數和,總和值最小的就是結果閾值。

OpenCV自適應閾值二值化:

一樣是用threshold()函式,使用方式也一樣,只是最後一個參數增加CV_THRESH_OTSU,目前otsu只能使用在8位元圖。

double threshold(InputArray src, OutputArray dst, double thresh, double maxval, int type)

src:輸入圖,只能輸入單通道。          dst:輸出圖,尺寸大小、深度會和輸入圖相同。

thresh:閾值。                                     maxval:二值化結果的最大值。

type:有THRESH_BINARY、THRESH_BINARY_INV、THRESH_TRUNC、THRESH_TOZERO、THRESH_TOZERO_INV五種。type從上述五種結合CV_THRESH_OTSU,類似寫成:THRESH_BINARY | CV_THRESH_OTSU

值得一说的是threshold_type使用CV_THRESH_OTSU类型,这样该函数就会使用大律法OTSU得到的全局自适应阈值来进行二值化图片,而参数中的threshold不再起作用。

from:https://blog.youkuaiyun.com/weixin_42296411/article/details/80901080

from:https://blog.youkuaiyun.com/zangle260/article/details/52980060

 

2、adaptiveThreshold —— 自适应阈值操作

    图像阈值化的一般目的是从灰度图像中分享目标区域和背景区域,然而仅仅通过设定固定阈值(固定阈值的求解可点此查看我写的博文)很难达到理想的分割效果。在实际应用中,我们可以通过某个像素的邻域以某种方法确定这个像素应该具有的阈值,进而保证图像中各个像素的阈值会随着周期围邻域块的变化而变化。在灰度图像中,灰度值变化明显的区域往往是物体的轮廓,所以将图像分成一小块一小块的去计算阈值往往会得出图像的轮廓,而固定阈值的方法就不行,可以把本文的结果和用固定阈值法进行二值化的结果作下对比,很容易发现这一点!
 

CV_EXPORTS_W void adaptiveThreshold( InputArray src, OutputArray dst,
                                     double maxValue, int adaptiveMethod,
                                     int thresholdType, int blockSize, double C );

InputArray src:源图像

OutputArray dst:输出图像,与源图像大小一致

int adaptiveMethod:在一个邻域内计算阈值所采用的算法,平均法和高斯法,有两个取值,分别为  ADAPTIVE_THRESH_MEAN_C 和 ADAPTIVE_THRESH_GAUSSIAN_C 。

ADAPTIVE_THRESH_MEAN_C的计算方法是计算出邻域的平均值再减去第七个参数double C的值

ADAPTIVE_THRESH_GAUSSIAN_C的计算方法是计算出邻域的高斯均值再减去第七个参数double C的值

int thresholdType:这是阈值类型,只有两个取值,分别为 THRESH_BINARY 和THRESH_BINARY_INV  

int blockSize:adaptiveThreshold的计算单位是像素的邻域块,这个值作决定了邻域块取多大。

double C:这个参数实际上是一个偏移值调整量

使用函数adaptiveThreshold的关键是确定blockSize和C的值,明白了这两个值的意义之后,在实际项目中,应该可以根据试验法选出较为合适的值!
from:https://blog.youkuaiyun.com/wenhao_ir/article/details/51565517

实例:

#include<iostream>
#include<opencv2\opencv.hpp>
#include<opencv2\imgproc\imgproc.hpp>
using namespace std;
using namespace cv;

int trackbarValue = 0;
Mat src,dst4, dst5, dst6;

void change1(int threshould, void *) {
	threshold(src, dst4, threshould, 255, THRESH_BINARY);
	imshow("dst4", dst4);
};

void change2(int threshould, void *) {
	threshold(src, dst5, threshould, 255, THRESH_BINARY | THRESH_OTSU);
	imshow("dst5", dst5);
};
void change3(int threshould, void *) {
	adaptiveThreshold(src, dst6, threshould, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 15, 10);
	imshow("dst6", dst6);
};

int main(){
	Mat img = imread("111.jpg", 1);
	img.copyTo(src);//深拷贝
    cvtColor(img, src, COLOR_RGB2GRAY);
	
	namedWindow("dst4", CV_WINDOW_AUTOSIZE);//创建进度条时,前面必须先创建一个窗口声明
	createTrackbar("threshould", "dst4", &trackbarValue, 255, change1);
	namedWindow("dst5", CV_WINDOW_AUTOSIZE);//创建进度条时,前面必须先创建一个窗口声明
	createTrackbar("threshould", "dst5", &trackbarValue, 255, change2);
	namedWindow("dst6", CV_WINDOW_AUTOSIZE);//创建进度条时,前面必须先创建一个窗口声明
	createTrackbar("threshould", "dst6", &trackbarValue, 255, change3);
    waitKey(0);
}

结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值