大律法(OTSU) ——图像数据二值化

2023-11-17

二值化的目的,是确定一个像素值,以像素为分界,将图像划分为前景和背景,前景的像素值取相同值,背景的像素也取相同值,从而将前景和背景的差异,在图像中最大化,或者说可以突出前景或者背景信息。

二值化可以有效的降低噪声,并且可以一定程度的增强目标特征

我使用一下,这篇文章的配图:https://blog.csdn.net/bigat/article/details/80889636

该文是关于图像混合的文章,我只是想用这两张图来说明,二值化的效果。

 那么最终要的问题就是,选择哪个像素值,作为划分最合适?

日本学者大津(Nobuyuki Otsu)于1979年给出了很好的解答,论文:

OTSU N. A threshold selection method from gray-level histo- grams[ J ].IEEE Transactions on Systems, Man and Cybernetics , 1979, 9 ( 1 ) : 62 - 66.
 

算法的核心思想是,选择使得划分出来的前景与背景有最大方差的划分为最优划分,很多文章称为类间方差,因为可以将前景数据作为一类,而背景数据作为另一类,所以可以称为前景类与背景类的类间方差。

所以只要知道,怎么计算图像数据的类间方差就可以实现了,这里引用一下:https://blog.csdn.net/u012198575/article/details/81128799

中的公式,因为很全,所以我就不重新写了,如下:

公式:  记 M = 256 单通道灰度分级 Sum = 像素总数

  1. 背景像素占比 \omega1 = \frac{N1}{Sum}  
  2. 前景像素占比\omega2 = 1- \omega1 = \frac{N2}{Sum} =1- \frac{N1}{Sum}
  3. 背景的平均灰度值\mu 1 = \sum_{i = 0}^{t} i *Pr(i | C_{0}) = \sum_{i = 0}^{t} i *Pi / \sum_{i = 0}^{t} Pi = \frac{\mu(t))}{\omega_{1}}
  4. 前景的平均灰度值\mu 2 = \sum_{i = t+1}^{M - 1} i *Pr(i | C_{1}) = \sum_{i = t+1}^{M - 1} i *Pi / \sum_{i = t+1}^{M - 1} Pi = \frac{\mu - \mu(t))}{\omega _{2}}
  5. 0~M灰度区间的灰度累计值\mu = \mu1*\omega 1 + \mu2*\omega 2
  6. 类间方差:g = \omega 1 * (\mu - \mu1)^{2} + \omega 2 * (\mu - \mu2)^{2}
  7. 将公式3.4.5带入公式6 可得最终简化公式: g = \omega 1 * \omega2 * (\mu1 - \mu2)^{2}

下面使用Python+cv2来实现,并且和cv2中的OTSU的结果进行比较,使用cv2主要是为了读取图片:

将三通道的RGB图像转换为单通道的灰度图像:

公式如下I[i][j] = (299*r[i][j] + 587*g[i][j] + 114*b[i][j])/1000

这里不做过多解释,可以使用cv2的方法进行转换,这里是自己实现的算法:

def Gray(img):
    a = np.shape(img)
    r,g,b = cv2.split(img)
    img_new = np.zeros((a[0], a[1]))
    for i in range(a[0]):
        for j in range(a[1]):
            data = (299*r[i][j] + 587*g[i][j] + 114*b[i][j])/1000
            img_new[i][j] = data
    img_new = img_new.astype('uint8')
    return img_new

效果如下:

 统计各个灰度值像素的数量和占比:

def Pixel_num(img):
    num = [0 for _ in range(256)]
    a = np.shape(img)
    for i in range(a[0]):
        for j in range(a[1]):
            num[img[i][j]] += 1
    return num

def Pixel_rate(num_list):
    rate_list = []
    n = sum(num_list)
    for i in range(len(num_list)):
        rate = num_list[i] / n
        rate_list.append(rate)
    return rate_list

遍历0~255的像素值,寻找最优:

def Optimal_partition(rate_list):
    deltaMax = 0
    T = 0
    for i in range(256):
        w1 = w2 = u1 = u2 = 0
        u1tmp = u2tmp = 0
        deltaTmp = 0
        for j in range(256):
            if (j <= i):
                w1 += rate_list[j]
                u1tmp += j * rate_list[j]
            else:
                w2 += rate_list[j]
                u2tmp += j * rate_list[j]
        if w1 == 0:
            u1 = 0
        else:
            u1 = u1tmp / w1
        if w2 == 0:
            u2 = 0
        else:
            u2 = u2tmp / w2
        deltaTmp = w1 * w2 * ((u1- u2) ** 2)
        if deltaTmp > deltaMax:
            deltaMax = deltaTmp
            T = i
    return T

根据最优灰度值进行划分:

