Skip to content

main

复制本地路径 | 在线编辑

原始文件为 .py 代码,本文是转换后的 Markdown 文件。

```.py
import cv2
import math
import numpy as np
from scipy import ndimage
from scipy import signal

计算图片的梯度

def compute_grad(img):
# gradX = ndimage.convolve1d(img, [-1, 1])
gradX = -np.diff(img, axis=0, append=0)
gradY = -np.diff(img, axis=1, append=0)

return gradX, gradY

根据梯度计算散度(本质上相当于做拉普拉斯)

def compute_diver(gradX, gradY):
# 这里有一个注意点,相加时 x方向需要右移,y方向需要下移,这个简单推一下就知道原因了
gradXX = np.roll(compute_grad(gradX)[0], 1, axis=1)
gradYY = np.roll(compute_grad(gradY)[1], 1, axis=0)
return gradXX + gradYY

比对一下 拉普拉斯 和 散度计算函数

PS: Opencv 的拉普拉斯感觉并不简便,需要 src 弄成 float,不然计算有问题

my_diver = compute_diver(gradX, gradY)

true_diver = signal.convolve2d(noflash, [[0, 1, 0], [1, -4, 1], [0, 1, 0]], mode='same')

true_diver = cv2.Laplacian(noflash.astype(float), ksize=1, ddepth=-1).astype(int)

直接对图片计算散度(即做一个拉普拉斯滤波)

def laplacian(img):
kernel = [[0, 1, 0], [1, -4, 1], [0, 1, 0]]

if len(img.shape) == 2:
    return signal.convolve2d(img, kernel, mode='same')

result = np.zeros(img.shape)
for i in range(img.shape[-1]):
    result[..., i] = signal.convolve2d(img[..., i], kernel, mode='same')
return result

def recover_img(gradX, gradY, thd=0.1):
# 先计算散度
diver = compute_diver(gradX, gradY)

imgshape = gradX.shape

# 掩膜
B = np.ones(imgshape, dtype=int)
B[0, :] = B[-1, :] = B[:, 0] = B[:, -1] = 0

# 开始求解 Af=b,f为结果,b为散度(diver)
f = np.zeros(imgshape, dtype=float)
b = diver.astype(float)
r = B * (b - laplacian(f))
d = np.copy(r)

# 共轭梯度下降求解 Af=b
# 计算在一维空间做,需要将二维矩阵变成一维向量
f, r, d, B, b = f.flatten(), r.flatten(), d.flatten(), B.flatten(), b.flatten()

# 为了加快速度(每次需要计算oldr*oldr和newr*newr),记录这个 r.T*r
r2 = np.dot(r.T, r)
for i in range(5000):
    Ad = laplacian(d.reshape(imgshape)).flatten()

    # 更新 f
    eta = r2 / np.dot(d.T, Ad)

    f = f + B * (eta * d)

    r = B * (r - eta * Ad)
    error = np.dot(r.T, r)
    d = r + error / r2 * d
    r2 = error

    if error < thd:
        break

print('Total Step is ', i)
print('error = ', error)

# f = (f - f.min()) / (f.max() - f.min()) * 255
f = f.clip(0, 255)
return np.round(f).reshape(imgshape)

计算残差梯度向量

def compute_M(grad_flash, grad_noflash):
gradX1, gradY1 = grad_flash
gradX2, gradY2 = grad_noflash

a = np.abs(gradX1*gradX2 + gradY1*gradY2)
b1 = np.sqrt(gradX1*gradX1 + gradY1*gradY1)
b2 = np.sqrt(gradX2*gradX2 + gradY2*gradY2)

zeros1 = (b1 == 0) 
zeros2 = (b2 == 0)
b1[zeros1] = 1
b2[zeros2] = 1

M = a / (b1 * b2)
M[zeros1 & zeros2] = 1
M[zeros1 & (~zeros2)] = 0
M[(~zeros1) & zeros2] = 1

M = (M-M.min()) / (M.max()-M.min())
return M

计算饱和权重图

def compute_ws(flash, sigma=50, tau=0.7):
z = sigma * (flash / 255 - tau)
# a = np.power(math.e, z)
# b = np.power(math.e, -z)
# ws = (a - b) / (a + b)
ws = np.tanh(z)
ws = (ws - ws.min()) / (ws.max() - ws.min())
return ws

融合闪光和无闪光梯度

def combine_flash_noflash(flash, noflash):
def getY(img):
return cv2.cvtColor(img, cv2.COLOR_BGR2YUV)[..., 0].astype(int)

# 用 Y 分量获取 M 和 ws
flashY, noflashY = getY(flash), getY(noflash)
gradX1, gradY1 = compute_grad(flashY)
gradX2, gradY2 = compute_grad(noflashY)

M = compute_M((gradX1, gradY1), (gradX2, gradY2))
ws = compute_ws(flashY)

# 获取各个颜色的梯度
gradX, gradY = np.zeros(flash.shape), np.zeros(flash.shape)

result = np.zeros(flash.shape)
for c in range(0, 3):
    gradX1, gradY1 = compute_grad(flash[..., c].astype(int))
    gradX2, gradY2 = compute_grad(noflash[..., c].astype(int))

    gradX[..., c] = ws * gradX2 + (1-ws) * (M * gradX1 + (1-M) * gradX2)
    gradY[..., c] = ws * gradY2 + (1-ws) * (M * gradY1 + (1-M) * gradY2)
    result[..., c] = recover_img(gradX[..., c], gradY[..., c], thd=0.0001)

return result.clip(0, 255), (M*255).clip(0, 255), (ws*255).clip(0, 255)

noflash = cv2.imread('./src/noflash.png')
flash = cv2.imread('./src/flash.png')

# 问题一

gradX, gradY = compute_grad(flash)

img = recover_img(gradX, gradY, thd=0.001).clip(0, 255).astype(np.uint8)

delta = flash - img

cv2.imwrite('./result/oneimg-result.png', img.astype(np.uint8))

cv2.imwrite('./result/oneimg-delta.png', flash.astype(np.uint8))

问题五

result, M, ws = combine_flash_noflash(flash, noflash)
cv2.imwrite(f'./result/twoimg-result.png', result.astype(np.uint8))
cv2.imwrite(f'./result/twoimg-M.png', M.astype(np.uint8))
cv2.imwrite(f'./result/twoimg-ws.png', ws.astype(np.uint8))```

Comments