参考这篇文章进行了一些试验:
https://www.analyticsvidhya.com/blog/2019/04/introduction-image-segmentation-techniques-python/
没有完全按照文章的代码,中间我是用skimage.io里的imread,imshow
结果发现提取出来的edge很不明显
然后试着跑了下源代码,发现是这样的
中间的操作几乎都一样,就是读入不一样,于是开始研究
打印出cv2和skimage读入的图片数据一看,一个是小数,一个是整数
中间就是将原图RBG转化为GRAY,然后再进行卷积操作,为什么结果就不一样呢
按照卷积的计算,是小数整数应该是不影响的;
按理说 RBG 0-255 为什么cv2要按浮点数存储,是不是中间有什么特别的过程?
于是查阅资料,这里引用一段话:
”32位屏幕显示的像素最终都是整数值。中间的颜色运算过程最好使用[0,1]之间的浮点数以保证运算精度,只是在最终光栅化到屏幕时才转换成整数,这样只有最后一步才产生一次运算误差,3D显卡都是这样做的。如果中间过程全部使用整数运算,每一步都在积累误差,最终可能导致屏幕显示完全失真。“
那是哪一步计算导致误差出现了吗?一步步排查吧
import matplotlib.pyplot as plt
%matplotlib inline
import numpy as np
from skimage.color import rgb2gray
from scipy import ndimage
from skimage.io import imread, imshow
import cv2
plimage = plt.imread('grid.png')
skimage = imread('grid.png')
第一步,检查读入数据的误差:
for i in range(225):
for j in range(225):
a = skimage[i][j] / 255
b = plimage[i][j]
if not (a == b).all():
print('%d %d not equal' % (i, j))
print(a )
print(b)
break
OUTPUT:
0 81 not equal
[ 1. 1. 0.99215686]
[ 1. 1. 0.99215686]
2 13 not equal
[ 1. 1. 0.99215686]
[ 1. 1. 0.99215686]
3 36 not equal
[ 1. 1. 0.99215686]
[ 1. 1. 0.99215686]
5 8 not equal
[ 0.87843137 0.87843137 0.88235294]
[ 0.87843138 0.87843138 0.88235295]
6 7 not equal
[ 0.55686275 0.56862745 0.57254902]
[ 0.55686277 0.56862748 0.57254905]
7 6 not equal
[ 0.69411765 0.70588235 0.69019608]
[ 0.69411767 0.70588237 0.6901961 ]
8 5 not equal
[ 0.98431373 0.98431373 0.98823529]
[ 0.98431373 0.98431373 0.98823529]
稍微观察下发现,误差其实很小的,继续往下检查,检查rbg转gray
pl_gray = rgb2gray(plimage)
sk_gray = cv2.cvtColor(skimage, cv2.COLOR_BGR2GRAY)
for i in range(225):
for j in range(225):
a = sk_gray[i][j] / 255
b = pl_gray[i][j]
if not (a == b).all():
print('%d %d not equal' % (i, j))
print(a )
print(b)
break
OUTPUT:
0 81 not equal
0.996078431373
0.999434509838
2 13 not equal
0.996078431373
0.999434509838
3 36 not equal
0.996078431373
0.999434509838
能看到误差开始变大了,但是也不该很明显。。
下一步其实就是做卷积了,这里用sobel_horizontal来测试
sobel_horizontal = np.array([[1, 2, 1], [0, 0, 0], [-1, -2, -1]])
sobel_vertical = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])
sk_out_h = ndimage.convolve(sk_gray, sobel_horizontal, mode='reflect')
sk_out_v = ndimage.convolve(sk_gray, sobel_vertical, mode='reflect')
pl_out_h = ndimage.convolve(pl_gray, sobel_horizontal, mode='reflect')
pl_out_v = ndimage.convolve(pl_gray, sobel_vertical, mode='reflect')
for i in range(225):
for j in range(225):
a = sk_out_h[i][j]
b = pl_out_h[i][j]*255
if a != b:
print(i, j)
print(a, b)
break
OUTPUT:
0 80
1 0.144199991405
1 12
255 -0.144199991405
2 35
255 -0.144199991405
3 12
1 0.144199991405
4 7
225 -30.9278981566
5 6
146 -110.56539341
6 5
179 -75.9258954745
7 4
252 -3.92789976588
8 4
231 -24.9278985142
仔细一看数据差距都很大,我尝试了把(1,12)这个点周围的数据拿出来单独计算,
g_sk = sk_gray[0:3, 11:14]
p_sk = pl_gray[0:3, 11:14]
print(g_sk)
print(p_sk)
print()
print(sobel_horizontal)
print(ndimage.convolve(g_sk, sobel_horizontal, mode='reflect'))
print(ndimage.convolve(p_sk, sobel_horizontal, mode='reflect'))
这里就不贴结果了...反正就是结果对不上,和我手算的结果也不一样。
然后仔细查了scipy.convolve的文档,以及matlab conv2d的文档
发现算法都没有问题...突然发现skimage读入的数据类型是 uint8
就 会 溢 出!
转为int16,跑出来结果几乎一样
" convert gray to int16 before convolve"
gray = gray.astype(np.int16)
out_h = ndimage.convolve(gray, sobel_hor, mode='reflect')
out_v = ndimage.convolve(gray, sobel_ver, mode='reflect')
结论?这么简单的计算里。。误差还不大吧。。。
浪费了一大波时间