用OpenCV实现Otsu算法

一、Otsu算法原理

Otsu算法(大津法或最大类间方差法)使用的是聚类的思想,把图像的灰度数按灰度级分成2个部分,使得两个部分之间的灰度值差异最大,每个部分之间的灰度差异最小,通过方差的计算来寻找一个合适的灰度级别来划分。 所以可以在二值化的时候采用otsu算法来自动选取阈值进行二值化。otsu算法被认为是图像分割中阈值选取的最佳算法,计算简单,不受图像亮度和对比度的影响。因此,使类间方差最大的分割意味着错分概率最小。

设t为设定的阈值。

w0 分开后前景像素点数占图像的比例
u0 分开后前景像素点的平均灰度
w1 分开后背景像素点数占图像的比例
u1 分开后背景像素点的平均灰度

图像总平均灰度为: u = w0∗u0 + w1∗u1

从L个灰度级遍历 t,使得 t 为某个值的时候,前景和背景的方差最大,则 这个 t 值便是我们要求得的阈值。其中,方差的计算公式如下:

g = wo∗(u0−u)∗(u0−u) + w1∗(u1−u)∗(u1−u)

此公式计算量较大,可以采用:

g = w0∗w1∗(u0−u1)∗(u0−u1)

由于Otsu算法是对图像的灰度级进行聚类,因此在执行Otsu算法之前,需要计算该图像的灰度直方图。

二、代码实现算法

第一份代码:来自Augusdi

 1 #include<iostream>
 2 #include<opencv\cv.h>
 3 //#include<opencv2\highgui.hpp>
 4 #include<opencv2\highgui\highgui.hpp>
 5
 6 int Otsu(IplImage* src);
 7
 8 int main()
 9 {
10     IplImage* img = cvLoadImage("E:\\house.jpg", 0);
11     IplImage* dst = cvCreateImage(cvGetSize(img), 8, 1);
12     int threshold = Otsu(img);
13
14     cvThreshold(img, dst, threshold, 255, CV_THRESH_BINARY);
15
16
17     cvNamedWindow("img", 1);
18     cvShowImage("img", dst);
19
20
21     cvWaitKey(-1);
22
23     cvReleaseImage(&img);
24     cvReleaseImage(&dst);
25
26     cvDestroyWindow("dst");
27     return 0;
28 }
29
30 int Otsu(IplImage* src)
31 {
32     int height = src->height;
33     int width = src->width;
34     long size = height * width;
35
36     //histogram
37     float histogram[256] = { 0 };
38     for (int m = 0; m < height; m++)
39     {
40         unsigned char* p = (unsigned char*)src->imageData + src->widthStep * m;
41         for (int n = 0; n < width; n++)
42         {
43             histogram[int(*p++)]++;
44         }
45     }
46
47     int threshold;
48     long sum0 = 0, sum1 = 0; //存储前景的灰度总和和背景灰度总和
49     long cnt0 = 0, cnt1 = 0; //前景的总个数和背景的总个数
50     double w0 = 0, w1 = 0; //前景和背景所占整幅图像的比例
51     double u0 = 0, u1 = 0;  //前景和背景的平均灰度
52     double variance = 0; //最大类间方差
53     int i, j;
54     double u = 0;
55     double maxVariance = 0;
56     for (i = 1; i < 256; i++) //一次遍历每个像素
57     {
58         sum0 = 0;
59         sum1 = 0;
60         cnt0 = 0;
61         cnt1 = 0;
62         w0 = 0;
63         w1 = 0;
64         for (j = 0; j < i; j++)
65         {
66             cnt0 += histogram[j];
67             sum0 += j * histogram[j];
68         }
69
70         u0 = (double)sum0 / cnt0;
71         w0 = (double)cnt0 / size;
72
73         for (j = i; j <= 255; j++)
74         {
75             cnt1 += histogram[j];
76             sum1 += j * histogram[j];
77         }
78
79         u1 = (double)sum1 / cnt1;
80         w1 = 1 - w0; // (double)cnt1 / size;
81
82         u = u0 * w0 + u1 * w1; //图像的平均灰度
83         printf("u = %f\n", u);
84         //variance =  w0 * pow((u0 - u), 2) + w1 * pow((u1 - u), 2);
85         variance = w0 * w1 *  (u0 - u1) * (u0 - u1);
86         if (variance > maxVariance)
87         {
88             maxVariance = variance;
89             threshold = i;
90         }
91     }
92
93     printf("threshold = %d\n", threshold);
94     return threshold;
95 }

