阈值化
阈值化的基本思想是:给定一个数组和一个阈值,然后根据数组中的每个元素是低于还是高于阈值而进行一些处理。
函数声明:
Threshold
对数组元素进行固定阈值操作
void cvThreshold( const CvArr* src, CvArr* dst, double threshold, double max_value, int threshold_type );
-
src
- 原始数组 (单通道 , 8-bit of 32-bit 浮点数). dst
- 输出数组,必须与 src 的类型一致,或者为 8-bit. threshold
- 阈值 max_value
- 使用 CV_THRESH_BINARY 和 CV_THRESH_BINARY_INV 的最大值. threshold_type
- 阈值类型 (见讨论)
函数 cvThreshold 对单通道数组应用固定阈值操作。该函数的典型应用是对灰度图像进行阈值操作得到二值图像。(cvCmpS 也可以达到此目的) 或者是去掉噪声,例如过滤很小或很大象素值的图像点。本函数支持的对图像取阈值的方法由 threshold_type 确定:
threshold_type=CV_THRESH_BINARY: dst(x,y) = max_value, if src(x,y)>threshold 0, otherwise threshold_type=CV_THRESH_BINARY_INV: dst(x,y) = 0, if src(x,y)>threshold max_value, otherwise threshold_type=CV_THRESH_TRUNC: dst(x,y) = threshold, if src(x,y)>threshold src(x,y), otherwise threshold_type=CV_THRESH_TOZERO: dst(x,y) = src(x,y), if (x,y)>threshold 0, otherwise threshold_type=CV_THRESH_TOZERO_INV: dst(x,y) = 0, if src(x,y)>threshold src(x,y), otherwise
下面是图形化的阈值描述:
实现代码:
/*
* 阈值化
*/
#include "highgui.h"
#include "cv.h"
#include<stdio.h>
void sum_rgb(IplImage* img, IplImage* dst);
void doThreshold(IplImage* img)
{
IplImage* dst = cvCreateImage(
cvGetSize(img),
img->depth,
1
);
sum_rgb(img,dst);
cvNamedWindow("thresh");
cvShowImage("thresh",dst);
while(1)
{
if((cvWaitKey(10) & 0x7f) == 27)
{
break;
}
}
cvDestroyWindow("thresh");
cvReleaseImage(&img);
cvReleaseImage(&dst);
}
void sum_rgb(IplImage* img, IplImage* dst)
{
IplImage* r = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1);
IplImage* g = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1);
IplImage* b = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1);
cvSplit(img, r, g, b, NULL);
IplImage* s = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1);
cvAddWeighted(r, 1./3., g, 1./3., 0.0, s);
cvAddWeighted(s, 2./3., b, 1./3., 0.0, s);
//IplImage* s = cvCreateImage(cvGetSize(img), IPL_DEPTH_32F, 1);
//cvZero(s);
//cvAcc(b,s);
//cvAcc(g,s);
//cvAcc(r,s);
cvThreshold(s, dst, 100, 100, CV_THRESH_TRUNC);
//cvConvertScale(s, dst, 1,0);
cvReleaseImage(&r);
cvReleaseImage(&g);
cvReleaseImage(&b);
cvReleaseImage(&s);
}
实现结果:
用注释部分的程序替换:另一种组合不同通道,并阈值化图像的方法
/*
* 阈值化
*/
#include "highgui.h"
#include "cv.h"
#include<stdio.h>
void sum_rgb(IplImage* img, IplImage* dst);
void doThreshold(IplImage* img)
{
IplImage* dst = cvCreateImage(
cvGetSize(img),
img->depth,
1
);
sum_rgb(img,dst);
cvNamedWindow("thresh");
cvShowImage("thresh",dst);
while(1)
{
if((cvWaitKey(10) & 0x7f) == 27)
{
break;
}
}
cvDestroyWindow("thresh");
cvReleaseImage(&img);
cvReleaseImage(&dst);
}
void sum_rgb(IplImage* img, IplImage* dst)
{
IplImage* r = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1);
IplImage* g = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1);
IplImage* b = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1);
cvSplit(img, r, g, b, NULL);
//IplImage* s = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1);
//cvAddWeighted(r, 1./3., g, 1./3., 0.0, s);
//cvAddWeighted(s, 2./3., b, 1./3., 0.0, s);
IplImage* s = cvCreateImage(cvGetSize(img), IPL_DEPTH_32F, 1);
cvZero(s);
cvAcc(b,s);
cvAcc(g,s);
cvAcc(r,s);
cvThreshold(s, dst, 100, 100, CV_THRESH_TRUNC);
cvConvertScale(s, dst, 1,0);
cvReleaseImage(&r);
cvReleaseImage(&g);
cvReleaseImage(&b);
cvReleaseImage(&s);
}
结果:
自适应阈值
这是一种改进的阈值技术,其中阈值本身是一个变量。
函数声明:
AdaptiveThreshold
自适应阈值方法
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
- 输出图像. max_value
- 使用 CV_THRESH_BINARY 和 CV_THRESH_BINARY_INV 的最大值. adaptive_method
- 自适应阈值算法使用:CV_ADAPTIVE_THRESH_MEAN_C 或 CV_ADAPTIVE_THRESH_GAUSSIAN_C (见讨论). threshold_type
-
取阈值类型:必须是下者之一
- CV_THRESH_BINARY,
- CV_THRESH_BINARY_INV
-
block_size
- 用来计算阈值的象素邻域大小: 3, 5, 7, ... param1
- 与方法有关的参数。对方法 CV_ADAPTIVE_THRESH_MEAN_C 和 CV_ADAPTIVE_THRESH_GAUSSIAN_C, 它是一个从均值或加权均值提取的常数(见讨论), 尽管它可以是负数。
函数 cvAdaptiveThreshold 将灰度图像变换到二值图像,采用下面公式:
threshold_type=CV_THRESH_BINARY: dst(x,y) = max_value, if src(x,y)>T(x,y) 0, otherwise threshold_type=CV_THRESH_BINARY_INV: dst(x,y) = 0, if src(x,y)>T(x,y) max_value, otherwise
其中 TI 是为每一个象素点单独计算的阈值
对方法 CV_ADAPTIVE_THRESH_MEAN_C,先求出块中的均值,再减掉param1。
对方法 CV_ADAPTIVE_THRESH_GAUSSIAN_C ,先求出块中的加权和(gaussian), 再减掉param1。
实现代码:
/*
* 自适应阈值
*/
#include "cv.h"
#include "highgui.h"
#include "math.h"
void doAdaptThreshold(IplImage* img)
{
IplImage* Igray = 0;
IplImage* It = 0;
IplImage* Iat;
Igray = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1);
cvCvtColor(img,Igray,CV_RGB2GRAY);
It = cvCreateImage(cvSize(Igray->width,Igray->height), IPL_DEPTH_8U, 1);
Iat = cvCreateImage(cvSize(Igray->width, Igray->height), IPL_DEPTH_8U, 1);
cvThreshold(Igray, It, 150, 255, CV_THRESH_BINARY);
cvAdaptiveThreshold(Igray, Iat, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, 3, 5);
cvNamedWindow("raw",1);
cvNamedWindow("Threshold",1);
cvNamedWindow("Ada", 1);
cvShowImage("raw", Igray);
cvShowImage("Threshold", It);
cvShowImage("Ada", Iat);
cvWaitKey(0);
cvReleaseImage(&Igray);
cvReleaseImage(&It);
cvReleaseImage(&Iat);
cvDestroyWindow("raw");
cvDestroyWindow("Threshold");
cvDestroyWindow("Ada");
}
第一张图为原图的灰度图
第二张图为二值阈值化
第三张为自适应二值阈值化