# Otsu算法

Otsu算法：最大类间方差法（大津算法），是一种确定阈值的算法。

(1) ω0=N0/ (M×N)
(2) ω1=N1/ (M×N)
(3) N0 + N1 = M×N
(4) ω0 + ω1 = 1
(5) μ = ω0 * μ0 + ω1 * μ1
(6) g = ω0 * (μ0 - μ)2 + ω1 * (μ1 - μ)2

(7) g = ω01 * (μ0 - μ1)2

opencv可以直接调用这种算法，`threshold(gray, dst, 0, 255, CV_THRESH_OTSU);`

C++

``````int otsu(IplImage* src)
{
int hist_size = 256;    //直方图尺寸
int hist_height = 256;
float range[] = {0,255};  //灰度级的范围
float* ranges[]={range};
//创建一维直方图，统计图像在[0 255]像素的均匀分布
CvHistogram* gray_hist = cvCreateHist(1,&hist_size,CV_HIST_ARRAY,ranges,1);
//计算灰度图像的一维直方图
cvCalcHist(&src,gray_hist,0,0);
//归一化直方图
cvNormalizeHist(gray_hist,1.0);

int Width = src->width;
int Height = src->height;
int threshold = 0;
double delta = 0;
double u = 0;
for(int m=0; m<256; m++)
{
u += cvQueryHistValue_1D(gray_hist,m)*m;  // cvGetReal1D 均值
}

double v_0 = 0, w_0 = 0;
for(int k=0; k<256; k++)
{

v_0 += cvQueryHistValue_1D(gray_hist,k)*k;   // cvGetReal1D  v_0 = w_0 * u_0
w_0 += cvQueryHistValue_1D(gray_hist,k);      //灰度大于阈值k的像素的概率

double t = u * w_0 - v_0;
double delta_tmp = t * t / (w * (1 - w) );

if(delta_tmp > delta)
{
delta = delta_tmp;
threshold = k;
}
}

cvReleaseHist(&gray_hist);
return threshold;
}
``````

Python

``````import numpy as np

def otsu_threshold(im):
width, height = im.size
img_size = width * height
pixel_counts = np.zeros(256)
for x in range(width):
for y in range(height):
pixel = im.getpixel((x, y))
pixel_counts[pixel] = pixel_counts[pixel] + 1
# 得到图片的以0-255索引的像素值个数列表
s_max = (0, -10)
for threshold in range(256):
# 遍历所有阈值
# 更新
n_0 = sum(pixel_counts[:threshold])  # 得到阈值以下像素个数
n_1 = sum(pixel_counts[threshold:])   # 得到阈值以上像素个数

w_0 = n_0 / img_size
w_1 = n_1 / img_size
# 得到阈值下所有像素的平均灰度
u_0 = sum([i * pixel_counts[i] for i in range(0, threshold)]) / n_0 if n_0 > 0 else 0

# 得到阈值上所有像素的平均灰度
u_1 = sum([i * pixel_counts[i] for i in range(threshold, 256)]) / n_1 if n_1 > 0 else 0

# 总平均灰度
u = w_0 * u_0 + w_1 * u_1

# 类间方差
g = w_0 * (u_0 - u) * (u_0 - u) + w_1 * (u_1 - u) * (u_1 - u)

# 类间方差等价公式
# g = w_0 * w_1 * (u_0 * u_1) * (u_0 * u_1)

# 取最大的
if g > s_max[1]:
s_max = (threshold, g)
return s_max[0]
``````

### 推荐阅读更多精彩内容

• 二值化是图像分割的一种方法。在二值化图象的时候把大于某个临界灰度值的像素灰度设为灰度极大值，把小于这个值的像素灰度...
木夜溯阅读 12,141评论 0 10
• 图像的二值化，就是讲图像变成黑或者白两种颜色。在很多场合，对图像进行二值化，可以忽略图像的颜色信息，背景信息，保留...
MarkOut阅读 15,994评论 0 9
• 如果你是一个计算机视觉研究员，那如果连最最基础的图像处理知识大津阈值都说不明白就说不过去啦！ 转载自博客园_大津阈...
zhnidj阅读 1,074评论 0 5
• 栈 1. 栈（stack）又名堆栈，它是一种运算受限的线性表。其限制是仅允许在表的一端进行插入和删除运算。这一端被...
程序员高级码农阅读 5,801评论 0 11
• 夏天的早上是很凉快的，天气呢明的很早，所以能施工大部分早早上 他们早起 起的是很早的在这样的环境下才可以顺利的工作...
云少nn阅读 90评论 0 1
• “懂”这个字眼缱绻又深邃，它写尽了“心有灵犀一点通”的柔情，却道不完“我本将心托明月，谁知明月照沟渠”的无奈。似乎...
锦瑟嫣然阅读 418评论 8 10
• （3）去年坐地铁，看到一对母子特别感人。 众所周知，坐地铁是不允许带气球一类的危险物品。当时小女孩死死的捏着氢气球...
正值青春_等待花期阅读 190评论 0 0