目录
一、OpenCV-阀值操作
1.1阀值操作函数threshold
1.2threshold的操作类型
1.3Otsu算法
二、样例开发
2.1 Makefile
2.2 main.cpp
2.3 运行效果
三、OpenCV-自适应阀值操作
3.1 自适应阀值操作函数-adaptiveThreshold
3.2 样例开发
一、OpenCV-阀值操作
1.1阀值操作函数threshold
在OpenCV中,阀值操作是一种基本的图像处理方法,用于将灰度图像转换为二值图像。这个操作是通过使用一个设定的阈值(thresh)来比较输入图像的每个像素值,并根据比较结果将像素值设置为0或最大值(maxval)。有五种不同的阀值操作类型,包括二进制阀值化、反二进制阀值化、截断阀值化、阀值化为0、反阀值化为0。
在OpenCV-C++源码中,其阀值操作函数定义在\opencv2\imgproc.hpp中:
@param src input array (multiple-channel, 8-bit or 32-bit floating point).
@param dst output array of the same size and type and the same number of channels as src.
@param thresh threshold value.
@param maxval maximum value to use with the #THRESH_BINARY and #THRESH_BINARY_INV thresholding
types.
@param type thresholding type (see #ThresholdTypes).
@return the computed threshold value if Otsu's or Triangle methods used.@sa adaptiveThreshold, findContours, compare, min, max*/
CV_EXPORTS_W double threshold( InputArray src, OutputArray dst, double thresh, double maxval, int type );
该函数threshold将固定级别的阈值设置应用于多通道阵列。该函数通常用于从灰度图像中获得双层(二进制)图像或用于去除噪声,即过滤掉太小或太大的像素价值观该函数支持多种类型的阈值处理。它们由类型参数。此外,特殊值#THRESH_OTSU或#THRESH-TRIANGLE可以与以上值。在这些情况下,函数使用Otsu或三角算法,并使用它来代替指定的阈值。注意:目前,Otsu和Triangle方法仅适用于8位单通道图像。
1.2threshold的操作类型
如果对卷积核有所了解的话,也可以把阀值操作看做是一个用1*1的核进行卷积,对每个像素进行一次非线性操作。
在OpenCV中,阀值操作有五种类型(int type),分别是:
- THRESH_BINARY = 0:二值化,大于阈值的为255,小于阈值的为0。
- THRESH_BINARY_INV = 1:反二值化,大于阈值的为0,小于阈值的为255。
- THRESH_TRUNC = 2:截断法,大于阈值的取阈值,小于阈值的不变。
- THRESH_TOZERO = 3:大于阈值的不变,小于阈值的为0。
- THRESH_TOZERO_INV = 4:大于阈值的为0,小于阈值的不变。
在使用时可以根据实际需求选择相应的类型。
1.3Otsu算法
函数cv::threshold可以自动决定最优的阀值,只需要对参数thresh传递THRESH_OTSU。Otsu算法是一种确定图像二值化最优阈值的算法,其原理是利用最大类间方差法来确定图像的阈值,从而将图像分割成前景和背景两部分。
Otsu算法的基本思想是:假设输入图像的高为、宽为,代表其归一化所获得的图像灰度直方图,代表灰度值等于的像素点的个数在图像中占的比例。首先,计算灰度直方图的零阶累积矩(也称为累加直方图)和一阶累积矩;然后,计算图像总体的灰度平均值,其实就是时的一阶累积矩;接着,对于每个灰度级作为阈值,计算前景区域的平均灰度、背景区域的平均灰度和整幅图像的平均灰度的方差,对方差的衡量采用以下度量;最后,找到使类间方差最大时的对应的灰度级作为最优阈值。
Otsu算法是一种自适应阈值确定的方法,计算简单,效率高,但对于光照不均的图像处理效果不是很好。
二、样例开发
2.1 Makefile
关于opencv编辑及库生成、调用等请参考本专栏的前面博文,这里不展开。 编译命令:mingw32-make -j4或make -4。
#/bin/sh
CX= g++ BIN := ./
TARGET := transform_img1.exe
FLAGS := -std=c++11 -static
SRCDIR := ./
#INCLUDES
INCLUDEDIR := -I"../../opencv_MinGW/include"
#-I"$(SRCDIR)"
staticDir := ../../opencv_MinGW/x64/mingw/staticlib/
#LIBDIR := $(staticDir)/libopencv_world460.a\
# $(staticDir)/libade.a \
# $(staticDir)/libIlmImf.a \
# $(staticDir)/libquirc.a \
# $(staticDir)/libzlib.a \
# $(wildcard $(staticDir)/liblib*.a) \
# -lgdi32 -lComDlg32 -lOleAut32 -lOle32 -luuid
#opencv_world放弃前,然后是opencv依赖的第三方库,后面的库是MinGW编译工具的库LIBDIR := -L $(staticDir) -lopencv_world460 -lade -lIlmImf -lquirc -lzlib \-llibjpeg-turbo -llibopenjp2 -llibpng -llibprotobuf -llibtiff -llibwebp \-lgdi32 -lComDlg32 -lOleAut32 -lOle32 -luuid
source := $(wildcard $(SRCDIR)/*.cpp) $(TARGET) :$(CX) $(FLAGS) $(INCLUDEDIR) $(source) -o $(BIN)/$(TARGET) $(LIBDIR)clean:rm $(BIN)/$(TARGET)
2.2 main.cpp
#include "opencv2/opencv.hpp" //Include file for every supported OpenCV function
#include <iostream>
#include <vector>
using namespace std;
//阀值化
void sum_rgb1( const cv::Mat& src, cv::Mat& dst )
{// Split image onto the color planes//vector< cv::Mat> planes;cv::split(src,planes);cv::Mat b = planes[0],g = planes[1],r = planes[2],s;// Add equally weighted rgb values//cv::addWeighted( r,1./3., g,1./3., 0.0,s );cv::addWeighted( s,1., b,1./3.,0.0,s );// Truncate values above 100//cv::threshold( s,dst,100,100,cv::THRESH_TRUNC );
}
//组合与阀值图像平面
void sum_rgb2( const cv::Mat& src,cv::Mat& dst )
{// Split image onto the color planes//vector<cv::Mat> planes;cv::split(src,planes);cv::Mat b = planes[0],g = planes[1],r= planes[2];// Accumulate separate planes, combine and threshold//cv::Mat s = cv::Mat::zeros(b.size(),CV_32F);cv::accumulate(b,s);cv::accumulate(g,s); cv::accumulate(r,s);// Truncate values above 100 and rescale into dst.cv::threshold( s,s,100,100,cv::THRESH_TRUNC );s.convertTo(dst,b.type());
}void help()
{cout <<"Call: ./1.PNG"<< endl;cout << "Shows use of alpha blending (addweighted) and threshold" << endl;
}int main(int argc,char** argv){help();if(argc< 2){ cout <<"specify input image" << endl; return -1;}// Load the image from the given file name//cv::Mat src = cv::imread( argv[1] ),dst;if( src.empty() ){cout << "can not load " << argv[1] << endl; return -1;}// sum_rgb1( src,dst);sum_rgb2( src,dst);// Create a named window with the name of the fle and// show the image in the window1cv::imshow( argv[1],dst );// Idle until the user hits any key//cv::waitKey(0);return 0;
}
2.3 运行效果
三、OpenCV-自适应阀值操作
3.1 自适应阀值操作函数-adaptiveThreshold
自适应阀值操作adaptiveThreshold和前面的阀值化方法不同,其阀值在整个过程中自动产生变化。同样在在\opencv2\imgproc.hpp中定义。在OpenCV中,自适应阈值操作是一种更为高级的阈值处理方法,用于处理具有非均匀亮度的图像。自适应阈值操作的基本思想是:对于每个像素,都使用其邻域的像素值来计算其阈值。这个邻域的像素值通常包括该像素周围的8个或16个像素。这种方法的优点是能够更好地适应图像的非均匀亮度。
@param src Source 8-bit single-channel image.
@param dst Destination image of the same size and the same type as src.
@param maxValue Non-zero value assigned to the pixels for which the condition is satisfied
@param adaptiveMethod Adaptive thresholding algorithm to use, see #AdaptiveThresholdTypes.
The #BORDER_REPLICATE | #BORDER_ISOLATED is used to process boundaries.
@param thresholdType Thresholding type that must be either #THRESH_BINARY or #THRESH_BINARY_INV,
see #ThresholdTypes.
@param blockSize Size of a pixel neighborhood that is used to calculate a threshold value for the
pixel: 3, 5, 7, and so on.
@param C Constant subtracted from the mean or weighted mean (see the details below). Normally, it
is positive but may be zero or negative as well.@sa threshold, blur, GaussianBlur*/
CV_EXPORTS_W void adaptiveThreshold( InputArray src, OutputArray dst,double maxValue, int adaptiveMethod,int thresholdType, int blockSize, double C );参数:src:输入图像,应该是灰度图像。dst:输出图像maxValue:输出图像的最大值。adaptiveMethod:自适应阈值算法的选择,可以是ADAPTIVE_THRESHOLD_MEAN_C或ADAPTIVE_THRESHOLD_GAUSSIAN_C。thresholdType:阈值类型,通常是THRESH_BINARY或THRESH_BINARY_INV。blockSize:用于计算阈值的邻域大小。C:加到阈值上的常数,以调整阈值。
cv::adaptiveThreshold()根据adaptiveMethod的设置,允许两种不同的自适应阙值方法。两种方法都是逐个像素地计算自适应阙值T(x,y),方法是通过计算每个像素位置周围的b*b区域的加权平均值然后减去常数C,其中b由blocksize给定。不同的是,如果选择的均值方法是cv::ADAPTIVE THRESH MEAN C,那么均值时取得权值是相等的,如果选择的均值方法是cv::ADAPTIVE THRESH GAUSSIAN C(x,y)周围的像素的权值则根据其到中心点的距离通过高斯方程得到。
对于thresholdType阈值类型来说 ,adaptiveThreshold函数的类型和threshold函数的类型相同。相对于一般的闽值化操作,当图像中出现较大的明暗差异时,自适应闽值时非常有效的。这个函数仅处理单通道8位或浮点型图像,并且要求源图像和目标图像不同。
3.2 样例开发
Makefile文件,与前面的Makefile文件几乎一致,仅将输出程序名调整一下:
#TARGET := transform_img1.exe
TARGET := transform_img2.exe
编译命令:mingw32-make -j4或make -4
main.cpp实现
#include "opencv2/opencv.hpp" //Include file for every supported OpenCV function #include<iostream>
using namespace std;
int main( int argc,char** argv )
{if(argc != 7){ cout <<"Usage:"<<argv[0] <<"fixed_threshold invert(0=offl1=on)""adaptive_type(0=mean]1=gaussian) block_size offset image\n""Example:"<<argv[0] <<"100 1 0 15 10 1.PNG"; return -1;}// Command linedouble fixed_threshold = (double)atof(argv[1]);int threshold_type = atoi(argv[2]) ? cv::THRESH_BINARY : cv::THRESH_BINARY_INV;int adaptive_method = atoi(argv[3]) ? cv::ADAPTIVE_THRESH_MEAN_C : cv::ADAPTIVE_THRESH_GAUSSIAN_C;int block_size = atoi(argv[4]);double offset =(double)atof(argv[5]);cv::Mat Igray = cv::imread(argv[6], cv::IMREAD_GRAYSCALE);// Read in gray image//if( Igray.empty() ){ cout << "Can not load " << argv[6] << endl; return -1; }// Declare the output images.//cv::Mat It,Iat;// Thresholdscv::threshold(Igray,It,fixed_threshold,255,threshold_type);cv::adaptiveThreshold(Igray,Iat ,255,adaptive_method,threshold_type,block_size,offset );// Show the results.//cv::imshow("Raw",Igray);cv::imshow("Threshold",It);cv::imshow("Adaptive Threshold",Iat);cv::waitKey(0);return 0;
}
运行效果如下: