聊聊大津法
最近一直在做一个和OpenCV有关的项目,在这个项目上使用到了大津法,今天就来谈谈这个方法。
之前因为要提取图片中的一个标志物的轮廓,在网上一番搜索找到了这个方法,它的作用是可以帮你找到二值化图片的一个阈值。这样能够比较好的分离出前后背景或者轮廓。但是也有缺点,如果前后背景颜色相似这个方法就不太适用了。
大津法的使用
使用大津法需要先将图片转为灰度图片,然后直接使用大津法求出阈值,最后二值化时带入这个阈值就可以求出比较好的二值化图像,此时再执行提取轮廓或者其他操作即可。
下面给出大津法的代码,这是网上的大神给出的代码。如果需要了解原理,可以看看阮一峰的文章 二、内容特征法
1 | def OTSU_enhance(img_gray, th_begin=0, th_end=256, th_step=1) -> int: |
仔细看看代码就可以发现这个函数的时间复杂度非常高,最大的问题就是非常耗时,有多耗时呢?一张400*400像素的图片用时0.2秒,要知道我的程序全部跑完也不过0.7秒左右,光是求阈值就占去30%的时间,所以最好是优化一下这个部分。更恐怖的是,这个时间不是线性增长,而是指数增长的,以维基百科上大津法示例图为例子:
一张1024*768的图片求出阈值需要多久呢?
1.5秒。现在知道优化的重要性了吧。
优化
那么如何优化呢?其实非常简单,将灰度图缩放一下就行了。经过我的测试,哪怕长宽各缩放到原来的十分之一,也就是面积只有原来的百分之一,求出的阈值相差也不超过2,但是时间大大的缩短了,只有0.0107秒,只有原来的18分之一。并且在整个程序中时间占比只有百分之二。效果非常好!
1 | img_grey = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2GRAY) # bgr turn into grey img |
使用求出的 suitable_th 进行二值化:
1 | _, img_bin = cv2.threshold(img_grey, suitable_th, 255, cv2.cv2.THRESH_BINARY_INV) |
还是用刚才的图片举例子:
即使加上缩放的时间也不过0.02秒,提升很大。
二值化的效果也非常好。