def Otsu(img, T):
    a = np.shape(img)
    new_img = np.zeros((a[0], a[1]))
    for i in range(a[0]):
        for j in range(a[1]):
            if img[i][j] > T:
                new_img[i][j] = 255
            else:
                new_img[i][j] = 0
    return new_img

 结果如下:

cv2结果:

ret, th = cv2.threshold(new_img, 0, 255, cv2.THRESH_OTSU)

 效果一致

使用面向对象的方式将算法封装为类(文件名为Threshold):

'''
@Author: BTboay
@Date: 2019-12-05 12:28:10
@LastEditTime: 2019-12-05 14:28:25
@LastEditors: Please set LastEditors
@Description: In User Settings Edit
@FilePath: \YOLOv3_01\OTSU.py
'''
import numpy as np
import cv2

class OTSU():
    def __init__(self, img_path):
        img = cv2.imread(img_path)
        self.img = img
        img_gray = self.Gray()
        self.img = img_gray
        num_list = self.Pixel_num()
        self.num_list = num_list
        rate_list = self.Pixel_rate()
        self.rate_list = rate_list
        optimal_pixel = self.Optimal_partition()
        self.optimal_pixel = optimal_pixel

    def Gray(self):
        a = np.shape(self.img)
        r,g,b = cv2.split(self.img)
        img_new = np.zeros((a[0], a[1]))
        for i in range(a[0]):
            for j in range(a[1]):
                data = (299*r[i][j] + 587*g[i][j] + 114*b[i][j])/1000
                img_new[i][j] = data
        img_new = img_new.astype('uint8')
        return img_new

    def Pixel_num(self):
        num = [0 for _ in range(256)]
        a = np.shape(self.img)
        for i in range(a[0]):
            for j in range(a[1]):
                num[self.img[i][j]] += 1
        return num

    def Pixel_rate(self):
        rate_list = []
        n = sum(self.num_list)
        for i in range(len(self.num_list)):
            rate = self.num_list[i] / n
            rate_list.append(rate)
        return rate_list

    def Optimal_partition(self):
        deltaMax = 0
        T = 0
        for i in range(256):
            w1 = w2 = u1 = u2 = 0
            u1tmp = u2tmp = 0
            deltaTmp = 0
            for j in range(256):
                if (j <= i):
                    w1 += self.rate_list[j]
                    u1tmp += j * self.rate_list[j]
                else:
                    w2 += self.rate_list[j]
                    u2tmp += j * self.rate_list[j]
            if w1 == 0:
                u1 = 0
            else:
                u1 = u1tmp / w1
            if w2 == 0:
                u2 = 0
            else:
                u2 = u2tmp / w2
            deltaTmp = w1 * w2 * ((u1- u2) ** 2)
            if deltaTmp > deltaMax:
                deltaMax = deltaTmp
                T = i
        return T

    def Otsu(self):
        a = np.shape(self.img)
        new_img = np.zeros((a[0], a[1]))
        for i in range(a[0]):
            for j in range(a[1]):
                if self.img[i][j] > self.optimal_pixel:
                    new_img[i][j] = 255
                else:
                    new_img[i][j] = 0
        return new_img

调用该类:

'''
@Author: your name
@Date: 2019-12-03 15:43:11
@LastEditTime: 2019-12-05 15:20:49
@LastEditors: Please set LastEditors
@Description: In User Settings Edit
@FilePath: gray.py
'''
import numpy as np
import matplotlib.pyplot as plt
import cv2
import Threshold

if __name__ == "__main__":
    path = 'D:/WorkSpace/YOLOv3_01/05.jpg'
    a = Threshold.OTSU(path)
    new_img = a.Otsu()

    plt.imshow(new_img, 'gray')
    plt.axis('off')
    plt.show()

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

大律法(OTSU) ——图像数据二值化 的相关文章

  • Python中Decimal类型的澄清

    每个人都知道 或者至少 每个程序员都应该知道 http docs oracle com cd E19957 01 806 3568 ncg goldberg html 即使用float类型可能会导致精度错误 然而 在某些情况下 精确的解决方
  • django_openid_auth TypeError openid.yadis.manager.YadisServiceManager 对象不是 JSON 可序列化

    I used django openid auth在我的项目上 一段时间以来它运行得很好 但今天 我测试了该应用程序并遇到了这个异常 Environment Request Method GET Request URL http local
  • Python模块可以访问英语词典,包括单词的定义[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我正在寻找一个 python 模块 它可以帮助我从英语词典中获取单词的定义 当然有enchant 这可以帮助我检查该单词是否存在于英语中
  • Python逻辑运算符优先级[重复]

    这个问题在这里已经有答案了 哪个运算符优先4 gt 5 or 3 lt 4 and 9 gt 8 这会被评估为真还是假 我知道该声明3 gt 4 or 2 lt 3 and 9 gt 10 显然应该评估为 false 但我不太确定 pyth
  • 如何使用 imaplib 获取“消息 ID”

    我尝试获取一个在操作期间不会更改的唯一 ID 我觉得UID不好 所以我认为 Message ID 是正确的 但我不知道如何获取它 我只知道 imap fetch uid XXXX 有人有解决方案吗 来自 IMAP 文档本身 IMAP4消息号
  • 填充两个函数之间的区域

    import matplotlib pyplot as plt import numpy as np def domain x np arange 0 10 0 001 f1 lambda x 2 x x 2 0 5 plt plot x
  • 从零开始的 numpy 形状意味着什么

    好的 我发现数组的形状中可以包含 0 对于将 0 作为唯一维度的情况 这对我来说是有意义的 它是一个空数组 np zeros 0 但如果你有这样的情况 np zeros 0 100 让我很困惑 为什么这么定义呢 据我所知 这只是表达空数组的
  • 如何计算numpy数组中元素的频率?

    我有一个 3 D numpy 数组 其中包含重复的元素 counterTraj shape 13530 1 1 例如 counterTraj 包含这样的元素 我只显示了几个元素 array 136 129 130 103 102 101 我
  • 切片 Dataframe 时出现 KeyError

    我的代码如下所示 d pd read csv Collector Output csv df pd DataFrame data d dfa df copy dfa dfa rename columns OBJECTID Object ID
  • TensorFlow的./configure在哪里以及如何启用GPU支持?

    在我的 Ubuntu 上安装 TensorFlow 时 我想将 GPU 与 CUDA 结合使用 但我却停在了这一步官方教程 http www tensorflow org get started os setup md 这到底是哪里 con
  • Python urllib.request.urlopen:AttributeError:'bytes'对象没有属性'data'

    我正在使用 Python 3 并尝试连接到dstk 我收到错误urllib包裹 我对SO进行了很多研究 但找不到与这个问题类似的东西 api url self api base street2coordinates api body jso
  • 从 python 发起 SSH 隧道时出现问题

    目标是在卫星服务器和集中式注册数据库之间建立 n 个 ssh 隧道 我已经在我的服务器之间设置了公钥身份验证 因此它们只需直接登录而无需密码提示 怎么办 我试过帕拉米科 它看起来不错 但仅仅建立一个基本的隧道就变得相当复杂 尽管代码示例将受
  • 如何解决使用 Spark 从 S3 重新分区大量数据时从内存中逐出缓存的表分区元数据的问题?

    在尝试从 S3 重新分区数据帧时 我收到一个一般错误 Caused by org apache spark SparkException Job aborted due to stage failure Task 33 in stage 1
  • 将 JSON 对象传递给带有请求的 url

    所以 我想利用 Kenneth 的优秀请求模块 https github com kennethreitz requests 在尝试使用时偶然发现了这个问题自由库API http wiki freebase com wiki API 基本上
  • 创建嵌套字典单行

    您好 我有三个列表 我想使用一行创建一个三级嵌套字典 i e l1 a b l2 1 2 3 l3 d e 我想创建以下嵌套字典 nd a 1 d 0 e 0 2 d 0 e 0 3 d 0 e 0 b a 1 d 0 e 0 2 d 0
  • mac osx 10.8 上的初学者 python

    我正在学习编程 并且一直在使用 Ruby 和 ROR 但我觉得我更喜欢 Python 语言来学习编程 虽然我看到了 Ruby 和 Rails 的优点 但我觉得我需要一种更容易学习编程概念的语言 因此是 Python 但是 我似乎找不到适用于
  • Tkinter - 浮动窗口 - 调整大小

    灵感来自this https stackoverflow com a 22424245 13629335问题 我想为我的根窗口编写自己的调整大小函数 但我刚刚注意到我的代码显示了一些性能问题 如果你快速调整它的大小 你会发现窗口没有像我希望
  • 如何读取Python字节码?

    我很难理解 Python 的字节码及其dis module import dis def func x 1 dis dis func 上述代码在解释器中输入时会产生以下输出 0 LOAD CONST 1 1 3 STORE FAST 0 x
  • 迭代 pandas 数据框的最快方法?

    如何运行数据框并仅返回满足特定条件的行 必须在之前的行和列上测试此条件 例如 1 2 3 4 1 1 1999 4 2 4 5 1 2 1999 5 2 3 3 1 3 1999 5 2 3 8 1 4 1999 6 4 2 6 1 5 1
  • Scrapy Spider不存储状态(持久状态)

    您好 有一个基本的蜘蛛 可以运行以获取给定域上的所有链接 我想确保它保持其状态 以便它可以从离开的位置恢复 我已按照给定的网址进行操作http doc scrapy org en latest topics jobs html http d

随机推荐