程序员最近都爱上了这个网站  程序员们快来瞅瞅吧!  it98k网:it98k.com

本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长

+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

OpenCV大津二值化算法OTSU简单理解

发布于2019-12-08 11:17     阅读(1547)     评论(0)     点赞(10)     收藏(4)


otsu 大津算法介绍

OTSU算法是由日本学者OTSU于1979年提出的一种对图像进行二值化的高效算法。
利用阈值将原图像分成前景,背景两个图象。
前景:用n1,csum,m1来表示在当前阈值下的前景的点数,质量矩,平均灰度
背景:用n2, sum-csum,m2来表示在当前阈值下的背景的点数,质量矩,平均灰度
当取最佳阈值时,背景应该与前景差别最大,关键在于如何选择衡量差别的标准,而在otsu算法中这个衡量差别的标准就是最大类间方差,在本程序中类间方差用sb表示,最大类间方差用fmax
  • 1
  • 2
  • 3
  • 4
  • 5

这段引用自百度百科,不是很好懂。

otsu 大津算法原理

otsu 大津算法是一种图像二值化算法,作用是确定将图像分成黑白两个部分的阈值。
将图像背景和前景分成黑白两类很好理解,但是如何确定背景和前景的二值化界限(阈值)呢?
对于不同的图像,这个阈值可能不同,这就需要有一种算法来根据图像的信息自适应地确定这个阈值。

首先,需要将图像转换成灰度图像,255个灰度等级。
可以将图像理解成255个图层,每一层分布了不同的像素,这些像素垂直叠加合成了一张完整的灰度图。

我们的目的就是找到一个合适的灰度值,大于这个值的我们将它称之为背景(灰度值越大像素越黑),小于这个值的我们将它称之为前景(灰度值越小像素越白)。

怎么确定这个值就是我们想要的值呢?
这里引入方差的概念,方差越大,相关性越低,黑白越分明。
我们将每一个灰度值之上下之间的像素的方差求出来不就行了吗?找到方差最大的那个灰度值,那个就是我们想要的二值化分隔阈值。

先定义几个符号代表的意义:
h:图像的宽度
w:图像的高度(h*w 得到图像的像素数量)

t :灰度阈值(我们要求的值,大于这个值的像素我们将它的灰度设置为255,小于的设置为0)

n0:小于阈值的像素,前景
n1:大于等于阈值的像素,背景
n0 + n1 == h * w

w0:前景像素数量占总像素数量的比例
w0 = n0 / (h * w)

w1:背景像素数量占总像素数量的比例
w1 = n1 / (h * w)
w0 + w1 == 1

u0:前景平均灰度
u0 = n0灰度累加和 / n0
u1:背景平均灰度
u1 = n1灰度累加和 / n1

u:平均灰度
u = (n0灰度累加和 + n1灰度累加和) / (h * w) 根据上面的关系
u = w0 * u0 + w1 * u1

g:类间方差(那个灰度的g最大,哪个灰度就是需要的阈值t)
g = w0 * (u0 - u)^2 + w1 * (u1 - u)^2
根据上面的关系,可以推出:(这个一步一步推导就可以得到)
g = w0 * w1 * (u0 - u1) ^ 2

然后,遍历每一个灰度值,找到这个灰度值对应的 g
找到最大的 g 对应的 t

代码实现:

import cv2
import numpy as np

# 这里直接将数据转换成float32了,方便后续计算
img = cv2.imread(r'001.jpg').astype(np.float32)

# 灰度化
def bgr2gray(img):
    b = img[:, :, 0].copy()
    g = img[:, :, 1].copy()
    r = img[:, :, 2].copy()

    gray_img = 0.2126 * r + 0.7152 * g + 0.0722 * b
    gray_img = gray_img.astype(np.uint8)

    return gray_img

# 大津二值化算法
def otsu(gray_img):
    h = gray_img.shape[0]
    w = gray_img.shape[1]
    threshold_t = 0
    max_g = 0
    
    # 遍历每一个灰度层
    for t in range(255):
    	# 使用numpy直接对数组进行运算
        n0 = gray_img[np.where(gray_img < t)]
        n1 = gray_img[np.where(gray_img >= t)]
        w0 = len(n0) / (h * w)
        w1 = len(n1) / (h * w)
        u0 = np.mean(n0) if len(n0) > 0 else 0.
        u1 = np.mean(n1) if len(n0) > 0 else 0.
        
        g = w0 * w1 * (u0 - u1) ** 2
        if g > max_g:
            max_g = g
            threshold_t = t
    print('类间方差最大阈值:', threshold_t)
    gray_img[gray_img < threshold_t] = 0
    gray_img[gray_img >= threshold_t] = 255
    return gray_img

gray_img = rgb2gray(img)
otsu_img = otsu(gray_img)
cv2.imshow('otsu_img ', otsu_img )

cv2.waitKey(0)
cv2.destroyAllWindows()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49


所属网站分类: 技术文章 > 博客

作者:听爸爸的话

链接:https://www.pythonheidong.com/blog/article/170328/d92ae1b47dd183b6f04b/

来源:python黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

10 0
收藏该文
已收藏

评论内容:(最多支持255个字符)