opencv Otsu自己实现和调用函数的结果不一致是什么原因呢?

最近在学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循环算的,第二个是调用函数算的

算法原理公式:

img

输出结果:

img

提示你说你除以0警告了,你要看下如果是0怎么处理的问题。
另外,opencv源码应该是CPP吧,你这个官方文档有给出源码吗?有源码的话源码图片贴出来看下,看下是不是你没带游标卡尺的问题。

【相关推荐阅读】

不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 这有个类似的问题, 你可以参考下: https://ask.csdn.net/questions/242460
  • 这篇博客你也可以参考下:OpenCV-Python学习笔记(八):图像阈值:简单阈值、自适应阈值、 Otsu's阈值
  • 除此之外, 这篇博客: Opencv学习八:阈值处理中的 三、Otsu处理 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:

    在使用函数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)
    

    与普通阈值分割的不同之处在于:

    • 参数type增加了一个参数值“cv2.THRESH_OTSU”;
    • 设定的阈值为0;
    • 返回t是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()
    

    在这里插入图片描述


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^