目录
一、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 window1
cv::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 line
double 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;
// Thresholds
cv::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;
}
运行效果如下: