OPenCV3之——图像阈值化操作:threshold()函数

阈值化

           在各种图形进行处理操作的过程中,常常需要对图像中的像素做出取舍决策,直接剔除一些低于或者高于一定值的像素。

           阈值可以被看作是最简单的图像分割方法,这样的图像分割方法基于图像中物体与背景直接的灰度差异,属于像素级别的分割,用图像中每一个像素值与选取的阈值做比较,并做出相应的判断。。

一、固定阈值操作:threshold()函数

           threshold()函数对单通道数组进行固定阈值操作

           典型应用:取二值图像(compare()函数也可以达到此目的)、去噪声(过滤很小或者很大的图像点)

函数原型:

double cv::threshold( InputArray _src, 
                      OutputArray _dst, 
                      double thresh, 
                      double maxval, 
                      int type )
{
    CV_INSTRUMENT_REGION()

    CV_OCL_RUN_(_src.dims() <= 2 && _dst.isUMat(),
                ocl_threshold(_src, _dst, thresh, maxval, type), thresh)

    Mat src = _src.getMat();
    int automatic_thresh = (type & ~CV_THRESH_MASK);
    type &= THRESH_MASK;

    CV_Assert( automatic_thresh != (CV_THRESH_OTSU | CV_THRESH_TRIANGLE) );
    if( automatic_thresh == CV_THRESH_OTSU )
    {
        CV_Assert( src.type() == CV_8UC1 );
        thresh = getThreshVal_Otsu_8u( src );
    }
    else if( automatic_thresh == CV_THRESH_TRIANGLE )
    {
        CV_Assert( src.type() == CV_8UC1 );
        thresh = getThreshVal_Triangle_8u( src );
    }

    _dst.create( src.size(), src.type() );
    Mat dst = _dst.getMat();

    if( src.depth() == CV_8U )
    {
        int ithresh = cvFloor(thresh);
        thresh = ithresh;
        int imaxval = cvRound(maxval);
        if( type == THRESH_TRUNC )
            imaxval = ithresh;
        imaxval = saturate_cast<uchar>(imaxval);

        if( ithresh < 0 || ithresh >= 255 )
        {
            if( type == THRESH_BINARY || type == THRESH_BINARY_INV ||
                ((type == THRESH_TRUNC || type == THRESH_TOZERO_INV) && ithresh < 0) ||
                (type == THRESH_TOZERO && ithresh >= 255) )
            {
                int v = type == THRESH_BINARY ? (ithresh >= 255 ? 0 : imaxval) :
                        type == THRESH_BINARY_INV ? (ithresh >= 255 ? imaxval : 0) :
                        /*type == THRESH_TRUNC ? imaxval :*/ 0;
                dst.setTo(v);
            }
            else
                src.copyTo(dst);
            return thresh;
        }

       CV_OVX_RUN(!ovx::skipSmallImages<VX_KERNEL_THRESHOLD>(src.cols, src.rows),
                  openvx_threshold(src, dst, ithresh, imaxval, type), (double)ithresh)

        thresh = ithresh;
        maxval = imaxval;
    }
    else if( src.depth() == CV_16S )
    {
        int ithresh = cvFloor(thresh);
        thresh = ithresh;
        int imaxval = cvRound(maxval);
        if( type == THRESH_TRUNC )
            imaxval = ithresh;
        imaxval = saturate_cast<short>(imaxval);

        if( ithresh < SHRT_MIN || ithresh >= SHRT_MAX )
        {
            if( type == THRESH_BINARY || type == THRESH_BINARY_INV ||
               ((type == THRESH_TRUNC || type == THRESH_TOZERO_INV) && ithresh < SHRT_MIN) ||
               (type == THRESH_TOZERO && ithresh >= SHRT_MAX) )
            {
                int v = type == THRESH_BINARY ? (ithresh >= SHRT_MAX ? 0 : imaxval) :
                type == THRESH_BINARY_INV ? (ithresh >= SHRT_MAX ? imaxval : 0) :
                /*type == THRESH_TRUNC ? imaxval :*/ 0;
                dst.setTo(v);
            }
            else
                src.copyTo(dst);
            return thresh;
        }
        thresh = ithresh;
        maxval = imaxval;
    }
    else if (src.depth() == CV_16U )
    {
        int ithresh = cvFloor(thresh);
        thresh = ithresh;
        int imaxval = cvRound(maxval);
        if (type == THRESH_TRUNC)
            imaxval = ithresh;
        imaxval = saturate_cast<ushort>(imaxval);

        int ushrt_min = 0;
        if (ithresh < ushrt_min || ithresh >= (int)USHRT_MAX)
        {
            if (type == THRESH_BINARY || type == THRESH_BINARY_INV ||
               ((type == THRESH_TRUNC || type == THRESH_TOZERO_INV) && ithresh < ushrt_min) ||
               (type == THRESH_TOZERO && ithresh >= (int)USHRT_MAX))
            {
                int v = type == THRESH_BINARY ? (ithresh >= (int)USHRT_MAX ? 0 : imaxval) :
                        type == THRESH_BINARY_INV ? (ithresh >= (int)USHRT_MAX ? imaxval : 0) :
                  /*type == THRESH_TRUNC ? imaxval :*/ 0;
                dst.setTo(v);
            }
            else
                src.copyTo(dst);
            return thresh;
        }
        thresh = ithresh;
        maxval = imaxval;
    }
    else if( src.depth() == CV_32F )
        ;
    else if( src.depth() == CV_64F )
        ;
    else
        CV_Error( CV_StsUnsupportedFormat, "" );

    parallel_for_(Range(0, dst.rows),
                  ThresholdRunner(src, dst, thresh, maxval, type),
                  dst.total()/(double)(1<<16));
    return thresh;
}

