【发布时间】:2018-01-11 18:02:04
【问题描述】:
看来我的实现不正确,不确定我到底做错了什么:
所以阈值应该在 170 左右?我将阈值设为 130。
这是我的代码:
#Otsu in Python
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
def load_image(file_name):
img = Image.open(file_name)
img.load()
bw = img.convert('L')
bw_data = np.array(bw).astype('int32')
BINS = np.array(range(0,257))
counts, pixels =np.histogram(bw_data, BINS)
pixels = pixels[:-1]
plt.bar(pixels, counts, align='center')
plt.savefig('histogram.png')
plt.xlim(-1, 256)
plt.show()
total_counts = np.sum(counts)
assert total_counts == bw_data.shape[0]*bw_data.shape[1]
return BINS, counts, pixels, bw_data, total_counts
def within_class_variance():
''' Here we will implement the algorithm and find the lowest Within- Class Variance:
Refer to this page for more details http://www.labbookpages.co.uk
/software/imgProc/otsuThreshold.html'''
for i in range(1,len(BINS), 1): #from one to 257 = 256 iterations
prob_1 = np.sum(counts[:i])/total_counts
prob_2 = np.sum(counts[i:])/total_counts
assert (np.sum(prob_1 + prob_2)) == 1.0
mean_1 = np.sum(counts[:i] * pixels[:i])/np.sum(counts[:i])
mean_2 = np.sum(counts[i:] * pixels[i:] )/np.sum(counts[i:])
var_1 = np.sum(((pixels[:i] - mean_1)**2 ) * counts[:i])/np.sum(counts[:i])
var_2 = np.sum(((pixels[i:] - mean_2)**2 ) * counts[i:])/np.sum(counts[i:])
if i == 1:
cost = (prob_1 * var_1) + (prob_2 * var_2)
keys = {'cost': cost, 'mean_1': mean_1, 'mean_2': mean_2, 'var_1': var_1, 'var_2': var_2, 'pixel': i-1}
print('first_cost',cost)
if (prob_1 * var_1) +(prob_2 * var_2) < cost:
cost =(prob_1 * var_1) +(prob_2 * var_2)
keys = {'cost': cost, 'mean_1': mean_1, 'mean_2': mean_2, 'var_1': var_1, 'var_2': var_2, 'pixel': i-1} #pixels is i-1 because BINS is starting from one
return keys
if __name__ == "__main__":
file_name = 'fish.jpg'
BINS, counts, pixels, bw_data, total_counts =load_image(file_name)
keys =within_class_variance()
print(keys['pixel'])
otsu_img = np.copy(bw_data).astype('uint8')
otsu_img[otsu_img > keys['pixel']]=1
otsu_img[otsu_img < keys['pixel']]=0
#print(otsu_img.dtype)
plt.imshow(otsu_img)
plt.savefig('otsu.png')
plt.show()
生成的 otsu 图像如下所示:
这是鱼的图像(它有一个赤膊男子抱着一条鱼,所以工作可能不安全):
链接:https://i.stack.imgur.com/EDTem.jpg
编辑:
原来通过将阈值改为255(差异更明显)
【问题讨论】:
-
您向我们展示了彩色图像,但 Otsu 处理的是灰度图像。你怎么知道阈值应该是 170?
-
这不是正确的阈值方法:
otsu_img[otsu_img > keys['pixel']]=1和otsu_img[otsu_img < keys['pixel']]=0。您在这里所做的是将所有高于阈值(假设为 130)的像素设置为 1。接下来,您将找到低于 130 的所有像素,包括您刚刚设置为 1 的像素,并将它们设置为 0。您得到了什么左边是值正好为 130 的所有像素。其余为 0。此外,您正在对彩色图像执行此操作,这意味着您将分别对三个通道进行阈值处理并将其重新组合为 RGB 图像。先转换成灰度图! -
关于您对 Otsu 的实施,它应该比这更有效。在这里阅读:en.wikipedia.org/wiki/Otsu%27s_method。简而言之,在每次循环迭代中,您可以更新估计的均值和方差,而不是在每次迭代中从所有 bin 中计算它们。这将算法从 O(n*^2) 更改为 O(*n)(其中 n 是直方图中的 bin 数量,诚然不是一个大值)。
-
@YvesDaoust 代码中正在将图像转换为灰度。
-
@CrisLuengo 我在第一个函数中将图像转换为灰度值。
标签: python python-3.x image-processing computer-vision