如何在没有循环的情况下均匀裁剪图像

Posted

技术标签:

【中文标题】如何在没有循环的情况下均匀裁剪图像【英文标题】:how crop an image evenly without loop 【发布时间】:2021-06-04 09:02:40 【问题描述】:

假设我有一个 np.array(image)

img = [[1,2,3,4],
       [5,6,7,8],
       [9,10,11,12],
       [13,14,15,16]]

我怎样才能把它分成 4 种作物?

[[1,2],    [[3,4],    [[9,10],    [[11,12],
 [5,6]]     [7,8]]     [13,14]]     [15,16]]

我知道的唯一方法是使用循环来指定img[x_start:x_end,y_start:y_end]。 但是对于大型 3D 体积,这非常耗时。 NumPy 库本身似乎比某些算法中的循环执行得更好。 顺便说一句,如果我使用img.reshape(-1,2,2),我会得到以下矩阵,这不是我想要的:

[[1,2],    [[5,6],    [[9,10],    [[13,14],
 [3,4]]     [7,8]]     [11,12]]     [15,16]]

当然,它不必是 Numpy 库,也可以是 cv2 或类似的东西,我可以在 python 中使用

【问题讨论】:

【参考方案1】:

我希望我理解你的问题是正确的:

img = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]])

out = [np.vsplit(x, 2) for x in np.hsplit(img, 2)]

for arr1 in out:
    for arr2 in arr1:
        print(arr2)
        print()

打印:

[[1 2]
 [5 6]]

[[ 9 10]
 [13 14]]

[[3 4]
 [7 8]]

[[11 12]
 [15 16]]

【讨论】:

谢谢!这正是我想要的!我发现我们可以将 out = [np.vsplit(x, 2) for x in np.hsplit(img, 2)] 更改为 out = [np.vsplit(x, size) for x in np.hsplit( img, size)],其中 size 是我想要的裁剪尺寸【参考方案2】:

为了解决您的问题,您可以使用例如np.transposenp.moveaxis 来使用轴。

以下解决方案可能不是最快的,但它说明了您可以使用这些工具做什么。

img = np.array([[1,2,3,4],
         [5,6,7,8],
         [9,10,11,12],
         [13,14,15,16]])
img = img.reshape(-1,2,2)
img = np.moveaxis(img, 0, 1)
img = img.reshape(-1,2,2)

输出:

>>> print(img)
[[[ 1  2]
  [ 5  6]]

 [[ 9 10]
  [13 14]]

 [[ 3  4]
  [ 7  8]]

 [[11 12]
  [15 16]]]

【讨论】:

【参考方案3】:

您想要的称为滑动窗口视图NumPy 已经具有执行此操作的函数:numpy.lib.stride_tricks.sliding_window_view,但该函数不采用自定义步幅(滑动窗口的步长)。我已经实现了自己的函数,它给出了这样的 view(需要最小的内存开销):

import numpy as np 
from numpy.lib.stride_tricks import as_strided
from typing import Tuple


def get_sliding_window_2d(x: np.ndarray, width: int, height: int, rowstride: int, colstride: int):
    """
    x: np.array
    width: width of window
    height: height of window
    rowstride: horizontal window step size
    colstride: vertical window step size 
    """
    imgRows, imgCols = x.shape
    u = np.array(x.itemsize)
    return as_strided(x,
        shape=((imgRows-width)//rowstride+1, (imgCols-height)//colstride+1, width, height), 
        strides=u*(imgCols*rowstride, colstride, imgCols, 1)
    )

a = np.arange(4*4).reshape(4,4)+1
for windows in get_sliding_window_2d(a, 2, 2, 2, 2):
    for window in windows:
        print(window, end="\n\n")

#[[1 2]
# [5 6]]
#
#[[3 4]
# [7 8]]
#
#[[ 9 10]
# [13 14]]
#
#[[11 12]
# [15 16]]

在相关说明中,如果您打算使用上述滑动窗口使用均值内核模糊图像或进行边缘检测或其他操作,您可以使用scipy.signal.convolve2d(以及许多其他类似功能)来实现。

【讨论】:

以上是关于如何在没有循环的情况下均匀裁剪图像的主要内容,如果未能解决你的问题,请参考以下文章

从上到下均匀裁剪图像

C#如何在不使用大量内存的情况下裁剪图像? [复制]

如何在裁剪前不修剪的情况下以小形式裁剪大图像?

使用 Python - 如何在不超过原始图像大小的情况下调整裁剪图像的大小以满足纵横比

如何在不更改 C#.Net 中的分辨率的情况下裁剪图像?

如何在不保存原始图像的情况下保存图像 URL 的裁剪图像? (在 Rails 中使用 Paperclip 或其他插件)