图像二值化

图像二值化是将像素点的灰度值设为0或255,使图像呈现明显的黑白效果。二值化之前需要把图像进行灰度处理。

(全局阈值法)固定阈值法   
Threshold为全局阈值,但是全局阈值不好确定,先尝试使用灰度图的平均像素作为全局阈值。

import cv2
import numpy as np
import matplotlib.pyplot as plt
image = cv2.imread("chatgpt.png")
# 加权求出灰度图
def weight_gray(image):
    weight_image = image[:, :, 0] * 0.11 + image[:, :, 1] * 0.59 + image[:, :, 2] * 0.3 # 三个通道加权求和
    weight_image = weight_image.astype(np.uint8)
    return weight_image
    
"""
像素平均值二值化
gray: 灰度图(ndarray)
return: 二值化图像(ndarray)
"""
def mean_threshold(gray):
    threshold = np.mean(gray)# 求平均像素值
    binary = np.where(gray >= threshold, 255, 0)
    binary = binary.astype(np.uint8)
    return binary
    
gray = weight_gray(image)
plt.figure(figsize=(10,10))
plt.subplot(121)#画子图   
plt.imshow(gray, cmap='gray')
plt.title("gray")
plt.subplot(122)#画子图   
plt.title("threshold")
plt.imshow(mean_threshold(gray), cmap='gray')

OTSU算法
OTSU是阈值分割中一种常用的算法,它可以根据图像自动生成最佳分割阈值。 OTSU的核心思想是类间方差最大化。

  1. 初始化一个阈值T0,将图像分为前景f和背景b;
  2. 图像像素点个数为图像N=height x width,前景像素个数Nf,背景像素个数Nb;
  3. 图像灰度等级L-1(0~255=256),每个灰度等级像素个数Ni,满足以下公式:
  4. 前景和背景的灰度平均值分别为:
  5. 整个图像灰度平均值:
  6. 求前景和背景之间的方差:
  7. 找到阈值T0,使得公式4最大;
  8. 怎么找?可以采用优化算法,本文中直接遍历灰度等级,查找最优阈值。
"""
统计像素点函数
image: 输入灰度图(ndarray)
reutrn: {像素:个数}(dict)
"""
def pixel_num(image):
    h, w = image.shape
    pdict = {}
    for i in range(h):
        for j in range(w):
            if image[i,j] in pdict:
                pdict[image[i,j]] += 1
            else:
                pdict[image[i,j]] = 0
    return pdict

"""
求公式4中sigma2的值
T0: 预设阈值(int)
gray: 灰度图(ndarray)
L: 灰度等级(int)
"""
def sigma2(T0, gray, L=256):
    h, w = gray.shape
    N = h * w
    pdict = pixel_num(gray)
    pf = sum([v for k,v in pdict.items() if k < T0]) / N#公式1
    pb = sum([v for k,v in pdict.items() if k >= T0]) / N#公式1
    pf = [pf if pf > 1e-6 else 1e-6][0]#控制最小值,避免除以0
    pb = [pb if pb > 1e-6 else 1e-6][0]#控制最小值,避免除以0
    mf = sum([k * pdict.get(k, 0) / N for k in range(T0)]) / pf#公式2
    mb = sum([k * pdict.get(k, 0) / N for k in range(T0, L)]) / pb#公式2
    M = pf * mf + pb * mb#公式3
    s2 = pf * (mf - M) ** 2 + pb * (mb - M) ** 2#公式4
    return s2, T0

"""
遍历查找最大sigma2
gray: 灰度图(ndarray)
L: 灰度等级(int)
"""
def otsu(gray, L=256):
    smax = 0
    tmax = 0
    for t in range(1, L):
        s2, T0 = sigma2(t, gray, L)
        if s2 > smax:
            smax = s2
            tmax = T0
    return smax, tmax

"""
根据最佳阈值求二值化图像
threshold: 最佳阈值(int)
return: 二值化图像(ndarray)
"""
def otsu_threshold(max_threshold, gray):
    threshold = np.mean(gray)
    binary = np.where(gray >= max_threshold, 255, 0)
    binary = binary.astype(np.uint8)
    return binary
    
smax, tmax = otsu(gray, 256)  
oimage = otsu_threshold(tmax, gray)
plt.figure(figsize=(10,10))
plt.subplot(121)#画子图
plt.imshow(mean_threshold(gray), cmap='gray')
plt.title("threshold")
plt.subplot(122)#画子图
plt.title("otsu")
plt.imshow(oimage, cmap='gray')

原文链接:https://blog.csdn.net/weixin_43828944/article/details/128911462