在二值图像的 Numpy 矩阵上通过矩阵运算计算均方误差
Calculating Mean Squared Error through Matrix Arithmetic on Numpy Matrices of Binary Images
我有2张二值图像,一张是ground truth,一张是我制作的图像分割。
我正在尝试计算均方距离...
Let G = {g1, g2, . . . , gN} be the points in the ground truth boundary.
Let B = {b1, b2, . . . , bM} be the points in the segmented boundary.
Define d(p, p0) be a measure of distance between points p and p0 (e.g. Euclidean, city block, etc.)
使用以下算法在两个图像之间。
def MSD(A,G):
'''
Takes a thresholded binary image, and a ground truth img(binary), and computes the mean squared absolute difference
:param A: The thresholded binary image
:param G: The ground truth img
:return:
'''
sim = np.bitwise_xor(A,G)
sum = 0
for i in range(0,sim.shape[0]):
for j in range(0,sim.shape[1]):
if (sim[i,j] == True):
min = 9999999
for k in range(0,sim.shape[0]):
for l in range(0,sim.shape[1]):
if (sim[k, l] == True):
e = abs(i-k) + abs(j-l)
if e < min:
min = e
mink = k
minl = l
sum += min
return sum/(sim.shape[0]*sim.shape[1])
虽然这个算法太慢而且永远不会完成。
此 example and this example(答案 3)可能显示了如何使用矩阵算术获得均方误差的方法,但我不明白这些示例有何意义或它们为何起作用。
所以如果我正确理解你的公式和代码,你就有一个(二进制)图像 B
和一个(地面实况)图像 G
。 "Points" 由任一图像具有 True
(或至少非零)值的像素位置定义。从你的 bitwise_xor
我推断出两个图像具有相同的形状 (M,N)
.
所以数量 d^2(b,g)
最多是一个 (M*N, M*N)
大小的数组,将 B
的每个像素与 G
的每个像素相关联。更好的是:如果 B
中有 m
个非零值且 G
中有 n
个非零值,我们只需要形状 (m,n)
。除非你的图片很大,否则我们可以跟踪这么大的数量。这将消耗内存,但我们将通过矢量化赢得大量 CPU 时间。因此,对于每个 m
,我们只需要找到关于每个 n
可能值的距离的最小值。然后总结每个最小值。请注意,下面的解决方案使用了极端矢量化,如果图像很大,它很容易耗尽你的内存。
假设曼哈顿距离(您的代码中似乎缺少 d^2
中的正方形):
import numpy as np
# generate dummy data
M,N = 100,100
B = np.random.rand(M,N) > 0.5
G = np.random.rand(M,N) > 0.5
def MSD(B, G):
# get indices of nonzero pixels
nnz_B = B.nonzero() # (x_inds, y_inds) tuple, x_inds and y_inds are shape (m,)
nnz_G = G.nonzero() # (x_inds', y_inds') each with shape (n,)
# np.array(nnz_B) has shape (2,m)
# compute squared Manhattan distance
dist2 = abs(np.array(nnz_B)[...,None] - np.array(nnz_G)[:,None,:]).sum(axis=0)**2 # shape (m,n)
# alternatively: Euclidean for comparison:
#dist2 = ((np.array(nnz_B)[...,None] - np.array(nnz_G)[:,None,:])**2).sum(axis=0)
mindist2 = dist2.min(axis=-1) # shape (m,) of minimum square distances
return mindist2.mean() # sum divided by m, i.e. the MSD itself
print(MSD(B, G))
如果上面使用了太多内存,我们可以在 nnz_B
的元素上引入一个循环,并且只对 nnz_G
的元素进行矢量化。这将需要更多 CPU 功率和更少内存。这种权衡是矢量化的典型特征。
计算此距离的一种有效方法是使用距离变换。 SciPy 在 ndimage 包中有一个实现:scipy.ndimage.morphology.distance_transform_edt.
想法是计算真实图像背景的距离变换G
。这导致新图像 D
对于 G
中的每个非零像素为 0,对于 G
中的每个零像素,将有到最近的非零像素的距离。
接下来,对于 B
(或您发布的代码中的 A
)中的每个非零像素,您查看 D
中的相应像素。这是该像素到 G
的距离。因此,只需对 D
中 B
非零的所有值进行平均即可获得结果。
import numpy as np
import scipy.ndimage as nd
import matplotlib.pyplot as pp
# Create some test data
img = pp.imread('erika.tif') # a random image
G = img > 120 # the ground truth
img = img + np.random.normal(0, 20, img.shape)
B = img > 120 # the other image
D = nd.morphology.distance_transform_edt(~G)
msd = np.mean(D[B]**2)
我有2张二值图像,一张是ground truth,一张是我制作的图像分割。
我正在尝试计算均方距离...
Let G = {g1, g2, . . . , gN} be the points in the ground truth boundary.
Let B = {b1, b2, . . . , bM} be the points in the segmented boundary.
Define d(p, p0) be a measure of distance between points p and p0 (e.g. Euclidean, city block, etc.)
使用以下算法在两个图像之间。
def MSD(A,G):
'''
Takes a thresholded binary image, and a ground truth img(binary), and computes the mean squared absolute difference
:param A: The thresholded binary image
:param G: The ground truth img
:return:
'''
sim = np.bitwise_xor(A,G)
sum = 0
for i in range(0,sim.shape[0]):
for j in range(0,sim.shape[1]):
if (sim[i,j] == True):
min = 9999999
for k in range(0,sim.shape[0]):
for l in range(0,sim.shape[1]):
if (sim[k, l] == True):
e = abs(i-k) + abs(j-l)
if e < min:
min = e
mink = k
minl = l
sum += min
return sum/(sim.shape[0]*sim.shape[1])
虽然这个算法太慢而且永远不会完成。
此 example and this example(答案 3)可能显示了如何使用矩阵算术获得均方误差的方法,但我不明白这些示例有何意义或它们为何起作用。
所以如果我正确理解你的公式和代码,你就有一个(二进制)图像 B
和一个(地面实况)图像 G
。 "Points" 由任一图像具有 True
(或至少非零)值的像素位置定义。从你的 bitwise_xor
我推断出两个图像具有相同的形状 (M,N)
.
所以数量 d^2(b,g)
最多是一个 (M*N, M*N)
大小的数组,将 B
的每个像素与 G
的每个像素相关联。更好的是:如果 B
中有 m
个非零值且 G
中有 n
个非零值,我们只需要形状 (m,n)
。除非你的图片很大,否则我们可以跟踪这么大的数量。这将消耗内存,但我们将通过矢量化赢得大量 CPU 时间。因此,对于每个 m
,我们只需要找到关于每个 n
可能值的距离的最小值。然后总结每个最小值。请注意,下面的解决方案使用了极端矢量化,如果图像很大,它很容易耗尽你的内存。
假设曼哈顿距离(您的代码中似乎缺少 d^2
中的正方形):
import numpy as np
# generate dummy data
M,N = 100,100
B = np.random.rand(M,N) > 0.5
G = np.random.rand(M,N) > 0.5
def MSD(B, G):
# get indices of nonzero pixels
nnz_B = B.nonzero() # (x_inds, y_inds) tuple, x_inds and y_inds are shape (m,)
nnz_G = G.nonzero() # (x_inds', y_inds') each with shape (n,)
# np.array(nnz_B) has shape (2,m)
# compute squared Manhattan distance
dist2 = abs(np.array(nnz_B)[...,None] - np.array(nnz_G)[:,None,:]).sum(axis=0)**2 # shape (m,n)
# alternatively: Euclidean for comparison:
#dist2 = ((np.array(nnz_B)[...,None] - np.array(nnz_G)[:,None,:])**2).sum(axis=0)
mindist2 = dist2.min(axis=-1) # shape (m,) of minimum square distances
return mindist2.mean() # sum divided by m, i.e. the MSD itself
print(MSD(B, G))
如果上面使用了太多内存,我们可以在 nnz_B
的元素上引入一个循环,并且只对 nnz_G
的元素进行矢量化。这将需要更多 CPU 功率和更少内存。这种权衡是矢量化的典型特征。
计算此距离的一种有效方法是使用距离变换。 SciPy 在 ndimage 包中有一个实现:scipy.ndimage.morphology.distance_transform_edt.
想法是计算真实图像背景的距离变换G
。这导致新图像 D
对于 G
中的每个非零像素为 0,对于 G
中的每个零像素,将有到最近的非零像素的距离。
接下来,对于 B
(或您发布的代码中的 A
)中的每个非零像素,您查看 D
中的相应像素。这是该像素到 G
的距离。因此,只需对 D
中 B
非零的所有值进行平均即可获得结果。
import numpy as np
import scipy.ndimage as nd
import matplotlib.pyplot as pp
# Create some test data
img = pp.imread('erika.tif') # a random image
G = img > 120 # the ground truth
img = img + np.random.normal(0, 20, img.shape)
B = img > 120 # the other image
D = nd.morphology.distance_transform_edt(~G)
msd = np.mean(D[B]**2)