第二份代码:

  1 #include <opencv\cv.h>
  2 #include <opencv2\highgui\highgui.hpp>
  3
  4 int otsu(IplImage *image)
  5 {
  6     assert(NULL != image);
  7
  8     int width = image->width;
  9     int height = image->height;
 10     int x = 0, y = 0;
 11     int pixelCount[256];
 12     float pixelPro[256];
 13     int i, j, pixelSum = width * height, threshold = 0;
 14
 15     uchar* data = (uchar*)image->imageData;
 16
 17     //初始化
 18     for (i = 0; i < 256; i++)
 19     {
 20         pixelCount[i] = 0;
 21         pixelPro[i] = 0;
 22     }
 23
 24     //统计灰度级中每个像素在整幅图像中的个数
 25     for (i = y; i < height; i++)
 26     {
 27         for (j = x; j <width; j++)
 28         {
 29             pixelCount[data[i * image->widthStep + j]]++;
 30         }
 31     }
 32
 33     //计算每个像素在整幅图像中的比例
 34     for (i = 0; i < 256; i++)
 35     {
 36         pixelPro[i] = (float)(pixelCount[i]) / (float)(pixelSum);
 37     }
 38
 39     //经典ostu算法,得到前景和背景的分割
 40     //遍历灰度级[0,255],计算出方差最大的灰度值,为最佳阈值
 41     float w0, w1, u0tmp, u1tmp, u0, u1, u, deltaTmp, deltaMax = 0;
 42     for (i = 0; i < 256; i++)
 43     {
 44         w0 = w1 = u0tmp = u1tmp = u0 = u1 = u = deltaTmp = 0;
 45
 46         for (j = 0; j < 256; j++)
 47         {
 48             if (j <= i) //背景部分
 49             {
 50                 //以i为阈值分类,第一类总的概率
 51                 w0 += pixelPro[j];
 52                 u0tmp += j * pixelPro[j];
 53             }
 54             else       //前景部分
 55             {
 56                 //以i为阈值分类,第二类总的概率
 57                 w1 += pixelPro[j];
 58                 u1tmp += j * pixelPro[j];
 59             }
 60         }
 61
 62         u0 = u0tmp / w0;        //第一类的平均灰度
 63         u1 = u1tmp / w1;        //第二类的平均灰度
 64         u = u0tmp + u1tmp;        //整幅图像的平均灰度
 65         //计算类间方差
 66         deltaTmp = w0 * (u0 - u)*(u0 - u) + w1 * (u1 - u)*(u1 - u);
 67         //找出最大类间方差以及对应的阈值
 68         if (deltaTmp > deltaMax)
 69         {
 70             deltaMax = deltaTmp;
 71             threshold = i;
 72         }
 73     }
 74     //返回最佳阈值;
 75     return threshold;
 76 }
 77
 78 int main(int argc, char* argv[])
 79 {
 80     IplImage* srcImage = cvLoadImage("house.jpg", 0);
 81     assert(NULL != srcImage);
 82
 83     cvNamedWindow("src");
 84     cvShowImage("src", srcImage);
 85
 86     IplImage* biImage = cvCreateImage(cvGetSize(srcImage), 8, 1);
 87
 88     //计算最佳阈值
 89     int threshold = otsu(srcImage);
 90     printf("threshold = %d\n", threshold);
 91     //对图像二值化
 92     cvThreshold(srcImage, biImage, threshold, 255, CV_THRESH_BINARY);
 93
 94     cvNamedWindow("binary");
 95     cvShowImage("binary", biImage);
 96
 97     cvWaitKey(0);
 98
 99     cvReleaseImage(&srcImage);
100     cvReleaseImage(&biImage);
101     cvDestroyWindow("src");
102     cvDestroyWindow("binary");
103
104     return 0;
105 }

三、代码运行结果

代码1运行结果:

代码2运行结果:

时间: 2024-11-04 05:41:42

用OpenCV实现Otsu算法的相关文章

大津法---OTSU算法

简介: 大津法(OTSU)是一种确定图像二值化分割阈值的算法,由日本学者大津于1979年提出.从大津法的原理上来讲,该方法又称作最大类间方差法,因为按照大津法求得的阈值进行图像二值化分割后,前景与背景图像的类间方差最大(何为类间方差?原理中有介绍). OTSU算法 OTSU算法也称最大类间差法,有时也称之为大津算法,由大津于1979年提出,被认为是图像分割中阈值选取的最佳算法,计算简单,不受图像亮度和对比度的影响,因此在数字图像处理上得到了广泛的应用.它是按图像的灰度特性,将图像分成背景和前景两

