如何将多个图像填充到包含它们的最小形状?

我正在尝试编写一个函数来加载和处理 NN 的数据。作为输入,我有一组不同尺寸的图片。图片应表示为具有 RGB 通道的 3D numpy 数组。我需要它们具有相同的大小(最大图片的大小)。


我已经尝试过np.pad,但似乎我不知道它应该如何工作。实际上,即使我得到了填充,我也不知道如何根据图片的大小来改变它。这是代码:


from PIL import Image

import numpy as np

import cv2

import os



def load_data(path):

    aminoacids = ['Ala','Arg','Asn','Asp','Cys','Gln','Glu','Gly','His','Ile', 'Ini', 'Leu','Lys','Met','Phe','Pro','Pyr', 'Sec','Ser','Thr','Trp','Tyr','Val']

    matrix = []

    answer_labeled = []

    names = os.listdir(path)


    for i in names:

      matrix = cv2.imread(path + i, 1)

      matrix = np.pad(matrix, (0, 1), 'constant', constant_values=[255,255,255])

      for y in aminoacids:

        if y + "-" in i:

          a = [matrix, y]

          answer_labeled.append(a)

    return answer_labeled

data_processed = load_data("/content/drive/My Drive/Thesis/dl/img/ans/")

我收到此错误:


ValueErrorTraceback (most recent call last)

<ipython-input-50-e021738e59ea> in <module>()

     20     return answer_labeled

     21 

---> 22 data_processed = load_data("/content/drive/My Drive/Thesis/dl/img/ans/")

     23 

     24 # print(len(os.listdir("/content/drive/My Drive/Thesis/dl/img/ans/")))


<ipython-input-50-e021738e59ea> in load_data(path)

     13     for i in names:

     14       matrix = cv2.imread(path + i, 1)

---> 15       matrix = np.pad(matrix, (0, 1), 'constant', constant_values=[255,255,255])

     16       for y in aminoacids:

     17         if y + "-" in i:


/usr/local/lib/python2.7/dist-packages/numpy/lib/arraypad.pyc in pad(array, pad_width, mode, **kwargs)

   1208                 kwargs[i] = _as_pairs(kwargs[i], narray.ndim, as_index=True)

   1209             if i in ['end_values', 'constant_values']:

-> 1210                 kwargs[i] = _as_pairs(kwargs[i], narray.ndim)

   1211     else:

   1212         # Drop back to old, slower np.apply_along_axis mode for user-supplied


当然,我试图用谷歌搜索这个错误,但没有找到对我有用或可以理解的东西(因为我真的是编程新手)。我将不胜感激任何帮助和想法。


守着星空守着你
浏览 133回答 2
2回答

繁星coding

