共计 5629 个字符,预计需要花费 15 分钟才能阅读完成。
提醒:本文最后更新于 2024-08-30 14:54,文中所关联的信息可能已发生改变,请知悉!
前一次的工作
改进 find_best
根据一段时间对于图像降噪的经验来看,总觉得上次的处理图怪怪的,虽然确实没有了所谓 1:7 的噪声区域,从结果来看似乎是正常的。但还是再调试了一下,发现确实有可改进之处
测试效果
原图:
噪声图:
处理图:
结果分析
- 这是当 k = 1 时,进行 10 次降噪之后的结果,从结果看,无明显 1:7 类型的噪声存在
- 与上一次工作的处理图相比,降噪效果更好
- 降噪在进行到第四次时,被处理掉的噪声比例已经明显降低
- 第五次时,更低
- 从第六次降噪完之后,就不再出现新减少的噪声
本次工作
对于前一次工作的成果进行进一步处理,使用 k = 2 作为多尺度指数进行降噪
代码示例
# python3.8
# utf-8
from denoise1 import main as dn1m
from denoise2 import main as dn2m
if __name__ == '__main__':
# dn1m('img.png', 'img_1.png', 1)
dn2m('img.png', 'img_2.png', 2)
调用 denoise2.py
# python 3.8
# utf-8
import cv2 as cv
import numpy as np
# 二维数组映射到一维
def _2d_2_1d(x, y):
if x == 0 and y == 0:
return int(0)
elif x == 0 and y == 1:
return int(1)
elif x == 0 and y == 2:
return int(2)
elif x == 1 and y == 2:
return int(3)
elif x == 2 and y == 2:
return int(4)
elif x == 2 and y == 1:
return int(5)
elif x == 2 and y == 0:
return int(6)
elif x == 1 and y == 0:
return int(7)
elif x == 1 and y == 1:
return int(8)
def _1d_2_2d(x):
if x == 0:
return 0, 0
elif x == 1:
return 0, 1
elif x == 2:
return 0, 2
elif x == 3:
return 1, 2
elif x == 4:
return 2, 2
elif x == 5:
return 2, 1
elif x == 6:
return 2, 0
elif x == 7:
return 1, 0
def division(_8):
result = [0] * 8
p1 = [_8[0][0], _8[0][1], _8[0][2], _8[1][2], _8[2][2], _8[2][1], _8[2][0],
_8[1][0]]
p = sorted(p1)
q = [abs(int(p[0]) - int(p[1])), abs(int(p[1]) - int(p[2])), abs(int(p[2]) - int(p[3])), abs(int(p[3]) - int(p[4])),
abs(int(p[4]) - int(p[5])), abs(int(p[5]) - int(p[6])), abs(int(p[6]) - int(p[7]))]
# 判断区分度
if max(q) < 10:
return result, False
max_index = q.index(max(q))
for i in range(0, max_index + 1):
for j in range(len(q)):
if p1[j] == p[i]:
result[j] = 1
for i in range(8):
if result[i] != 1:
result[i] = 2
return result, True
def find_best(a, x, y, flag):
p = a[x][y]
neighborhood = []
if flag[x - 1][y - 1] == 0:
neighborhood.append(a[x - 1][y - 1])
if flag[x - 1][y] == 0:
neighborhood.append(a[x - 1][y])
if flag[x - 1][y + 1] == 0:
neighborhood.append(a[x - 1][y + 1])
if flag[x][y + 1] == 0:
neighborhood.append(a[x][y + 1])
if flag[x + 1][y + 1] == 0:
neighborhood.append(a[x + 1][y + 1])
if flag[x + 1][y] == 0:
neighborhood.append(a[x + 1][y])
if flag[x + 1][y - 1] == 0:
neighborhood.append(a[x + 1][y - 1])
if flag[x][y - 1] == 0:
neighborhood.append(a[x][y - 1])
d = []
for i in range(len(neighborhood)):
d.append(abs(int(neighborhood[i]) - int(p)))
if len(d) == 0:
return p
min_index = d.index(min(d))
return neighborhood[min_index]
def find_noise(x, y, channel, flag, flag0, sub_flag):
for i in range(1, x - 1):
for j in range(1, y - 1):
# 取出九宫格
a = [[0] * 3 for ix in range(3)]
for i0 in range(3):
for j0 in range(3):
a[i0][j0] = channel[i - 1 + i0][j - 1 + j0]
# 划分区域
div, div_flag = division(a)
if not div_flag:
continue
cnt = 0
for i0 in range(8):
if div[i0] == 1:
cnt += 1
if cnt == 1:
for i0 in range(8):
if div[i0] == 1:
x0, y0 = _1d_2_2d(i0)
if flag[i - 1 + x0][j - 1 + y0] == 1 and flag0[i - 1 + x0][j - 1 + y0] == 0:
sub_flag += 1
flag0[i - 1 + x0][j - 1 + y0] = 1
elif cnt == 7:
for i0 in range(8):
if div[i0] == 2:
x0, y0 = _1d_2_2d(i0)
if flag[i - 1 + x0][j - 1 + y0] == 1 and flag0[i - 1 + x0][j - 1 + y0] == 0:
sub_flag += 1
flag0[i - 1 + x0][j - 1 + y0] = 1
return flag0, sub_flag
def shrunk(channel, k):
x, y = channel.shape
result = np.zeros((k, k), dtype=type(channel))
for i in range(k):
for j in range(k):
result0 = np.zeros((x // k, y // k))
for m in range(0, x // k):
for n in range(0, y // k):
if m * k + i < x and n * k + j < y:
result0[m][n] = channel[m * k + i][n * k + j]
result[i][j] = result0
return result
def merge_array(array, x, y, k):
result = np.zeros((x, y))
for i in range(k):
for j in range(k):
for m in range(x // k):
for n in range(y // k):
result[m * k + i][n * k + j] = array[i][j][m][n]
return result
def denoise_1_7(channel, flag, k):
"""
:param channel: 待检测通道
:param flag: 噪声标记
:param k: 多尺度指数
:return: 被找到的噪声个数
"""
if k == 2:
x, y = channel.shape
flag0 = np.zeros((k, k), dtype=type(channel))
sub_flag = 0
shrunk_channel = shrunk(channel, k)
for i in range(k):
for j in range(k):
sx, sy = shrunk_channel[0][0].shape
flag00 = np.zeros((sx, sy))
flag00, sub_flag = find_noise(sx, sy, shrunk_channel[i][j], flag, flag00, sub_flag)
flag0[i][j] = flag00
for m in range(1, sx - 1):
for n in range(1, sy - 1):
if flag[m * k + i][n * k + j] == 1:
shrunk_channel[i][j][m][n] = find_best(shrunk_channel[i][j], m, n, flag00)
# flag0 = merge_array(flag0, x, y, k)
channel = merge_array(shrunk_channel, x, y, k)
'''
for i in range(1, x - 1):
for j in range(1, y - 1):
if flag[i][j] == 1:
channel[i][j] = find_best(channel, i, j, flag0)
'''
return channel, sub_flag
def denoise(noise, noise_flag, k):
"""
:param noise: 噪声图像
:param noise_flag: 噪声标记
:param k: 多尺度指数
:return: 修改后的噪声图像,被找到的噪声
"""
b_noise, g_noise, r_noise = cv.split(noise)
sub_flag = 0
b_noise, f = denoise_1_7(b_noise, noise_flag[0], k)
sub_flag += f
g_noise, f = denoise_1_7(g_noise, noise_flag[1], k)
sub_flag += f
r_noise, f = denoise_1_7(r_noise, noise_flag[2], k)
sub_flag += f
new_noise = cv.merge((b_noise, g_noise, r_noise))
return new_noise, sub_flag
def get_noise_flag(origin, noise):
"""
:param origin: Mat 原图
:param noise: Mat 噪声图
:return: flag 矩阵
"""
b_origin, g_origin, r_origin = cv.split(origin)
b_noise, g_noise, r_noise = cv.split(noise)
row, col = b_origin.shape
flag = np.zeros((3, row, col))
cnt_flag = 0
for i in range(row):
for j in range(col):
if b_origin[i][j] != b_noise[i][j]:
flag[0][i][j] = 1
cnt_flag += 1
if g_origin[i][j] != g_noise[i][j]:
flag[1][i][j] = 1
cnt_flag += 1
if r_origin[i][j] != r_noise[i][j]:
flag[2][i][j] = 1
cnt_flag += 1
return flag, cnt_flag
def main(origin, noise, k):
"""
:param origin: 原始标准图片路径
:param noise: 噪声图路径
:param k: 多尺度指数
:return:
"""
img_origin = cv.imread(origin, 1)
img_noise = cv.imread(noise, 1)
noise_flag, cnt_flag = get_noise_flag(img_origin, img_noise)
print(' 原噪声个数:', cnt_flag)
noises = [img_noise]
for i in range(10):
new, sub_flag = denoise(noises[i], noise_flag, k)
noises.append(new)
print('[' + str(i + 1) + ']', sub_flag / cnt_flag)
cv.imwrite('new.png', noises[9])
if __name__ == '__main__':
origin_addr = 'img_1.png'
noise_addr = 'img_2.png'
main(origin_addr, noise_addr, 2)
结果
原噪声个数:21447
[1] 0.02802256725882408
[2] 0.0180444817456987
[3] 0.017997855177880356
[4] 0.017997855177880356
结果分析
原噪声个数
原噪声个数与预期不符。这是因为噪声检测程序是利用原图与 k = 1 时得到的图片比对得出噪声,而大部分在 k = 1 时被修改的噪声不可能准确的还原为原值(而是利用附近的非噪声值代替),所以在 k = 2 时,比对所得的噪声个数会比预期多很多,所以噪声个数失去了参考价值
降噪比
由于上述噪声个数的原因,降噪比也只能用做降噪是否彻底的参考(即,该数值稳定后,降噪完成)
降噪效果
下图为 k = 1 的降噪图,比对上图(k = 2 降噪图)发现,前一次残留的连在一起的噪声几乎都被去除;只在图像的内部残留零星的单个噪声点,这可以再次利用 k = 1 来解;而图像的边界的降噪效果仍然不好,由于 k = 2 时会丢失更多的信息,所以,效果会比 k = 1 时要差
正文完