OpenCV使用Harris算法实现角点检测

纯粹阅读,请移步OpenCV使用Harris算法实现角点检测 效果图 源码 KqwOpenCVFeaturesDemo 角点是两条边缘的交点或者在局部邻域中有多个显著边缘方向的点.Harris角点检测是一种在角点检测中最常见的技术. Harris角点检测器在图像上使用滑动窗口计算亮度的变化. 封装 这里用到了RxJava.主要是因为图片处理是耗时操作,会阻塞线程,为了防止界面卡顿,这里使用RxJava进行了线程切换. /** * Harris角点检测 * * @param bitmap 要检测的

java 在centos6.5+eclipse环境下调用opencv实现sift算法

java 在centos6.5+eclipse环境下调用opencv实现sift算法,代码如下: import org.opencv.core.Core; import org.opencv.core.Mat; import org.opencv.core.MatOfKeyPoint; import org.opencv.highgui.Highgui; import org.opencv.features2d.*; public class ExtractSIFT{ public static

基于Otsu算法的图像自适应阈值分割

在图像处理实践中,将灰度图转化为二值图是非常常见的一种预处理手段.在Matlab中,可以使用函数BW = im2bw(I, level)来将一幅灰度图 I,转化为二值图.其中,参数level是一个介于0~1之间的值,也就是用于分割图像的阈值.默认情况下,它可取值是0.5. 现在问题来了,有没有一种根据图像自身特点来自适应地选择阈值的方法呢?答案是肯定的!我们今天就来介绍其中最为经典的Otsu算法(或称大津算法).该算法由日本科学家大津展之(Nobuyuki Otsu)于1979年提出.这个算法看

用OpenCV实现Photoshop算法(三): 曲线调整

http://blog.csdn.net/c80486/article/details/52499919 系列文章: 用OpenCV实现Photoshop算法(一): 图像旋转 用OpenCV实现Photoshop算法(二): 图像剪切 用OpenCV实现Photoshop算法(三): 曲线调整 用OpenCV实现Photoshop算法(四): 色阶调整 用OpenCV实现Photoshop算法(五): 亮度对比度调整 用OpenCV实现Photoshop算法(六): 变为黑白图像 用OpenC

OTSU算法(二)

%使用OTSU算法进行二值化后的图像 close all;clear all;clc %% I = imread('C.jpg'); scoreImage0=rgb2gray(I); scoreImage=double(scoreImage0); [height,length]=size(scoreImage); totalPixel=height*length; % maxPixNumber=max(max(scoreImage)); % 这个地方为了以后计算方便 就不这样计算了 而是默认最大

OPENCV下SIFT算法使用方法笔记

这几天继续在看Lowe大神的SIFT神作,看的眼花手脚抽筋.也是醉了!!!!实在看不下去,来点干货.我们知道opencv下自带SIFT特征检测以及MATCH匹配的库,这些库完全可以让我们进行傻瓜似的操作.但实际用起来的时候还不是那么简单.下文将对一个典型的基于OPENCV的SIFT特征点提取以及匹配的例程进行分析,并由此分析详细的对OPENCV中SIFT算法的使用进行一个介绍. OPENCV下SIFT特征点提取与匹配的大致流程如下: 读取图片->特征点检测(位置,角度,层)->特征点描述的提取

自动阈值法:Otsu法 用MATLAB实现Otsu算法:

%自动阈值法:Otsu法 用MATLAB实现Otsu算法: clc;clear;close; I=imread('e:\role0\003i.bmp'); subplot(1,2,1),imshow(I); title('原始图像') grid on; %显示网格线 axis on; %显示坐标系 level=graythresh(I); %确定灰度阈值 BW=im2bw(I,level); subplot(1,2,2),imshow(BW); title('Otsu 法阈值分割图像') gri

用OpenCV实现Photoshop算法(一): 图像旋转

最近学习了OpenCV,于是想用它实现Photoshop的主要功能,用于照片处理. 对于一张照片,PS的一般处理步骤包括: 1, 旋转图片,校正位置. 2,剪切,调整大小,重新构图. 3,调整色阶.曲线,使图片曝光正确.对比适中. 4,调整对比度.饱和度 5,印章去掉不想要的东西,液化调整形体线条 6,对于人像图片,美肤.美白 7, 用色彩平衡.可选颜色等调整色调,形成照片调性 8,加一些光效 9,锐化 以后的一系列博文将采用OpenCV逐一实现Photoshop的算法和功能, 并用计算机视觉人