图像二值化是将像素点的灰度值设为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的核心思想是类间方差最大化。
- 初始化一个阈值T0,将图像分为前景f和背景b;
- 图像像素点个数为图像N=height x width,前景像素个数Nf,背景像素个数Nb;
- 图像灰度等级L-1(0~255=256),每个灰度等级像素个数Ni,满足以下公式:
- 前景和背景的灰度平均值分别为:
- 整个图像灰度平均值:
- 求前景和背景之间的方差:
- 找到阈值T0,使得公式4最大;
- 怎么找?可以采用优化算法,本文中直接遍历灰度等级,查找最优阈值。
"""
统计像素点函数
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