一、算法简述
Otsu算法是一种用于二值化最佳阈值的选取方法。基本原理是根据阈值T将图像中的像素点分为C1和C2两类,不断的调整阈值T之后若此时两类之间存在最大的类间方差,那么此阈值即是最佳阈值。
二、算法理论
1、基础公式
(1)
(2)
(3)
(4)
(5)
(6)
(7)
(8)
2、Otsu算法公式推导(为了减少计算量,所以对(6)式进行化简)
利用(7)、(8)可将(6)化简成:
(9)
利用(3)、(4)可将(9)化简成:
(10)
不断更改阈值T,,再利用(1)、(2)、(3)、(5)计算出(10)中的相关值计算出(10)中的最大方差值时,阈值T即为 最佳。
三、算法实现(2020.2.4)
1、matlab实现
clear all
PI = imread('E:\Image_Processing\Image_Repo\拉力表.jpg');
subplot(1,2,1),imshow(PI);
T = graythresh(PI);
PO = im2bw(PI,T);
subplot(1,2,2),imshow(PO);
2、python实现
# -*- coding: utf-8 -*-
import sys
import numpy as np
import cv2
import math
#计算图像灰度直方图
def calcGrayHist(image):
#灰度图像矩阵的宽高
rows,cols = image.shape
#存储灰度直方图
grayHist = np.zeros([1,256],np.uint32)
for r in range(rows):
for c in range(cols):
grayHist[0][image[r][c]] +=1
return grayHist
def ostu(image):
rows,cols = image.shape
#计算图像的灰度直方图
grayHist = calcGrayHist(image)
#归一化灰度直方图
uniformGrayHist = grayHist/float(rows*cols)
#计算零阶累积矩和一阶累积矩
zeroCumuMoment = np.zeros([1,256],np.float32)
oneCumuMoment = np.zeros([1,256],np.float32)
for k in range(256):
if k == 0:
zeroCumuMoment[0][k] = uniformGrayHist[0][0]
oneCumuMoment[0][k] = (k+1)*uniformGrayHist[0][0]
else:
zeroCumuMoment[0][k] = zeroCumuMoment[0][k-1] + uniformGrayHist[0][k]
oneCumuMoment[0][k] = oneCumuMoment[0][k-1] + k*uniformGrayHist[0][k]
#计算类间方差
variance = np.zeros([1,256],np.float32)
for k in range(255):
if zeroCumuMoment[0][k] == 0:
variance[0][k] = 0
else:
variance[0][k] = math.pow(oneCumuMoment[0][255]*zeroCumuMoment[0][k] - oneCumuMoment[0][k],2)/(zeroCumuMoment[0][k]*(1.0-zeroCumuMoment[0][k]))
#找到阈值
threshLoc = np.where(variance[0][0:255] == np.max(variance[0][0:255]))
thresh = threshLoc[0]
#阈值处理
threshold = np.copy(image)
threshold[threshold > thresh] = 255
threshold[threshold <= thresh] = 0
return threshold
#主函数
if __name__ =="__main__":
image = cv2.imread('E:\Image_Processing\Image_Repo\pull_Meter.jpg',cv2.IMREAD_COLOR)
#显示原图
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cv2.imshow("image",image)
#阈值算法
ostu_threshold = ostu(image)
#显示阈值处理的结果
cv2.imshow("ostu_threshold",ostu_threshold)
cv2.waitKey(0)
cv2.destroyAllWindows()
3、c++实现
四、后记:本文主要是本人在学习过程中的一些学习记录和心得,欢迎大家评论交流纠正。