让我们说我希望在python中实现以下代码
此函数将图像作为一维数组,并迭代数组中的各个元素(输入图像中的像素),这会影响输出数组,该输出数组也是表示为1维数组的图像
例如: 输入图像中的单个像素(红色)影响(橙色)中的8个周围像素
C中的基本实现是
/* C version
* Given an input image create an
* output image that is shaped by individual pixels
* of the input image
*/
int image[width * height]; //image retrieved elsewhere
int output [width * height]; //output image
int y = 0, x = 0;
for( y = 1; y < height-1 ; ++ y) {
for(x = 1; x < width-1; ++ x) {
if (image[y * width + x] > condition) {
/* pixel affects the surrounding 8 pixels in the output image */
output[(y-1) * width + x - 1]++; /* upper left */
output[(y-1) * width + x ]++; /* above */
output[(y-1) * width + x + 1]++; /* upper right */
output[y * width + x + 1 ]++; /* right */
output[y * width + x - 1 ]++; /* left */
output[(y+1) * width + x - 1]++; /* lower left */
output[(y+1) * width + x ]++; /* below */
output[(y+1) * width + x + 1]++; /* lower right */
}
}
}
python中的天真方法是使用完全相同的元素明智访问,如下所示
#Python version
input = blah # formed elsewhere
output = np.zeros(width * height)
for y in xrange(1, height-1):
for x in xrange(1, width-1):
if input[y * width + x] > condition:
output[(y-1) * width + x - 1]+= 1; # upper left
output[(y-1) * width + x ]+= 1; # above
output[(y-1) * width + x + 1]+= 1; # upper right
output[y * width + x + 1 ]+= 1; # right
output[y * width + x - 1 ]+= 1; # left
output[(y+1) * width + x - 1]+= 1; # lower left
output[(y+1) * width + x ]+= 1; # below
output[(y+1) * width + x + 1]+= 1; # lower right
有更好的方法来实现这个吗?是否可以对此函数进行矢量化?
答案 0 :(得分:5)
如果我正确地理解了这个问题,那么这种方法可以颠倒过来:如果一个像素在其邻域中具有与条件匹配的像素,则为每个匹配将其递增一。对所有像素执行此操作。 Scipy(以及其他)为filtering images提供了工具:
In [51]: import scipy.ndimage
从1维数组中创建样本图像。重塑创建视图而不是复制:
In [62]: I1d
Out[62]:
array([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 129, 0, 129, 129, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129])
In [63]: height
Out[63]: 8
In [64]: width
Out[64]: 8
In [65]: I = I1d.reshape((height, width))
In [66]: I
Out[66]:
array([[ 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 129, 0, 129, 129, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 129, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 129]])
使用卷积创建一个图像,该图像通过超出条件的二进制掩码(此处为128)保存原始图像中每个像素的增量:
In [67]: scipy.ndimage.filters.convolve(
(I > 128).astype(np.int), # conditioned binary image
weights=np.array([[1, 1, 1], # each match weighted as 1
[1, 0, 1],
[1, 1, 1]]),
mode='constant', cval=0) # Use zeros as constant fill values on edges
Out[67]:
array([[0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 1, 2, 2, 2, 1, 0],
[0, 1, 0, 2, 1, 1, 1, 0],
[0, 1, 1, 3, 3, 3, 1, 0],
[0, 0, 0, 1, 0, 1, 0, 0],
[0, 0, 0, 1, 1, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 1],
[0, 0, 0, 0, 0, 0, 1, 0]])
In [68]: conv = _
如果最终目标是添加原始和增量:
In [69]: I + conv
Out[69]:
array([[ 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 1, 1, 2, 2, 2, 1, 0],
[ 0, 1, 129, 2, 130, 130, 1, 0],
[ 0, 1, 1, 3, 3, 3, 1, 0],
[ 0, 0, 0, 1, 129, 1, 0, 0],
[ 0, 0, 0, 1, 1, 1, 0, 0],
[ 0, 0, 0, 0, 0, 0, 1, 1],
[ 0, 0, 0, 0, 0, 0, 1, 129]])
要输出一维数组,请使用ravel()
或flatten()
。前者创建了原始二维数组的一维视图,后者创建了一个展平的副本:
In [70]: conv.ravel()
Out[70]:
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 2, 1, 0, 0, 1, 0, 2, 1, 1, 1,
0, 0, 1, 1, 3, 3, 3, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0])
答案 1 :(得分:3)
我认为您尝试做的事情最简单的是使用2D数组索引。您可以使用numpy轻松地重塑阵列。没有数据被复制。新的2D数组只是提供了一种方便的方法来索引存储在原始数组中的相同值。这是一个示例代码。
#imports
import numpy as np
# Setup
Nx = 5
Ny = 7
cutoff = 3.0
arr_input = np.array([[0, 0, 0, 0, 0, 0, 9],
[0, 4, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 3, 0],
[0, 2, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 5, 0, 0]]).flatten()
# Make an array of center locations with input value bigger than the cutoff value
centers_array_2d = np.where(arr_input>=cutoff, 1.0, 0.0)
# Initialize the output array
arr_output = np.zeros_like(centers_array_2d)
# Reshape the arrays to use 2D indexing
ai = centers_array_2d.reshape(Nx, Ny)
ao = arr_output.reshape(Nx, Ny)
# Do the neighbor calculation with numpy indexing rules
ao[:-1, :-1] += ai[1:, 1:] # lower left
ao[:, :-1] += ai[:, 1:] # lower center
ao[1:, :-1] += ai[:-1, 1:] # lower right
ao[:-1, :] += ai[1:, :] # middle left
# ao[:, :] += ai[:, :] # middle center
ao[1:, :] += ai[:-1, :] # middle right
ao[:-1, 1:] += ai[1:, :-1] # top left
ao[:, 1:] += ai[:, :-1] # top center
ao[1:, 1:] += ai[:-1, :-1] # top right
# Reshape the output array to return a 1D array like the input
arr_output = ao.flatten()
# Print the results
print('input1d: \n{}\n'.format(arr_input))
print("2D array 'ai':\n{}\n".format(ai))
print("2D array 'ao':\n{}\n".format(ao))
print('output1d: \n{}\n'.format(arr_output))
阵列如下。
input1d:
[0 0 0 0 0 0 9 0 4 0 0 0 0 0 0 0 0 0 0 3 0 0 2 0 0 0 0 1 0 0 0 0 5 0 0]
2D array 'ai':
[[ 0. 0. 0. 0. 0. 0. 1.]
[ 0. 1. 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0. 1. 0.]
[ 0. 0. 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 1. 0. 0.]]
2D array 'ao':
[[ 1. 1. 1. 0. 0. 1. 0.]
[ 1. 0. 1. 0. 1. 2. 2.]
[ 1. 1. 1. 0. 1. 0. 1.]
[ 0. 0. 0. 1. 2. 2. 1.]
[ 0. 0. 0. 1. 0. 1. 0.]]
output1d:
[ 1. 1. 1. 0. 0. 1. 0. 1. 0. 1. 0. 1. 2. 2. 1. 1. 1. 0. 1. 0. 1. 0. 0. 0. 1. 2. 2. 1. 0. 0. 0. 1. 0. 1. 0.]
这是您正在寻找的计算吗?这就是我将其解释为矢量化您给出的代码。此外,您可以为与每个邻居对应的1D数组创建索引列表。当我使用2D切片索引来访问2D数组的元素时,这基本上就是在内部发生的事情。
答案 2 :(得分:0)
让我们说arr
代表输入数组,thresh
是要与每个输入元素进行比较的阈值。现在,我们可以根据给定的阈值对输入数组进行阈值处理,为我们提供一个掩码/布尔数组。然后,我们可以执行2D卷积并从中减去1s
,其中我们有阈值数组的True
值。
因此,实现看起来像这样 -
from scipy.signal import convolve2d
# Get thresholded mask as int array & set first, last cols and rows as 0s
mask = (arr > thresh).astype(int)
mask[[0,-1]] = 0
mask[:,[0,-1]] = 0
# Perform 2D convolution and subtract 1s corresponding to True elems in mask
out = convolve2d(mask,np.ones((3,3),dtype=int),'same') - mask