OPenCV3之——图像阈值化操作:threshold()函数
程序员文章站
2024-02-11 12:41:28
...
阈值化
在各种图形进行处理操作的过程中,常常需要对图像中的像素做出取舍决策,直接剔除一些低于或者高于一定值的像素。
阈值可以被看作是最简单的图像分割方法,这样的图像分割方法基于图像中物体与背景直接的灰度差异,属于像素级别的分割,用图像中每一个像素值与选取的阈值做比较,并做出相应的判断。。
一、固定阈值操作: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,对图像取阈值的方法,取值如下:
- THRESH_BINARY:二值阈值化 0
- THRESH_TOZERO_INV:反二值阈值化 1
- THRESH_TRUNC:截断阈值化 2
- THRESH_TOZERO:低于阈值被置为0 3
- 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);
}
运行结果:
上一篇: Android-Android 10 创建不了文件夹
下一篇: 读书笔记-opencv-阈值分割