在 Python 中为图像中的每个像素选择 7*7 相邻像素的最快方法

Posted

技术标签:

【中文标题】在 Python 中为图像中的每个像素选择 7*7 相邻像素的最快方法【英文标题】:fastest way to select 7*7 neighbor pixels for every pixel in an image in Python 【发布时间】:2018-01-01 19:52:16 【问题描述】:

需要将图像作为数组读取,并为每个像素选择 7*7 相邻像素,然后对其进行整形并作为训练集的第一行:

  import numpy as np
  from scipy import misc
  face1=misc.imread('face1.jpg') 

face1 尺寸为 (288, 352, 3) ,需要为每个像素找到 7*7 相邻像素,因此 49*3 颜色然后将其重塑为 (1,147) 数组并将其堆叠成所有像素的数组,我拿以下方法:

X_training=np.zeros([1,147] ,dtype=np.uint8)
for i in range(3, face1.shape[0]-3):
    for j in range(3, face1.shape[1]-3):
        block=face1[i-3:i+4,j-3:j+4]
        pxl=np.reshape(block,(1,147))
        X_training=np.vstack((pxl,X_training))

结果X_training 形状为(97572, 147)

最后一行全为零:

a = len(X_training)-1
X_training = X_training[:a]

上面的代码适用于一张图片,但Wall time: 5min 19s 我有 2000 张图片,所以要花很长时间才能处理所有图片。我正在寻找一种更快的方法来迭代每个像素并完成上述任务。

编辑: 这就是我所说的相邻像素,对于每个像素face1[i-3 : i+4 ,j-3:j+4]

【问题讨论】:

你能把图像分成几块,然后用线程或类似的东西处理不同的部分吗? 我不太明白您要选择哪些相邻像素。你能详细说明一下吗? @Jacobr365 没有必要的技能来做到这一点 另外,你想如何处理图像的边缘? 认为应该是:X_training=np.zeros([0,147] ,dtype=np.uint8). 【参考方案1】:

以下是我笔记本电脑上的

import scipy as sp
im = sp.rand(300, 300, 3)

size = 3
ij = sp.meshgrid(range(size, im.shape[0]-size), range(size, im.shape[1]-size))
i = ij[0].T.flatten()
j = ij[1].T.flatten()

N = len(i)
L = (2*size + 1)**2
X_training = sp.empty(shape=[N, 3*L])

for pixel in range(N):
    si = (slice(i[pixel]-size, i[pixel]+size+1))
    sj = (slice(j[pixel]-size, j[pixel]+size+1))
    X_training[pixel, :] = im[si, sj, :].flatten()

X_training = X_training[-1::-1, :]

想不到单行矢量化版本的时候总是有点难过,但至少对你来说更快。

【讨论】:

您能否将您的答案与最佳答案进行比较?它不会返回相同的结果。某处应该有一些错误,我自己的方法和最佳答案返回完全相同的结果 我已经更新了我的答案,现在它产生了与@kazemakase 相同的输出。行的顺序不同,所以我转置了ij 数组,并且我还颠倒了最终答案中行的整体顺序。【参考方案2】:

一种有效的方法是使用stride_tricks 在图像上创建一个二维滚动窗口,然后将其展平:

import numpy as np

face1 = np.arange(288*352*3).reshape(288, 352, 3)  # toy data

n = 7  # neighborhood size

h, w, d = face1.shape
s = face1.strides

tmp = np.lib.stride_tricks.as_strided(face1, strides=s[:2] + s,
                                      shape=(h - n + 1, w - n + 1, n, n, d))
X_training = tmp.reshape(-1, n**2 * d)
X_training = X_training[::-1]  # to get the rows into same order as in the question

tmp 是图像的 5D 视图,其中tmp[x, y, :, :, c] 相当于颜色通道c 中的邻域face1[x:x+n, y:y+n, c]

【讨论】:

好一个!要复制 OP 的输出,我们需要沿行翻转。 @对,谢谢。我已将此添加为明确的步骤,因为我不太喜欢消极的步伐:) 我以前从未听说过 strides,但经过一番阅读后,我发现我错过了一些强大的东西......谢谢! @2cynykyl 很高兴听到这个消息。我还了解到这个网站上的进步。 @kazemakase 知道如何在 pyspark 中完成完全相同的任务吗? ***.com/questions/45400235/…【参考方案3】:

使用 scikit-image:

import numpy as np
from skimage import util

image = np.random.random((288, 352, 3))
windows = util.view_as_windows(image, (7, 7, 3))

out = windows.reshape(-1, 7 * 7 * 3)

【讨论】:

+1 用于使用 skimage ......但我刚刚阅读了这个 view_as_window 函数的文档,它有可怕的性能问题!真的应该有人在接受的答案中使用stride_tricks 重新实现它。 我不确定你的意思;它确实使用步幅:github.com/scikit-image/scikit-image/blob/master/skimage/util/… 我很抱歉没有检查源...但是文档字符串确实使它听起来像是在创建数组的新副本,并且内存可能会变得非常大。我对 strides 的理解是,它为底层数据的单个副本提供了新的“视图”,因此没有副本并且速度更快。在我想知道的速度方面,你的答案与 @kazemakase 相比如何? 如果能比较就好了!我们很高兴 PR 改进文档或实施。

以上是关于在 Python 中为图像中的每个像素选择 7*7 相邻像素的最快方法的主要内容,如果未能解决你的问题,请参考以下文章

基于像素的标签将2D像素阵列更改为图像

在 Xcode 7.2 中为图标图像使用 PDF

在python中创建圆圈以遮盖图像并计算每个圆圈内的像素

像素翻转

如何逐像素分析python中的图像

在图像中随机更改像素值程序——matlab