BF_FPGA
原始文件为 .py 代码,本文是转换后的 Markdown 文件。
```.py
import numpy as np
双边 → 模拟 FPGA 实现,没有除法
def BF1(img, sigmaColor, sbit=10, Gs=16, Ws=16):
img = img.astype(int)
# 预先存储 G
sigmaColor *= 4096 / 256
G = np.array([i for i in range(4096)])
G = np.exp(-((G / sigmaColor)**2) / 2)
G = G[0:4096:Gs]
S = (2 ** sbit)
G = np.round(G * (S-1)).astype(int)
# W = np.array([i for i in range(0, S*12)]) + S * 4
# W = np.round((S/W)*S-1).astype(int)
W = np.array([i for i in range(0, int(S*16/Ws))])
W = np.round((S/(W*Ws+4*S))*S-1).astype(int)
# 空间固定 3x3,注意中间变成了 0
F = np.array([[1, 2, 1], [2, 0, 2], [1, 2, 1]])
new_img = np.zeros(img.shape)
for i in range(1, img.shape[0]-1):
for j in range(1, img.shape[1]-1):
# 和中心的差值
D = np.abs(img[i-1:i+2, j-1:j+2] - img[i, j])
# 高斯和颜色相乘
now_W = F * G[D//Gs]
b = np.sum(now_W)
if b == 0:
new_img[i, j] = img[i, j]
else:
# 分母
a = np.sum(now_W * img[i-1:i+2, j-1:j+2]) + img[i, j]*4* S
# 分子,+1 是因为事先计算 W 的时候减了 1(否则最大值为S/4,溢出)
b = W[b//Ws] + 1
new_img[i, j] = a * b / (S * S)
return new_img
FPGA 实现,有除法
def BF2(img, sigmaColor, size, Gs, x):
img = img.astype(int)
F = None
if size == 3:
F = np.array([[1, 2, 1], [2, 4, 2], [1, 2, 1]])
if size == 5:
F = np.zeros((5, 5))
F[0] = F[4] = np.array([1, 4, 7, 4, 1])
F[1] = F[3] = np.array([4, 16, 26, 16, 4])
F[2] = F[2] = np.array([7, 26, 41, 26, 7])
# 预先存储 G
# sigmaColor *= 4096 / 256
# G = np.array([i for i in range(4096)])
# G = np.exp(-((G / sigmaColor)**2) / 2)
# # FPGA 中的 G:缩小+量化
# G = G[0:4096:Gs]
# G = (G * ((1<<x)-1)).astype(int)
# G = np.array([i for i in range(256)])
# G = 63 * np.exp(-8 * ((G/sigmaColor)**2))
# G = G.astype(int)
# nowGs = 256 // 64
# 8bit 计算
G = np.array([i for i in range(256)])
G = np.exp(-((G / sigmaColor)**2) / 2)
G = G[0:256:Gs]
G = (G * ((1<<x)-1)).astype(int)
with open('./BF_G.txt', 'w') as f:
for Gidx in G:
f.writelines(str(Gidx)+'\n')
# G = np.array([i for i in range(256)])
# G = np.exp(-((G / sigmaColor)**2) / 2)
# G = G[0:256]
# G = (G * ((1<<x)-1)).astype(int)
r = size // 2
new_img = np.copy(img).astype(float)
for i in range(r, img.shape[0]-r):
for j in range(r, img.shape[1]-r):
# 和中心的插值
D = np.abs(img[i-r:i+r+1, j-r:j+r+1] - img[i, j])
# 分母
now_W = F * G[D//Gs]
result = np.sum(now_W * img[i-r:i+r+1, j-r:j+r+1]) / np.sum(now_W)
new_img[i, j] = result
return new_img
def goodBilateral(img, sigmaColor, size):
img = img.astype(int)
# 空间固定 3x3
F = None
if size == 3:
F = np.array([[1, 2, 1], [2, 4, 2], [1, 2, 1]])
if size == 5:
F = np.zeros((5, 5))
F[0] = F[4] = np.array([1, 4, 7, 4, 1])
F[1] = F[3] = np.array([4, 16, 26, 16, 4])
F[2] = F[2] = np.array([7, 26, 41, 26, 7])
# 预先存储 G
sigmaColor *= 4096 / 256
G = np.array([i for i in range(4096)])
G = np.exp(-((G / sigmaColor)**2) / 2)
r = size // 2
new_img = np.copy(img).astype(float)
for i in range(r, img.shape[0]-r):
for j in range(r, img.shape[1]-r):
# 和中心的插值
D = np.abs(img[i-r:i+r+1, j-r:j+r+1] - img[i, j])
# 分母
now_W = F * G[D]
result = np.sum(now_W * img[i-r:i+r+1, j-r:j+r+1]) / np.sum(now_W)
new_img[i, j] = result
return new_img
# 输入 bad_img, uint16
bad_img = np.fromfile(f'./test.raw', dtype=np.uint16)
bad_img = bad_img.reshape(2000, 2048)
sigma = 100
size = 3
r = size//2
cv_img = goodBilateral(bad_img, sigma, size=size)
cv_img = cv_img[r:-r, r:-r].clip(0, 4095).astype(int)
print('max', cv_img.max(), 'min', cv_img.min())
# for Gs in [1, 2, 4, 8, 16]:
# for Ws in [8, 16, 32, 64]:
# my_img = BF1(bad_img, 128, x=11, Gs=Gs, Ws=Ws)
# my_img = my_img[1:-1, 1:-1]
# delta = cv_img - my_img
# print(Gs, Ws, ':', delta.max(), delta.min(), np.mean(np.abs(delta)))
# for Gs in [128, 64]:
# for x in [4, 6, 8, 10, 12]:
# my_img = BF2(bad_img, 30, Gs=Gs, x=x)
# my_img = my_img[1:-1, 1:-1].clip(0, 4095).astype(int)
# delta = cv_img - my_img
# print(Gs, x, ':', delta.max(), delta.min(), np.mean(np.abs(delta)))
# import cv2
# for x in [4, 6, 8, 10, 12]:
# my_img = BF2(bad_img, 10, Gs=None, x=x)
# my_img = my_img[1:-1, 1:-1].clip(0, 4095).astype(int)
# delta = cv_img - my_img
# print(x, ':', delta.max(), delta.min(), np.mean(np.abs(delta)))
# cv2.imwrite('./bf.png', (my_img/16).astype(np.uint8))
my_img = BF2(bad_img, sigma, Gs=64, x=6, size=size)
# my_img = my_img[r:-r, r:-r].clip(0, 4095).astype(int)
# delta = cv_img - my_img
# print(delta.max(), delta.min(), np.mean(np.abs(delta)))
print(my_img.shape, my_img.dtype)
my_img = my_img.clip(0, 4095).astype(np.uint16)
my_img.tofile('./BF_result_2.raw')
输入 bad_img, uint16
import cv2
good_img = cv2.imread('./good_pic.png')
good_img = cv2.cvtColor(good_img, cv2.COLOR_BGR2GRAY)
gauss = np.random.normal(0, 40, good_img.shape)
bad_img = good_img + gauss
bad_img = bad_img.clip(0, 255).astype(np.uint8)
sigma = 120
size = 5
r = size//2
cv_img = cv2.bilateralFilter(bad_img, d=5, sigmaColor=sigma, sigmaSpace=75)
my_img = BF2(bad_img, sigmaColor=sigma, size=5, Gs=4, x=6)
my_img = my_img.clip(0, 255).astype(np.uint8)
cv2.imwrite('./bf-my.png', my_img)
cv2.imwrite('./bf-cv.png', cv_img)
cv_img = cv_img.astype(float)
my_img = my_img.astype(float)
delta = cv_img[5:-5, 5:-5] - my_img[5:-5, 5:-5]
print(delta.max(), delta.min(), np.mean(np.abs(delta)))```