前言
为什么要进行图像二值化,rgb图像有三个通道,处理图像的计算量较大,二值化的图像极大的减少了处理图像的计算量。即便从彩色图像转成了二值化图像,也不影响对物体的识别。本章开始讲解图像二值化。Python包含全局128、全局均值、大津阈值法(OTSU);FPGA只做全局128的讲解。
一、Python全局128
import numpy as np
import matplotlib.pyplot as plt
img = plt.imread("lenna.png")
gray = 0.299 * img[:, :, 0] + 0.587 * img[:, :, 1] + 0.114 * img[:, :, 2]
gray = gray * 255#图像是[0-1]--->[0-255]
bin_image = np.where(gray >= 128, 255, 0)#全局二值化
fig = plt.figure(figsize=(8, 8))
ax = fig.add_subplot(1, 2, 1)
ax.set_title("gray image")
ax.set_xlabel("width")
ax.set_ylabel("height")
plt.imshow(gray, cmap="gray")
ax = fig.add_subplot(1, 2, 2)
ax.set_title("binary image")
ax.set_xlabel("width")
ax.set_ylabel("height")
plt.imshow(bin_image, cmap="gray")
二、Python全局均值
mean_image = np.where(gray > np.mean(gray), 255, 0)#全局均值
fig = plt.figure(figsize=(8, 8))
ax = fig.add_subplot(1, 2, 1)
ax.set_title("gray image")
ax.set_xlabel("width")
ax.set_ylabel("height")
plt.imshow(gray, cmap="gray")
ax = fig.add_subplot(1, 2, 2)
ax.set_title("mean image")
ax.set_xlabel("width")
ax.set_ylabel("height")
plt.imshow(mean_image, cmap="gray")
三、Python全局OTSU
OTSU是阈值分割中一种常用的算法,它可以根据图像自动生成最佳分割阈值。 OTSU的核心思想是类间方差最大化。
- 初始化一个阈值T0,将图像分为前景f和背景b;
- 图像像素点个数为图像N=height x width,前景像素个数Nf,背景像素个数Nb;
- 图像灰度等级L-1(0~255=256),每个灰度等级像素个数Ni,满足以下公式:
P f = ∑ i = 0 i = T 0 N i N P b = ∑ i = T 0 i = L − 1 N i N (1) Pf = \sum_{i = 0}^{i=T0}\frac{Ni}{N} \quad\quad Pb= \sum_{i = T0}^{i=L-1}\frac{Ni}{N}\tag{1} Pf=i=0∑i=T0NNiPb=i=T0∑i=L−1NNi(1)
- 前景和背景的灰度平均值分别为:
M f = ∑ i = 0 i = T 0 i × P i P f M b = ∑ i = T 0 i = L − 1 i × P i P b (2) Mf = \sum_{i = 0}^{i=T0}i \times \frac{Pi}{Pf} \quad\quad Mb= \sum_{i = T0}^{i=L-1}i\times\frac{Pi}{Pb}\tag{2} Mf=i=0∑i=T0i×PfPiMb=i=T0∑i=L−1i×PbPi(2)
-
整个图像灰度平均值:
M = P f × M f + P b × M b (3) M = Pf \times Mf + Pb \times Mb\tag{3} M=Pf×Mf+Pb×Mb(3) -
求前景和背景之间的方差:
σ 2 = P f × ( M f − M ) 2 + P b × ( M b − M ) 2 (4) \sigma^2 = Pf\times(Mf-M)^2 + Pb \times(Mb-M)^2\tag{4} σ2=Pf×(Mf−M)2+Pb×(Mb−M)2(4) -
找到阈值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)
return binary
smax, tmax = otsu(gray, 256)
otsu_image = otsu_threshold(tmax, gray)
plt.figure(figsize=(10,10))
ax = plt.subplot(1, 2, 1)
ax.set_title("gray image")
ax.set_xlabel("width")
ax.set_ylabel("height")
plt.imshow(gray, cmap="gray")
ax = plt.subplot(1, 2, 2)
ax.set_title("otsu image")
ax.set_xlabel("width")
ax.set_ylabel("height")
plt.imshow(otsu_image, cmap="gray")
大津阈值法计算量较大,FPGA实现没有意义。
四、FPGA全局128
module ycbcr2binary_global
(
input wire vga_clk ,
input wire sys_rst_n ,
input wire [7:0] y_data ,
input wire rgb_valid ,
output reg [15:0] binary_data
);
wire [7: 0] temp;
reg y_valid;
assign temp = (y_data >= 8'd128)? 8'd255: 8'd0;
always @(posedge vga_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
y_valid <= 1'b0;
else
y_valid <= rgb_valid;
always@(posedge vga_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
binary_data <= 16'd0 ;
else if(y_valid == 1'b1)
binary_data <= {temp[7:3], temp[7:2], temp[7:3]};
else
binary_data <= binary_data;
endmodule
文章来源:https://www.toymoban.com/news/detail-839029.html
总结
全局二值化都比较基础,Python与FPGA实现都较为简单。下期讨论难度升级的局部二值化,敬请期待。文章来源地址https://www.toymoban.com/news/detail-839029.html
到了这里,关于Python与FPGA——全局二值化的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!