本文主要讲解实现自定义的二值化功能以及讲解OpenCV中的二值化函数adaptiveThreshold
和threshold
来达到同样的目的,当然还有其他的二值化函数也可以达到同样的目的。
OpenCV提供了全局固定阈值
和局部自适应阈值
的函数来实现二值化图像。
全局二值化方法(Global Binariztion Method)对每一幅图计算一个单一的阀值。灰度级大于阈值的像素被标记为背景色,否则为前景。
局部二值化方法(Local Adaptive Binarization Method)以像素的邻域的信息为基础来计算每一个像素的阈值。其中一些方法还会计算整个图像中的一个阈值面。如果图像中的一个像素(x,y)的灰度级高于在(x,y)点的阈值面的计算值,那么把像素(x,y)标记为背景,否则为前景字符。
C++:
void adaptiveThreshold(InputArray src, OutputArray dst, double maxValue, int adaptiveMethod, int thresholdType, int blockSize, double C)
C:
void cvAdaptiveThreshold(const CvArr* src, CvArr* dst, double max_value, int adaptive_method=CV_ADAPTIVE_THRESH_MEAN_C, int threshold_type=CV_THRESH_BINARY, int block_size=3, double param1=5 )
参数说明:
src:单通道的输入图像
dst:和输入图像同类型的输出图像
maxValue: 二值化后非零的最大值设置,二值,顾名思义有两个值,一个是零,一个是(0~256)之间的值。具体和阈值类型搭配说明见下面。
adaptiveMethod:自适应阈值算法选择:CV_ADAPTIVE_THRESH_MEAN_C 或CV_ADAPTIVE_THRESH_GAUSSIAN_C。具体说明见下面。
thresholdType:阈值类型,下面有详细选择说明。注意,adaptiveThreshold方法只支持前两个参数
blockSize:用来计算每个像素的阈值的邻域大小,如3,5,7等。
C:从adaptiveMethod选择的方法中计算出来的平均值或加权平均值减去的参数值,可以是正数或负数。区别C方式函数,没有默认值。
详细说明:
THRESH_BINARY/CV_THRESH_BINARY
THRESH_BINARY_INV/CV_THRESH_BINARY_INV
THRESH_TRUNC/CV_THRESH_TRUNC
THRESH_TOZERO/CV_THRESH_TOZERO
THRESH_TOZERO_INV/CV_THRESH_TOZERO_INV
上面的前两个参数是用于自适应阈值的函数。imgpro.hpp
和types_c.h
中有定义枚举变量:
enum
{
CV_THRESH_BINARY=0,/*value=value>threshold?max_value:0*/
CV_THRESH_BINARY_INV=1,/*value=value>threshold?0:max_value*/
CV_THRESH_TRUNC=2,/*value=value>threshold?threshold:value*/
CV_THRESH_TOZERO=3,/*value=value>threshold?value:0*/
CV_THRESH_TOZERO_INV=4,/*value=value>threshold?0:value*/
CV_THRESH_MASK=7,
CV_THRESH_OTSU=8/*useOtsualgorithmtochoosetheoptimalthresholdvalue;
combinetheflagwithoneoftheaboveCV_THRESH_*values*/
};
//!typeofthethresholdoperation
enum{
THRESH_BINARY=CV_THRESH_BINARY,
THRESH_BINARY_INV=CV_THRESH_BINARY_INV,
THRESH_TRUNC=CV_THRESH_TRUNC,
THRESH_TOZERO=CV_THRESH_TOZERO,
THRESH_TOZERO_INV=CV_THRESH_TOZERO_INV,
THRESH_MASK=CV_THRESH_MASK,
THRESH_OTSU=CV_THRESH_OTSU
};
T(x,y)为图像中每一个像素的阈值。可以看作是一种电路上的滤波方式,第一种为比较器。OTSU算法(大津法或最大类间方差法)。图像直观理解:
ADAPTIVE_THRESH_MEAN_C
方法:blockSize块的均值减去C作为阈值T(x,y)。
ADAPTIVE_THRESH_GAUSSIAN_C
方法:加权平均值(默认为标准差)减去C作为阈值T(x,y)。
C++:
double threshold(InputArray src, OutputArray dst, double thresh, double maxval, int type)
C:
double cvThreshold(const CvArr* src, CvArr* dst, double threshold, double max_value, int threshold_type)
参数说明:
maxval:二值最大值
thresh:固定阈值大小
type:阈值计算方式类型,同上。
自己实现简单的二值化功能(类似固定阈值方式,非0即255)。可以读取彩色图像,因为距离计算是求取了三个通道的,这一点不同于OpenCV提供的二值化函数必须为单通道图像。原理简单,就是通过对每个像素跟设定的固定值进行距离比较,在设定的距离范围内就将其设置为二值的某个值。
OpenCV动态库加入到工程配置文件中
xxx.pro
INCLUDEPATH += E:\OpenCV2_4_11_MinGW\include
LIBS+=-LE:\\OpenCV2_4_11_MinGW\\bin\
libopencv_core2411\
libopencv_highgui2411\
libopencv_imgproc2411\
libopencv_features2d2411\
libopencv_calib3d2411\
计算当前像素点与设定的目标像素点的距离
计算方法有很多,常见的有欧几里得距离、曼哈顿距离(街区距离)、闵科夫斯基距离等。这里用的是曼哈顿距离计算公式。
int ColorDetector::getDistance(const Vec3b& color) const
{
return abs(color[0] - target[0]) +
abs(color[1] - target[1]) +
abs(color[2] - target[2]);
}
对图像进行二值化处理
二值画处理的原理就是计算当前像素与设定的像素的距离是否在我们设定的阈值距离minDist
之内,是则将像素点置为255,否则置为0。
Mat ColorDetector::process(const Mat image)
{
int count = 0;
//按需重新分配二值图像
//与输入图像的尺寸相同,但是只有一个通道(二值化)
result.create(image.rows,image.cols,CV_8U);
Mat_<Vec3b>::const_iterator it =
image.begin<Vec3b>();
Mat_<Vec3b>::const_iterator itend =
image.end<Vec3b>();
Mat_<uchar>::iterator itout =
result.begin<uchar>();
for(;it!= itend;++it,++itout){
count++;
if(getDistance(*it) < minDist){
*itout = 255;
}
else {
*itout = 0;
}
}
return result;
}
最后得到二值化结果
二值化的结果要很好的话是跟设定的像素点的BGR值和阈值距离有关的。
基于库函数就比较容易了。
全局固定阈值关键代码:
void MainWindow::on_pushButton_2_clicked()
{
if(!image.data)return ;
Mat result;
//创建同原始图像等大小的图像空间
result.create(image.rows,image.cols,CV_8U);
//二值化
//CV_THRESH_OTSU参数自动生成阈值,跟第三个参数也就没有关系了。
threshold(image,result,0,255, CV_THRESH_BINARY | CV_THRESH_OTSU);
//获取处理后的结果
if(!result.data){
return ;
}
//转为QImage格式。注意这不需要用cvtColor()函数来转换格式,因为process中就是二值化图像了,即只有一个通道。
QImage img = QImage((const unsigned char*)(result.data),
result.cols,result.rows,result.cols*result.channels(),QImage::Format_Grayscale8);
//显示到label上
ui->label_2->setPixmap(QPixmap::fromImage(img));
ui->label_2->resize(ui->label_2->pixmap()->size());
}
局部自适应阈值关键代码:
void MainWindow::on_pushButton_3_clicked()
{
if(!image.data)return ;
Mat result;
//创建同原始图像等大小的图像空间
result.create(image.rows,image.cols,CV_8U);
//自适应二值化
adaptiveThreshold(image,result,255,CV_ADAPTIVE_THRESH_GAUSSIAN_C,CV_THRESH_BINARY,3,5);
//获取处理后的结果
if(!result.data){
return ;
}
//转为QImage格式。注意这不需要用cvtColor()函数来转换格式,因为process中就是二值化图像了,即只有一个通道。
QImage img = QImage((const unsigned char*)(result.data),
result.cols,result.rows,result.cols*result.channels(),QImage::Format_Grayscale8);
//显示到label上
ui->label_3->setPixmap(QPixmap::fromImage(img));
ui->label_3->resize(ui->label_3->pixmap()->size());
}
结果:
当然,我们还可以多测试下不同的参数会有什么影响。
测试源码下载:
http://download.csdn.net/download/freeape/9378465
参考资料:
http://docs.opencv.org/2.4/modules/imgproc/doc/miscellaneous_transformations.html?highlight=cvadaptivethreshold
http://blog.csdn.net/tyf122/article/details/8738156
本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。