最近在学opencv,跟着官方文档敲,这是Otsu算法的实现,请问为什么自己实现的和调用函数得出的的答案不一样呢呢,麻烦dl们解答一下,非常感谢
#Otsu's工作原理
import cv2
import numpy as np
img=cv2.imread('./picture3.jpg',0)
blur=cv2.GaussianBlur(img,(5,5),0)
hist=cv2.calcHist([blur],[0],None,[256],[0,256])
hist_norm=hist.ravel()/hist.max()
#归一化,形成各值出现的概率p(X=x)
#ravel():将数组拉成一维数组
Q=hist_norm.cumsum()
#形成概率分布p(X<=x)
bins=np.arange(256)
#直方图坐标轴上x轴各点
fn_min=np.inf
#记录至今最小的组内方差,Otsu是找到使组内方差加权和最小的分割点,先设为最大,后面逐步更新
thresh=-1
#每次记录当前组内方差加权和最小的分割点
for i in range(256):
p1,p2=np.hsplit(hist_norm,[i])
q1,q2=Q[i],Q[-1]-Q[i]
b1,b2=np.hsplit(bins,[i])
#i值
u1,u2=np.sum(b1*p1)/q1,np.sum(b2*p2)/q2
v1,v2=np.sum((b1-u1)**2*p1/q1),np.sum((b2-u2)**2*p2/q2)
#两个组内方差
fn_temp=q1*v1+q2*v2
if fn_temp<fn_min:
fn_min=fn_temp
thresh=i
ret,otsu=cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
print(thresh,ret)
#第一个是前面自己定义的for循环算的,第二个是调用函数算的
算法原理公式:
输出结果:
提示你说你除以0警告了,你要看下如果是0怎么处理的问题。
另外,opencv源码应该是CPP吧,你这个官方文档有给出源码吗?有源码的话源码图片贴出来看下,看下是不是你没带游标卡尺的问题。
【相关推荐阅读】
不知道你这个问题是否已经解决, 如果还没有解决的话:在使用函数cv2.threshold()进行阈值处理时,需要自定义一个阈值,并以此阈值作为图像阈值处理的依据。通常情况下处理的图像都是色彩均衡的,这时候阈值设定为127比较合适。但是,灰度图像的分布是不平均的,如果将阈值设置为127,那么处理出的结果很可能是全为0的。因此,在opencv中,通过函数cv2.threshold()中对参数type的类型多传递一个参数cv2.THRESH_OTSU,即可实现Otsu方式的阈值分割。
在使用Otsu方法的时,要把阈值设为0,此时函数cv2.threshold会自动寻找最优阈值,并将该阈值返回,例如,下面的语句让函数cv2.threshold()采用Otsu方法进行阈值分割:
t,otsu = cv2.threshold(img,0,255,cv2.THRESH_BINARY+CV2.THRESH_OTSU)
与普通阈值分割的不同之处在于:
需要注意的是,如果采用普通的阈值分割,返回的阈值就是设定的阈值。例如下面语句设定的阈值为127,所以最终返回的就是t=127。
t,thd = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
分别对一副图像进行普通的二值化阈值处理和Otsu阈值处理,代码如下:
import cv2
img = cv2.imread("C:\\Users\\asus\\Desktop\\tiffany.bmp",0)
t1,thd = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
t2,otsu = cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
cv2.imshow("img",img)
cv2.imshow("thd",thd)
cv2.imshow("otsu",otsu)
cv2.waitKey()
cv2.destroyAllWindows()