简版

double cv::threshold( InputArray _src, 
                      OutputArray _dst, 
                      double thresh, 
                      double maxval, 
                      int type )

参数详解:

  • 第一个参数,InputArray类型的src,输出数组,单通道,8或32位Mat类对象即可;
  • 第二个参数,OutputArray类型的dst,输出数组,和src有一样的尺寸和类型;
  • 第三个参数,double类型的thresh,阈值的具体值;
  • 第四个参数,double类型的maxval,当第五个参数取THRESH_BINARY或THRESH_BINARY_INV阈值类型时的最大值;
  • 第五个参数,int类型的typy,对图像取阈值的方法,取值如下:
  1. THRESH_BINARY:二值阈值化                            0
  2. THRESH_TOZERO_INV:反二值阈值化              1
  3. THRESH_TRUNC:截断阈值化                             2
  4. THRESH_TOZERO:低于阈值被置为0                3
  5. THRESH_TOZERO_INV:超过阈值被置为0        4

<1>固定阈值操作示例:

#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;

#define WINDOW_NAME "【程序窗口】"

//全局变量声明部分
int g_nThresholdValue = 100;
int g_nThresholdType = 3;
Mat g_srcImage, g_grayImage, g_dstImage;

//全局函数声明部分
void on_Threshold(int, void*);//回调函数

int main() {
	g_srcImage = imread("1.jpg");
	if (!g_srcImage.data) {
		cout << "读取图片错误!" << endl;
		return false;
	}

	//留存一份原图的灰度图
	cvtColor(g_srcImage, g_grayImage, COLOR_RGB2GRAY);

	//创建窗口并显示原图
	namedWindow(WINDOW_NAME,WINDOW_AUTOSIZE);
	imshow(WINDOW_NAME, g_srcImage);

	//创建滑动条来控制阈值
	createTrackbar("模式", WINDOW_NAME, &g_nThresholdType, 4, on_Threshold);
	createTrackbar("参数值", WINDOW_NAME, &g_nThresholdValue, 255, on_Threshold);

	//初始化自定义的 阈值回调函数
	on_Threshold(0, 0);

	//轮询等待用户按键
	while (1) {
		int key;
		key = waitKey(20);
		if ((char)key == 27)
			break;
	}
	return 0;
}

//on_Threshold函数
void on_Threshold(int, void*) {
	//调用阈值函数
	threshold(g_grayImage, g_dstImage, g_nThresholdValue, 255, g_nThresholdType);

	//更新效果图
	imshow(WINDOW_NAME, g_dstImage);
}

运行截图:

 

二、自适应阈值操作:adaptiveThreshold()函数

        adaptiveThreshold()函数作用是对矩形采用自适应阈值操作,支持就地操作

函数原型:

