opencv实现c++的otsu自适应阈值分割的算法描述
- 格式:docx
- 大小:20.99 KB
- 文档页数:7
图像二值化----otsu(最大类间方差法、大津算法)
最大类间方差法是由日本学者大津于1979年提出的,是一种自适应的阈值确定的方法,又叫大津法,简称OTSU。
它是按图像的灰度特性,将图像分成背景和目标两部分。
背景和目标之间的类间方差越大,说明构成图像的两部分的差别越大,当部分目标错分为背景或部分背景错分为目标都会导致两部分差别变小。
因此,类间方差最大的分割意味着错分概率最小。
OTSU被认为是图像分割中阈值选取的最佳算法,计算简单,不受图像亮度和对比度的影响,因此在数字图像处理上得到了广泛的应用。
Otsu算法步骤如下:
设图象包含L个灰度级(0,1…,L-1),灰度值为i的的象素点数为Ni ,图象总的象素点数为N=N0+N1+...+N(L-1)。
灰度值为i的点的概为:
P(i) = N(i)/N.
门限t将整幅图象分为暗区c1和亮区c2两类,则类间方差σ是t的函数:
σ=a1*a2(u1-u2)^2 (2)
式中,aj 为类cj的面积与图象总面积之比,a1 = sum(P(i)) i->t, a2 = 1-a1; uj 为类cj的均值,u1 = sum(i*P(i))/a1 0->t,
u2 = sum(i*P(i))/a2, t+1->L-1
该法选择最佳门限t^ 使类间方差最大,即:令Δu=u1-u2,σb = max{a1(t)*a2(t)Δu^2}。
Otsu算法是一种自适应的二值化方法,其主要思想是将图像分成背景和前景两部分,使得背景和前景之间的类间方差最大,而背景和前景内部的类内方差最小。
具体实现步骤如下:
统计图像的灰度直方图,得到每个灰度级别的像素数量。
计算每个灰度级别的归一化概率和平均灰度值。
遍历所有灰度级别,计算每个灰度级别的类内方差和类间方差。
选择使类间方差最大的灰度级别作为阈值进行二值化。
将图像中小于阈值的像素设为0,大于等于阈值的像素设为255。
通过Otsu 算法,可以得到一个自适应的二值化阈值,能够有效地将背景和前景分离,提高图像的对比度和清晰度,常用于图像分割和边缘检测等领域。
opencv 动态阈值算法OpenCV(Open Source Computer Vision)是一个开放源代码的计算机视觉库,包含了超过2500个优化的算法和超过500个示例。
OpenCV提供了动态阈值算法来处理图像。
动态阈值算法是一种自适应的方法,根据图像的局部特征来确定每个像素点的阈值。
这种方法可以有效地处理光照不均匀或者背景杂乱的图像。
OpenCV提供了几种常用的动态阈值算法,包括:1. 自适应高斯阈值法(cv2.ADAPTIVE_THRESH_GAUSSIAN_C):根据感兴趣区域周围的像素点确定阈值,使用高斯加权平均来获取感兴趣区域的阈值。
2. 自适应均值阈值法(cv2.ADAPTIVE_THRESH_MEAN_C):与高斯阈值法类似,但是使用的是平均值来获取感兴趣区域的阈值。
这些算法都可以通过cv2.adaptiveThreshold()函数来实现。
函数的参数包括输入图像、输出图像、阈值类型、块的大小(用于指定感兴趣区域的大小)、常数C(用于调整阈值)等。
以下是一个示例代码:```import cv2img = cv2.imread('input.jpg', 0)# 自适应高斯阈值处理th1 = cv2.adaptiveThreshold(img, 255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, \cv2.THRESH_BINARY, 11, 2)# 自适应均值阈值处理th2 = cv2.adaptiveThreshold(img, 255,cv2.ADAPTIVE_THRESH_MEAN_C, \cv2.THRESH_BINARY, 11, 2)cv2.imshow('Original Image', img)cv2.imshow('Adaptive Gaussian Thresholding', th1)cv2.imshow('Adaptive Mean Thresholding', th2)cv2.waitKey(0)cv2.destroyAllWindows()```在上面的示例中,我们首先通过cv2.imread()函数读取输入图像,然后分别使用自适应高斯阈值法和自适应均值阈值法进行处理,最后使用cv2.imshow()函数显示原始图像和处理后的图像。
阈值分割公式阈值分割公式阈值分割是一种常用的图像处理技术,它可以将图像根据给定的阈值进行二值化处理,使得图像中的目标物体与背景色彩有所区分,便于后续的处理。
随着图像处理技术的不断发展,阈值分割也不断完善,其中最常用的就是基于阈值的分割公式。
一、常见阈值分割算法1. Otsu阈值法Otsu是一种基于直方图的阈值分割方法,它的基本思想是寻找一个最佳阈值,使得图像中目标物体与背景的差异最大化。
这种方法适用于灰度图像,具有较好的分割效果。
Otsu算法的计算公式如下:$$\sigma^2(w_0,w_1) =w_0(t)\sigma^2_0(t)+w_1(t)\sigma^2_1(t)$$2. 最大熵阈值法最大熵阈值法是一种基于信息熵的阈值分割方法,它通过最大化图像的熵值,来确定最佳阈值。
这种方法适用于处理具有复杂背景的图像,它的计算公式如下:$$\max H(T)= - \sum_{i=1}^{k}p_i\log_2(p_i)$$3. 基于聚类的阈值分割法基于聚类的阈值分割法是一种就是把原始图像分成若干个子集,使得每个子集都包含一部分图像的像素值,从而将图像进行分割。
它计算每个子集的灰度均值和方差来确定分割阈值,公式如下:$$\max \varepsilon(i)=\frac{(T*\mu_i-\mu)^2}{T*\sigma_i^2+(1-T)*\sigma_{i+1}^2}$$二、阈值分割的应用阈值分割在实际应用中广泛,例如人脸识别、车牌号识别等。
通过对图像二值化处理可以提高算法的精度,使得对目标物体的检测更加准确。
例如,在车牌号识别中,阈值分割可以先进行图像二值化处理,再进行腐蚀、膨胀等操作,从而将车牌号与背景进行分离,然后再进行字符识别等操作,提高了算法的效率和准确性。
三、总结阈值分割是图像处理中最为常见和实用的方法之一,其应用范围广泛,通过选择不同的阈值分割算法和参数,可以实现不同的图像处理任务。
opencv adaptivethreshold参数详解OpenCV自适应阈值参数详解OpenCV(Open Source Computer Vision Library)是一个开源的跨平台计算机视觉库,广泛应用于图像处理和计算机视觉领域。
在OpenCV 中,自适应阈值(Adaptive Threshold)是一种常用的图像二值化方法,它可以根据图像不同区域的亮度分布自动选择合适的阈值进行二值化处理。
本文将详细介绍OpenCV中自适应阈值的参数及其作用。
1. 图像二值化简介图像二值化是将图像从灰度或彩色转换为二值图像的过程,即将图像的每个像素点转换为黑白两种颜色。
这种处理方法可以大大简化图像处理和分析的复杂度,提取出感兴趣的目标物体。
2. 自适应阈值原理自适应阈值根据图像不同区域的亮度分布自动选择阈值,以便更好地适应图像的局部变化。
它首先将图像分割为多个块(或称为子区域),然后针对每个子区域分别计算阈值。
这样可以针对不同亮度的区域进行不同的处理,提高二值化的效果。
3. 自适应阈值函数在OpenCV中,自适应阈值函数的原型如下:```cv2.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C)```参数解释:- src:输入图像,单通道灰度图像。
- maxValue:像素的最大值,当阈值类型为cv2.THRESH_BINARY 或cv2.THRESH_BINARY_INV时,将超过阈值的像素值设置为该最大值。
- adaptiveMethod:自适应方法,有两个选择:cv2.ADAPTIVE_THRESH_MEAN_C和cv2.ADAPTIVE_THRESH_GAUSSIAN_C。
- thresholdType:阈值类型,有两个选择:cv2.THRESH_BINARY 和cv2.THRESH_BINARY_INV。
自适应阈值处理
自适应阈值处理是一种图像处理技术,用于自动确定图像分割的阈值。
这种方法通常用于二值化图像,将像素值分为两类:高于阈值的像素和低于阈值的像素。
在传统的阈值处理中,阈值是固定的,这意味着它不会根据图像的局部特性进行调整。
然而,在许多情况下,图像的亮度和对比度可能会在不同的区域中有所不同,这就需要一个能够自适应地调整阈值的方法。
自适应阈值处理通过计算图像的局部统计信息(如均值或中值)来确定每个像素的阈值。
这种方法可以确保阈值能够适应图像的局部变化,从而得到更准确的二值化结果。
OpenCV库提供了自适应阈值处理的函数,如
`cv2.adaptiveThreshold()`。
这个函数接受一个源图像、最大值、自适应方法、阈值类型和块大小等参数。
其中,自适应方法可以是
`cv2.ADAPTIVE_THRESH_MEAN_C`或
`cv2.ADAPTIVE_THRESH_GAUSSIAN_C`,分别表示使用均值或高斯加权和作为阈值。
块大小参数指定了用于计算阈值的邻域大小。
自适应阈值处理在许多图像处理应用中都非常有用,例如文档扫描、车牌识别、图像分割等。
通过使用自适应阈值处理,可以更准确地提取图像中的有用信息,从而提高后续处理的准确性和效率。
openCV实现图像分割本次实验为⼤家分享了openCV实现图像分割的具体实现代码,供⼤家参考,具体内容如下⼀.实验⽬的进⼀步理解图像的阈值分割⽅法和边缘检测⽅法的原理。
掌握图像基本全局阈值⽅法和最⼤类间⽅差法(otsu法)的原理并编程实现。
编程实现图像的边缘检测。
⼆.实验内容和要求编程实现图像阈值分割(基本全局阈值⽅法和otsu法)和边缘检测。
三.实验主要仪器设备和材料计算机,VS2017+OpenCV四.实验原理与⽅法图像的阈值分割的基本原理图像的⼆值化处理图像分割中的⼀个主要内容,就是将图像上的点的灰度置为0或255,也就是讲整个图像呈现出明显的⿊⽩效果。
⽤I表⽰原图,R表⽰⼆值化后的图,则⼆值化的过程可以⽤以下公式表⽰:thr表⽰选取的阈值。
⼆值化的过程就是当原图的像素灰度值⼤于阈值就将其变⽩,否则就将其变⿊。
即将256个亮度等级的灰度图像通过适当的阀值选取⽽将图像变为⼆个级别灰度级,这样只有⼆个灰度级的图像在图像处理分析过程中占有⾮常重要的地位,特别是在实⽤的图像处理中。
根据对全图使⽤统⼀阈值还是对不同区域使⽤不同阈值,可以分为全局阈值⽅法(global thresholding)和局部阈值⽅法(local thresholding,也叫做⾃适应阈值⽅法adaptive thresholding);这种与坐标相关的阈值也叫动态阈值,具体的⽅法,可以参考相关的图像处理书籍。
1、基本全局阈值⽅法,即在整个图像中所有的象素点,其阈值thr相同,具体步骤为:(1)选取⼀个初始估计值T;(2)⽤T分割图像。
这样便会⽣成两组像素集合:G1由所有灰度值⼤于T的像素组成,⽽G2由所有灰度值⼩于或等于T的像素组成。
(3)对G1和G2中所有像素计算平均灰度值u1和u2。
(4)计算新的阈值:T=(u1 + u2)/2。
(5)重复步骤(2)到(4),直到得到的T值之差⼩于⼀个事先定义的参数T0。
2、Otsu⽅法的算法步骤为:(1)先计算图像的归⼀化直⽅图;(2)i表⽰分类的阈值,也即⼀个灰度级,从0开始迭代;(3)通过归⼀化的直⽅图,统计0~i 灰度级的像素(背景像素) 所占整幅图像的⽐例w0,并统计背景像素的平均灰度u0;统计i~255灰度级的像素(前景像素) 所占整幅图像的⽐例w1,并统计前景像素的平均灰度u1;(4)计算前景像素和背景像素的⽅差 g = w0w1(u0-u1) (u0-u1)(5)i++,直到i为256时结束迭代;(6)将最⼤g相应的i值作为图像的全局阈值。
ostu法计算阈值OSTU法是一种常用的图像分割方法,用于将图像分成两个部分:前景和背景。
本文将介绍OSTU法的原理和计算阈值的步骤。
一、OSTU法的原理OSTU法是基于图像的灰度直方图的分析来确定阈值的。
它的基本思想是使得图像的前景和背景之间的类间方差最大化,即使得前景和背景之间的差异最大化。
二、计算阈值的步骤1. 首先,读取图像并将其转换为灰度图像。
通过将彩色图像转换为灰度图像,可以简化计算并减少计算量。
2. 然后,计算灰度图像的直方图。
直方图表示了图像中每个灰度级的像素数量。
3. 接下来,计算每个可能的阈值下的类内方差。
类内方差是指在某个阈值下,将图像分成前景和背景两部分后,前景和背景内部的像素灰度值的方差之和。
4. 然后,计算每个可能的阈值下的类间方差。
类间方差是指在某个阈值下,将图像分成前景和背景两部分后,前景和背景之间的像素灰度值的方差。
5. 最后,选取使得类间方差最大化的阈值作为最终的分割阈值。
三、OSTU法计算阈值的优势OSTU法计算阈值的优势在于它能够自动选择最佳的阈值,而无需用户进行手动调整。
这一点尤其适用于大量图像的处理和分割任务。
四、OSTU法的应用领域OSTU法广泛应用于图像处理和计算机视觉领域。
例如,它可以用于图像分割、边缘检测、目标识别等任务中。
在医学影像领域,OSTU法也常用于肿瘤分割、血管分割等应用中。
五、OSTU法的局限性虽然OSTU法在很多情况下表现良好,但它也有一些局限性。
首先,OSTU法假设图像的前景和背景之间的差异是明显的,但在一些复杂的图像场景中,前景和背景之间的差异可能较小。
其次,OSTU 法对噪声敏感,当图像包含大量噪声时,OSTU法可能产生错误的分割结果。
六、总结OSTU法是一种常用的图像分割方法,通过使得图像的前景和背景之间的类间方差最大化来确定阈值。
它具有自动选择最佳阈值的优势,并广泛应用于图像处理和计算机视觉领域。
然而,OSTU法也有一些局限性,需要根据具体的应用场景进行选择和调整。
基于OpenCV实现图像分割本⽂实例为⼤家分享了基于OpenCV实现图像分割的具体代码,供⼤家参考,具体内容如下1、图像阈值化源代码:#include "opencv2/highgui/highgui.hpp"#include "opencv2/imgproc/imgproc.hpp"#include <iostream>using namespace std;using namespace cv;int thresholds=50;int model=2;Mat image,srcimage;void track(int ,void *){Mat result;threshold(srcimage,result,thresholds,255,CV_THRESH_BINARY);//imshow("原图",result);if(model==0){threshold(srcimage,result,thresholds,255,CV_THRESH_BINARY);imshow("分割",result);}if(model==1){threshold(srcimage,result,thresholds,255,THRESH_BINARY_INV);imshow("分割",result);}if(model==2){threshold(srcimage,result,thresholds,255,THRESH_TRUNC);imshow("分割",result);}if(model==3){threshold(srcimage,result,thresholds,255,THRESH_TOZERO);imshow("分割",result);}if(model==4){threshold(srcimage,result,thresholds,255,THRESH_TOZERO_INV);imshow("分割",result);}}int main(){image=imread("2.2.tif");if(!image.data){return 0;}cvtColor(image,srcimage,CV_BGR2GRAY);namedWindow("分割",WINDOW_AUTOSIZE);cv::createTrackbar("阈a值:","分割",&thresholds,255,track);cv::createTrackbar("模式:","分割",&model,4,track);track(thresholds,0);track(model,0);waitKey(0);return 0;}实现结果:2、阈值处理//阈值处理#include "opencv2/core/core.hpp"#include "opencv2/highgui/highgui.hpp"#include "opencv2/imgproc/imgproc.hpp"using namespace cv;using namespace std;int main(){printf("键盘按键ESC--退出程序");Mat g_srcImage = imread("1.tif",0);if(!g_srcImage.data){printf("读取图⽚失败");}imshow("原始图",g_srcImage);//⼤津法阈值分割显⽰/*⼤津法,简称OTSU.它是按图像的灰度特性,将图像分成背景和⽬标2部分。
otsu算法选择使类间方差最大的灰度值为阈值,具有很好的效果 算法具体描述见otsu论文,或冈萨雷斯著名的数字图像处理那本书 这里给出程序流程: 1、计算直方图并归一化histogram 2、计算图像灰度均值avgValue. 3、计算直方图的零阶w[i]和一级矩u[i] 4、计算并找到最大的类间方差(between-class variance) variance[i]=(avgValue*w[i]-u[i])*(avgValue*w[i]-u[i])/(w[i]*(1-w[i])) 对应此最大方差的灰度值即为要找的阈值 5、用找到的阈值二值化图像 我在代码中做了一些优化,所以算法描述的某些地方跟程序并不一致 otsu代码,先找阈值,继而二值化 // implementation of otsu algorithm // author: onezeros(@yahoo.cn) // reference: Rafael C. Gonzalez. Digital Image Processing Using MATLAB void cvThresholdOtsu(IplImage* src, IplImage* dst) { int height=src->height; int width=src->width;
//histogram float histogram[256]= {0}; for(int i=0; i{ unsigned char* p=(unsigned char*)src->imageData+src->widthStep*i; for(int j=0; j{ histogram[*p++]++; } } //normalize histogram int size=height*width; for(int i=0; i<256; i++) { histogram[i]=histogram[i]/size; }
//average pixel value float avgValue=0; for(int i=0; i<256; i++) { avgValue+=i*histogram[i]; }
int threshold; float maxVariance=0; float w=0,u=0; for(int i=0; i<256; i++) { w+=histogram[i]; u+=i*histogram[i];
float t=avgValue*w-u; float variance=t*t/(w*(1-w)); if(variance>maxVariance) { maxVariance=variance; threshold=i; } }
cvThreshold(src,dst,threshold,255,CV_THRESH_BINARY); }
更多情况下我们并不需要对每一帧都是用otsu寻找阈值,于是可以先找到阈值,然后用找到的阈值处理后面的图像。下面这个函数重载了上面的,返回值就是阈值。只做了一点改变
// implementation of otsu algorithm // author: onezeros(@yahoo.cn) // reference: Rafael C. Gonzalez. Digital Image Processing Using MATLAB int cvThresholdOtsu(IplImage* src) { int height=src->height; int width=src->width; //histogram float histogram[256]= {0}; for(int i=0; i{ unsigned char* p=(unsigned char*)src->imageData+src->widthStep*i; for(int j=0; j{ histogram[*p++]++; } } //normalize histogram int size=height*width; for(int i=0; i<256; i++) { histogram[i]=histogram[i]/size; }
//average pixel value float avgValue=0; for(int i=0; i<256; i++) { avgValue+=i*histogram[i]; }
int threshold; float maxVariance=0; float w=0,u=0; for(int i=0; i<256; i++) { w+=histogram[i]; u+=i*histogram[i];
float t=avgValue*w-u; float variance=t*t/(w*(1-w)); if(variance>maxVariance) { maxVariance=variance; threshold=i; } }
return threshold; }
我在手的自动检测中使用这个方法,效果很好。 下面是使用上述两个函数的简单的主程序,可以试运行一下,如果处理视频,要保证第一帧时,手要在图像中。
#include #include #include #pragma comment(lib,"cv210d.lib") #pragma comment(lib,"cxcore210d.lib") #pragma comment(lib,"highgui210d.lib")
#include using namespace std;
int main(int argc, char** argv) { #ifdef VIDEO //video process CvCapture* capture=cvCreateCameraCapture(-1); if (!capture) { cout<<"failed to open camera" int threshold=-1; IplImage* img; while (img=cvQueryFrame(capture)) { cvShowImage("video",img); cvCvtColor(img,img,CV_RGB2YCrCb); IplImage* imgCb=cvCreateImage(cvGetSize(img),8,1); cvSplit(img,NULL,NULL,imgCb,NULL); if (threshold<0) { threshold=cvThresholdOtsu(imgCb); } //cvThresholdOtsu(imgCb,imgCb); cvThreshold(imgCb,imgCb,threshold,255,CV_THRESH_BINARY); cvErode(imgCb,imgCb); cvDilate(imgCb,imgCb); cvShowImage("object",imgCb); cvReleaseImage(&imgCb); if (cvWaitKey(3)==27) //esc { break; } } cvReleaseCapture(&capture); #else //single image process const char* filename=(argc>=2?argv[1]:"cr.jpg"); IplImage* img=cvLoadImage(filename,CV_LOAD_IMAGE_GRAYSCALE); cvThresholdOtsu(img,img); cvShowImage( "src", img ); char buf[256]; sprintf_s(buf,256,"%s.otsu.jpg",filename); cvSaveImage(buf,img); cvErode(img,img); cvDilate(img,img); cvShowImage( "dst", img ); sprintf_s(buf,256,"%s.otsu.processed.jpg",filename); cvSaveImage(buf,img); cvWaitKey(0); #endif return 0; } #include #include #include #pragma comment(lib,"cv210d.lib") #pragma comment(lib,"cxcore210d.lib") #pragma comment(lib,"highgui210d.lib") #include using namespace std; int main(int argc, char** argv) { #ifdef VIDEO //video process CvCapture* capture=cvCreateCameraCapture(-1); if (!capture) { cout<<"failed to open camera"