我曾经不得不解决一个类似的任务,所以我为它创建了以下函数。它允许为每个维度指定大小差异的分数,应该在之前和之后填充(类似于np.pad)。例如,如果您有两个形状数组(3,)和(5,),那么before=1将在左侧填充整个差异(在本例2中为 ),而在左侧填充before=0.5一个元素,在右侧填充一个元素。与np.pad这些因素类似,也可以为每个维度指定。这是实现:import numpy as npdef pad_max_shape(arrays, before=None, after=1, value=0, tie_break=np.floor):&nbsp; &nbsp; """Pad the given arrays with a constant values such that their new shapes fit the biggest array.&nbsp; &nbsp; Parameters&nbsp; &nbsp; ----------&nbsp; &nbsp; arrays : sequence of arrays of the same rank&nbsp; &nbsp; before, after : {float, sequence, array_like}&nbsp; &nbsp; &nbsp; &nbsp; Similar to `np.pad -> pad_width` but specifies the fraction of values to be padded before&nbsp; &nbsp; &nbsp; &nbsp; and after respectively for each of the arrays.&nbsp; Must be between 0 and 1.&nbsp; &nbsp; &nbsp; &nbsp; If `before` is given then `after` is ignored.&nbsp; &nbsp; value : scalar&nbsp; &nbsp; &nbsp; &nbsp; The pad value.&nbsp; &nbsp; tie_break : ufunc&nbsp; &nbsp; &nbsp; &nbsp; The actual number of items to be padded _before_ is computed as the total number of elements&nbsp; &nbsp; &nbsp; &nbsp; to be padded times the `before` fraction and the actual number of items to be padded _after_&nbsp; &nbsp; &nbsp; &nbsp; is the remainder. This function determines how the fractional part of the `before` pad width&nbsp; &nbsp; &nbsp; &nbsp; is treated. The actual `before` pad with is computed as ``tie_break(N * before).astype(int)``&nbsp; &nbsp; &nbsp; &nbsp; where ``N`` is the total pad width. By default `tie_break` just takes the `np.floor` (i.e.&nbsp; &nbsp; &nbsp; &nbsp; attributing the fraction part to the `after` pad width). The after pad width is computed as&nbsp; &nbsp; &nbsp; &nbsp; ``total_pad_width - before_pad_width``.&nbsp; &nbsp; Returns&nbsp; &nbsp; -------&nbsp; &nbsp; padded_arrays : list of arrays&nbsp; &nbsp; Notes&nbsp; &nbsp; -----&nbsp; &nbsp; By default the `before` pad width is computed as the floor of the `before` fraction times the number&nbsp; &nbsp; of missing items for each axis. This is done regardless of whether `before` or `after` is provided&nbsp; &nbsp; as a function input. For that reason the fractional part of the `before` pad width is attributed&nbsp; &nbsp; to the `after` pad width (e.g. if the total pad width is 3 and the left fraction is 0.5 then the&nbsp; &nbsp; `before` pad width is 1 and the `after` pad width is 2; in order to f). This behavior can be controlled&nbsp; &nbsp; with the `tie_break` parameter.&nbsp; &nbsp; """&nbsp; &nbsp; shapes = np.array([x.shape for x in arrays])&nbsp; &nbsp; if before is not None:&nbsp; &nbsp; &nbsp; &nbsp; before = np.zeros_like(shapes) + before&nbsp; &nbsp; else:&nbsp; &nbsp; &nbsp; &nbsp; before = np.ones_like(shapes) - after&nbsp; &nbsp; max_size = shapes.max(axis=0, keepdims=True)&nbsp; &nbsp; margin = (max_size - shapes)&nbsp; &nbsp; pad_before = tie_break(margin * before.astype(float)).astype(int)&nbsp; &nbsp; pad_after = margin - pad_before&nbsp; &nbsp; pad = np.stack([pad_before, pad_after], axis=2)&nbsp; &nbsp; return [np.pad(x, w, mode='constant', constant_values=value) for x, w in zip(arrays, pad)]对于您的示例,您可以按如下方式使用它:test = [np.ones(shape=(i, i, 3)) for i in range(5, 10)]result = pad_max_shape(test, before=0.5, value=255)print([x.shape for x in result])print(result[0][:, :, 0])这会产生以下输出:[(9, 9, 3), (9, 9, 3), (9, 9, 3), (9, 9, 3), (9, 9, 3)][[255. 255. 255. 255. 255. 255. 255. 255. 255.]&nbsp;[255. 255. 255. 255. 255. 255. 255. 255. 255.]&nbsp;[255. 255.&nbsp; &nbsp;1.&nbsp; &nbsp;1.&nbsp; &nbsp;1.&nbsp; &nbsp;1.&nbsp; &nbsp;1. 255. 255.]&nbsp;[255. 255.&nbsp; &nbsp;1.&nbsp; &nbsp;1.&nbsp; &nbsp;1.&nbsp; &nbsp;1.&nbsp; &nbsp;1. 255. 255.]&nbsp;[255. 255.&nbsp; &nbsp;1.&nbsp; &nbsp;1.&nbsp; &nbsp;1.&nbsp; &nbsp;1.&nbsp; &nbsp;1. 255. 255.]&nbsp;[255. 255.&nbsp; &nbsp;1.&nbsp; &nbsp;1.&nbsp; &nbsp;1.&nbsp; &nbsp;1.&nbsp; &nbsp;1. 255. 255.]&nbsp;[255. 255.&nbsp; &nbsp;1.&nbsp; &nbsp;1.&nbsp; &nbsp;1.&nbsp; &nbsp;1.&nbsp; &nbsp;1. 255. 255.]&nbsp;[255. 255. 255. 255. 255. 255. 255. 255. 255.]&nbsp;[255. 255. 255. 255. 255. 255. 255. 255. 255.]]所以我们可以看到每个数组都被对称地填充到最大数组的形状(9, 9, 3)。

米脂

的使用np.pad()实际上是有据可查的。一个适用于您提供的数字的 3D 数据的示例是:import numpy as nparr = np.random.randint(0, 255, (72, 72, 3))new_arr = np.pad(&nbsp; &nbsp; arr, ((0, 92 - 72), (0, 92 - 72), (0, 0)),&nbsp; &nbsp; 'constant', constant_values=255)print(new_arr.shape)# (92, 92, 3)编辑要解决完整的问题,您需要首先确定最大尺寸,然后相应地填充所有其他图像。FlyingCircus包为您提供了许多功能,可以更轻松地完成工作(免责声明:我是它的主要作者)。如果您可以将所有图像放入内存中,最简单的方法就是使用fc.extra.multi_reframe(),即:import flyingcircus as fcnew_arrs = fc.extra.multi_reframe(arrs, background=255)如果您无法将所有数据放入内存中,则应分两次执行此操作,一次计算适合所有输入的最小形状,然后执行实际填充fc.extra.reframe():# assume your data is loaded with `load(filepath)`# ... and saved with `save(array, filepath)`# : first passshapes = [load(filepath).shape for filepath in filepaths]target_shape = tuple(np.max(np.array(shapes), axis=0))# : second passfor filepath in filepaths:&nbsp; &nbsp; arr = load(filepath)&nbsp; &nbsp; new_arr = fc.extra.reframe(arr, target_shape, 0.5, 255)&nbsp; &nbsp; save(new_arr, filepath)在内部,fc.extra.reframe()正在使用np.pad()(或类似但更快的东西),它大致相当于:def reframe(arr, target_shape, position=0.5, *args, **kws):&nbsp; &nbsp; source_shape = arr.shape&nbsp; &nbsp; padding = tuple(&nbsp; &nbsp; &nbsp; &nbsp; (int(position * (dim_target - dim_source)),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(dim_target - dim_source) - int(position * (dim_target - dim_source)))&nbsp; &nbsp; &nbsp; &nbsp; for dim_target, dim_source in zip(target_shape, source_shape))&nbsp; &nbsp; return np.pad(arr, padding, *args, **kws)reframe(arr, target_shape, 0.5, 'constant', constant_values=255)请注意,position参数决定了数组相对于新形状的位置。的默认值0.5会将所有图像放在中心,而0.0或1.0会将其推到所有轴上新形状的一侧或另一侧。它的 FlyingCircus 版本更加灵活,您可以position分别为所有轴指定一个值。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python