void cv::adaptiveThreshold( InputArray _src, 
                            OutputArray _dst, 
                            double maxValue,
                            int method, 
                            int type,
                            int blockSize, 
                            double delta )
{
    CV_INSTRUMENT_REGION()

    Mat src = _src.getMat();
    CV_Assert( src.type() == CV_8UC1 );
    CV_Assert( blockSize % 2 == 1 && blockSize > 1 );
    Size size = src.size();

    _dst.create( size, src.type() );
    Mat dst = _dst.getMat();

    if( maxValue < 0 )
    {
        dst = Scalar(0);
        return;
    }

    CALL_HAL(adaptiveThreshold, cv_hal_adaptiveThreshold, src.data, src.step, dst.data, dst.step, src.cols, src.rows,
             maxValue, method, type, blockSize, delta);

    Mat mean;

    if( src.data != dst.data )
        mean = dst;

    if (method == ADAPTIVE_THRESH_MEAN_C)
        boxFilter( src, mean, src.type(), Size(blockSize, blockSize),
                   Point(-1,-1), true, BORDER_REPLICATE|BORDER_ISOLATED );
    else if (method == ADAPTIVE_THRESH_GAUSSIAN_C)
    {
        Mat srcfloat,meanfloat;
        src.convertTo(srcfloat,CV_32F);
        meanfloat=srcfloat;
        GaussianBlur(srcfloat, meanfloat, Size(blockSize, blockSize), 0, 0, BORDER_REPLICATE|BORDER_ISOLATED);
        meanfloat.convertTo(mean, src.type());
    }
    else
        CV_Error( CV_StsBadFlag, "Unknown/unsupported adaptive threshold method" );

    int i, j;
    uchar imaxval = saturate_cast<uchar>(maxValue);
    int idelta = type == THRESH_BINARY ? cvCeil(delta) : cvFloor(delta);
    uchar tab[768];

    if( type == CV_THRESH_BINARY )
        for( i = 0; i < 768; i++ )
            tab[i] = (uchar)(i - 255 > -idelta ? imaxval : 0);
    else if( type == CV_THRESH_BINARY_INV )
        for( i = 0; i < 768; i++ )
            tab[i] = (uchar)(i - 255 <= -idelta ? imaxval : 0);
    else
        CV_Error( CV_StsBadFlag, "Unknown/unsupported threshold type" );

    if( src.isContinuous() && mean.isContinuous() && dst.isContinuous() )
    {
        size.width *= size.height;
        size.height = 1;
    }

    for( i = 0; i < size.height; i++ )
    {
        const uchar* sdata = src.ptr(i);
        const uchar* mdata = mean.ptr(i);
        uchar* ddata = dst.ptr(i);

        for( j = 0; j < size.width; j++ )
            ddata[j] = tab[sdata[j] - mdata[j] + 255];
    }
}

简版:

void cv::adaptiveThreshold( InputArray _src, 
                            OutputArray _dst, 
                            double maxValue,
                            int method, 
                            int type,
                            int blockSize, 
                            double delta )

参数详解:

 

  • 第一个参数,InputArray类型的src,输入图像,需为8位单通道浮点型图像;
  • 第二个参数,OutputArray类型的dst,输出图像,和src有一样的尺寸和类型;
  • 第三个参数,double类型的maxValue,给像素赋的满足条件的非零值;
  • 第四个参数,int类型的adaptiveMethod,用于指定要使用的阈值化算法,可取值为:ADAPTIVE_THRESH_MEAN_C或者ADAPTIVE_THRESH_GAUSSIAN_C;
  • 第五个参数,int类型的thresholdType,阈值类型,取值须为CV_THRESH_BINARY和CV_THRESH_BINARY_INV其中之一;
int idelta = type == THRESH_BINARY ? cvCeil(delta) : cvFloor(delta);
uchar tab[768];

if( type == CV_THRESH_BINARY )
        for( i = 0; i < 768; i++ )
            tab[i] = (uchar)(i - 255 > -idelta ? imaxval : 0);
    else if( type == CV_THRESH_BINARY_INV )
        for( i = 0; i < 768; i++ )
            tab[i] = (uchar)(i - 255 <= -idelta ? imaxval : 0);
    else
        CV_Error( CV_StsBadFlag, "Unknown/unsupported threshold type" );
  • 第六个参数,int类型的blockSize,用于计算阈值大小的一个像素的邻域尺寸,取值为3、5、7等;
  • 第七个参数,double类型的C,减去平均或者加权平均值后的常数值。通常为正数,少数情况下为负数或者0。

<2>自适应阈值化操作示例:

#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;

#define WINDOW_NAME "【程序窗口】"

//全局变量声明部分
int g_nThresholdValue = 100;
int g_nThresholdType = 1;
int g_c = 0;
int g_binary = 0;
Mat g_srcImage, g_grayImage, g_dstImage;

//全局函数声明部分
void on_Threshold(int, void*);//回调函数

int main() {
	g_srcImage = imread("1.jpg");
	if (!g_srcImage.data) {
		cout << "读取图片错误!" << endl;
		return false;
	}

	//留存一份原图的灰度图
	cvtColor(g_srcImage, g_grayImage, COLOR_RGB2GRAY);

	//创建窗口并显示原图
	namedWindow(WINDOW_NAME,WINDOW_AUTOSIZE);
	imshow(WINDOW_NAME, g_srcImage);

	//创建滑动条来控制阈值
	createTrackbar("模式", WINDOW_NAME, &g_nThresholdType, 1, on_Threshold);
	createTrackbar("参数值", WINDOW_NAME, &g_nThresholdValue, 255, on_Threshold);
	createTrackbar("C值", WINDOW_NAME, &g_c, 100, on_Threshold);

	//初始化自定义的 阈值回调函数
	on_Threshold(0, 0);

	//轮询等待用户按键
	while (1) {
		int key;
		key = waitKey(20);
		if ((char)key == 27)
			break;
	}
	return 0;
}

//on_Threshold函数
void on_Threshold(int, void*) {
	//调用阈值函数
	adaptiveThreshold(g_grayImage, g_dstImage, g_nThresholdValue, g_nThresholdType, THRESH_BINARY, 5, g_c);

	//更新效果图
	imshow(WINDOW_NAME, g_dstImage);
}

运行结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

衣带渐宽人憔悴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值