在做项目的过程中,想比较 同一幅图像 的 二值化处理结果 和 人工标注的ground_truth图 之间的差异。
因为这两幅用来比较的图在生成的时候都是 二值图像(即像素值非 0 即 255),所以用来求差异图的代码段,我想当然地这么写:
for i in range(h):
for j in range(w):
if thresh_pic[i, j, 0] == 0 and label_pic[i, j, 0] == 0:
diff_pic[i, j, :] = 0
elif thresh_pic[i, j, 0] == 255 and label_pic[i, j, 0] == 255:
diff_pic[i, j, :] = 255
elif thresh_pic[i, j, 0] == 0 and label_pic[i, j, 0] == 255:
diff_pic[i, j, 2] = 255
elif thresh_pic[i, j, 0] == 255 and label_pic[i, j, 0] == 0:
diff_pic[i, j, 1] = 255
else:
logging.error('({},{}): thresh={}, label={}'.format(i, j, thresh_pic[i, j, 0], label_pic[i, j, 0]))
在差异比对效果图出来之后却看到了很诡异的现象,图片中出现了很多黑色麻花,如下图:
logging打印出来的结果也显示有很多 既非 0 也非 255 的像素点:
...
ERROR:root:(279,535): thresh=254, label=0
ERROR:root:(279,576): thresh=253, label=0
ERROR:root:(279,581): thresh=253, label=0
...
经过观察,我发现某些像素点在 存储为图片 之前 像素值 还是 255 或 0,存为图片 以后,就会变成了245~255或0~10范围内的随机数(在不懂原理的我看来感觉那就是随机偏移,真实情况其实应该是按照某个算法进行了对应的偏移)了。初步猜测是在 存储为图片时 或 从图片读取出来时,部分像素点 发生了 像素值 的 少许偏移。
于是我修改了代码,考虑到了一个 阈值为10 的 像素值偏移区间:
for i in range(h):
for j in range(w):
if thresh_pic[i, j, 0] < 10 and label_pic[i, j, 0] < 10:
diff_pic[i, j, :] = 0
elif thresh_pic[i, j, 0] > 245 and label_pic[i, j, 0] > 245:
diff_pic[i, j, :] = 255
elif thresh_pic[i, j, 0] < 10 and label_pic[i, j, 0] > 245:
diff_pic[i, j, 2] = 255
elif thresh_pic[i, j, 0] > 245 and label_pic[i, j, 0] < 10:
diff_pic[i, j, 1] = 255
else:
logging.error('({},{}): thresh={}, label={}'.format(i, j, thresh_pic[i, j, 0], label_pic[i, j, 0]))
这次黑色麻花没有了,logging也没有打印error信息了:
经过上网查找,我发现原来一些细心的前辈们也发现这个问题了,并给出了解答:
Soga,原来是因为:
那么好奇心大发作的我又想拿我最爱的妹子图来进一步探究一下。
像素点的像素值变化 | 置色方案 |
---|---|
不变 | 黑色 |
增加 | 绿色 |
减少 | 红色 |
原图像:
100轮 存-读 之后的图像:
原图像 与 第1轮 存-读 后的 图像差异:
第1轮 存-读 后的图像 与 第2轮 存-读 后的 图像差异:
第2轮 存-读 后的图像 与 第3轮 存-读 后的 图像差异:
第3轮 存-读 后的图像 与 第4轮 存-读 后的 图像差异:
第4轮 存-读 后的图像 与 第5轮 存-读 后的 图像差异:
# coding=utf-8
first_path = './data/first.jpg'
second_path = './data/second.jpg'
third_path = './data/third.jpg'
forth_path = './data/forth.jpg'
fifth_path = './data/fifth.jpg'
one_hundred_path = './data/one_hundred.jpg'
import cv2
import numpy as np
import logging
# 生成并保存 俩图像 的 差异图
def compare(pic1, pic2, dst_path):
h, w, c = pic1.shape
diff_pic = np.zeros_like(pic1, dtype=np.uint8)
for i in range(h):
for j in range(w):
if pic1[i, j, 0] == pic2[i, j, 0]: # 像素值 不变,该点 置 黑色
diff_pic[i, j, :] = 0
elif pic1[i, j, 0] < pic2[i, j, 0]: # 像素值 增加,该点 置 绿色
diff_pic[i, j, 1] = 255
elif pic1[i, j, 0] > pic2[i, j, 0]: # 像素值 减少,该点 置 红色
diff_pic[i, j, 2] = 255
else:
logging.error('({},{}): pic1={}, pic2={}'.format(i, j, pic1[i, j, 0], pic2[i, j, 0]))
cv2.imwrite(dst_path, diff_pic)
return diff_pic
# 指定轮数 进行 循环 存储和读取
def save_and_read_cycle(pic, path, num):
for _ in xrange(num):
cv2.imwrite(path, pic)
pic = cv2.imread(path)
return pic
# 原图像
origin_pic = cv2.imread('./data/girl.jpg')
# 需要 循环 1次 的图像
first_pic = origin_pic.copy()
first_pic = save_and_read_cycle(first_pic, first_path, 1)
# 需要 循环 2次 的图像
second_pic = origin_pic.copy()
second_pic = save_and_read_cycle(second_pic, second_path, 2)
# 需要 循环 3次 的图像
third_pic = origin_pic.copy()
third_pic = save_and_read_cycle(third_pic, third_path, 3)
# 需要 循环 4次 的图像
forth_pic = origin_pic.copy()
forth_pic = save_and_read_cycle(forth_pic, forth_path, 4)
# 需要 循环 5次 的图像
fifth_pic = origin_pic.copy()
fifth_pic = save_and_read_cycle(fifth_pic, fifth_path, 5)
# 需要 循环 100次 的图像
one_hundred_pic = origin_pic.copy()
one_hundred_pic = save_and_read_cycle(one_hundred_pic, one_hundred_path, 100)
# 求 循环 存储和读取 后 该图片 与 原图像 差异
ori_fir = compare(origin_pic, first_pic, 'data/ori_fir.jpg')
fir_sec = compare(first_pic, second_pic, 'data/fir_sec.jpg')
sec_thi = compare(second_pic, third_pic, 'data/sec_thi.jpg')
thi_for = compare(third_pic, forth_pic, 'data/thi_for.jpg')
for_fif = compare(forth_pic, fifth_pic, 'data/for_fif.jpg')
ori_hundred = compare(origin_pic, one_hundred_pic, 'data/ori_hundred.jpg')
不足之处 |
---|
没有进一步探究压缩算法的原理 |
没有实验出像素值的偏移区间范围 |
没有探究循环读写的失真率变化原因 |
没有制作循环读写的失真率变化曲线图 |
缺少其他图片进行对比试验,验证实验结论的泛化性 |
没有在单通道灰度图像上做实验 |