如何将图像列表加载到 Numpy 中每个通道的数组中?
How do I load a list of images into an array for each channel in Numpy?
我想要一个形状为 (n_samples、n_cols、n_rows、n_channels 的数组 X。我想要一个形状为 (n_sample,n_cols,n_rows,n_channels)
的数组 y
我试过了
import glob
from skimage import io, color
import numpy as np
def loadfunc(files)
for fl in files:
img = color.rgb2lab(io.imread(fl))
L = img[:,:,:1]
ab = img[:,:,1:]
yield L,ab
X,y = np.fromiter(loadfunc(glob.glob('path/to/images/*.png')),float)
我收到此错误:ValueError:设置带有序列的数组元素。
我认为这一定是一个有点常见的操作 - 任何时候有人想将图像数据加载到 numpy 中的数组中,所以我一定缺少某些东西?
numpy.fromiter
does not support simultaneous array creation and then return them as a tuple, (to be unpacked into X,y
) It is possible there is a way to do this in np
but not to my knowledge, you may need to split the iterator into a tee
改为
# the built in map in python 3 uses iteration,
# uncomment the added imap import if you are using python 2
from itertools import tee #, imap as map
from operator import itemgetter
iter_a, iter_b = tee(loadfunc(glob.glob('path/to/images/*.png')))
X = np.fromiter(map(itemgetter(0),iter_a), float) #array from the first elements
y = np.fromiter(map(itemgetter(1),iter_b), float) #array from the second elements
np.fromiter
要求您声明数据类型。如果您使用 dtype=float
,那么可迭代对象中的每个值都必须是浮点数。如果您从 loadfunc
生成单个 NumPy 数组,您可以使用它们的 flat
属性来获取平展数组值的迭代器,这些值可以与 itertools.chain.from_iterable
连接,然后传递给 np.fromiter
:
def loadfunc(files):
for fl in files:
img = skcolor.rgb2lab(skio.imread(fl)[..., :3])
yield img
arrs = loadfunc(files)
Z = np.fromiter(IT.chain.from_iterable([arr.flat for arr in arrs]), dtype=float)
由于 np.fromiter
returns 是一维数组,因此您需要对其进行整形:
Z = Z.reshape(len(files), h, w, n)
请注意,这依赖于每个具有相同形状的图像。
最后,将 L
值加载到 X
并将 ab
值加载到 y
:
X = Z[..., :1]
y = Z[..., 1:]
import glob
import itertools as IT
import numpy as np
import skimage.io as skio
import skimage.color as skcolor
def loadfunc(files):
for fl in files:
img = skcolor.rgb2lab(skio.imread(fl)[..., :3])
yield img
files = glob.glob('path/to/images/*.png')
arrs = loadfunc(files)
first = next(arrs)
h, w, n = first.shape
Z = np.fromiter(IT.chain.from_iterable(
[first.flat] + [arr.flat for arr in arrs]), dtype=float)
Z = Z.reshape(len(files), h, w, n)
X = Z[..., :1]
y = Z[..., 1:]
关于 :
If I wanted to do extra processing to L and ab, where would I do that?
我相信将加载与数据处理分开。通过保持这两个功能的不同,您可以将来自不同来源的不同数据传递到相同的处理功能。如果您将数据的加载和处理(例如 ab 值的 KNN 分类)都放入 loadfunc
中,那么如果不从文件中加载数据,就无法重用 KNN 分类代码。
如果你允许我们改变坐标轴的顺序
(n_samples, n_cols, n_rows, n_channels)
至
(n_cols, n_rows, n_channels, n_samples)
,
然后可以使用 np.stack
:
简化代码
import glob
import numpy as np
import skimage.io as skio
import skimage.color as skcolor
def loadfunc(files):
for fl in files:
img = skcolor.rgb2lab(skio.imread(fl)[..., :3])
yield img
files = glob.glob('path/to/images/*.png')
Z = np.stack(loadfunc(files), axis=-1)
X = Z[..., :1, :]
Y = Z[..., 1:, :]
此代码更简单,因此比上面的代码(使用 np.fromiter
)更可取。
通常当我们用迭代创建一个数组时,我们要么收集列表中的值,然后从中创建数组。或者我们分配一个空列表并为插槽赋值。
这是一种进行赋值的方法,其中生成器 returns 一个数组元组:
def mk_array(N):
for i in range(N):
img=np.ones((2,3,3),int)
L=img[:,:,:1]*i
ab=img[:,:,1:].astype(float)*i/10
yield L,ab
我把一个设为整数数组,另一个设为浮点数数组。这减少了将它们连接成一个的诱惑。
In [157]: g=mk_array(4)
In [158]: for i,v in enumerate(g):
print(v[0].shape,v[1].shape)
.....:
(2, 3, 1) (2, 3, 2)
(2, 3, 1) (2, 3, 2)
(2, 3, 1) (2, 3, 2)
(2, 3, 1) (2, 3, 2)
让我们分配正确形状的目标数组;这里我把迭代轴放在第三位,但它可以在任何地方
In [159]: L, ab = np.empty((2,3,4,1),int), np.empty((2,3,4,2),float)
In [160]: for i,v in enumerate(g):
L[...,i,:], ab[...,i,:] = v
我猜这与任何 fromiter
或 stack
替代方案一样快。当通过读取文件生成组件时,该步骤必然是最昂贵的 - 比迭代机制或数组副本更昂贵。
================
如果迭代器返回一个标量元组,我们可以使用fromiter
:
def mk_array1(N):
for i in range(N):
img=np.ones((2,3,3),int)
L=img[:,:,:1]*i
ab=img[:,:,1:].astype(float)*i/10
for i,j in zip(L.ravel(),ab.ravel()):
yield i,j
In [184]: g=mk_array1(2)
In [185]: V=np.fromiter(g,dtype=('i,f'))
生成一维结构化数组:
In [186]: V
Out[186]:
array([(0, 0.0), (0, 0.0), (0, 0.0), (0, 0.0), (0, 0.0), (0, 0.0),
(1, 0.10000000149011612), (1, 0.10000000149011612),
(1, 0.10000000149011612), (1, 0.10000000149011612),
(1, 0.10000000149011612), (1, 0.10000000149011612)],
dtype=[('f0', '<i4'), ('f1', '<f4')])
可重塑,数组以字段名分隔:
In [187]: V['f0']
Out[187]: array([0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], dtype=int32)
In [188]: V.reshape(2,2,3)['f0']
Out[188]:
array([[[0, 0, 0],
[0, 0, 0]],
[[1, 1, 1],
[1, 1, 1]]], dtype=int32)
In [189]: V.reshape(2,2,3)['f1']
Out[189]:
array([[[ 0. , 0. , 0. ],
[ 0. , 0. , 0. ]],
[[ 0.1, 0.1, 0.1],
[ 0.1, 0.1, 0.1]]], dtype=float32)
================
如果我定义一个更复杂的 dtype
,每个字段都有一个数组会怎么样:
In [200]: dt=np.dtype([('f0',int,(2,3,1)),('f1',float,(2,3,2))])
In [201]: g=mk_array(2) # the original generator
In [202]: V=np.fromiter(g,dtype=dt)
In [203]: V['f0']
Out[203]:
array([[[[0],
[0],
[0]],
....
[[1],
[1],
[1]]]])
In [204]: _.shape
Out[204]: (2, 2, 3, 1)
在
中也描述了 fromiter
对复合 dtype 的使用
实际上,这是从元组列表构建结构化数组的常用方法的变体。我不止一次使用表达式:
np.array([tuple(x) for x in something], dtype=dt)
总而言之,我们可以使用两种创建 2 个数组的方法:
def foo1(N):
g = mk_array(N)
L, ab = np.empty((N,2,3,1),int), np.empty((N,2,3,2),float)
for i,v in enumerate(g):
L[i,...], ab[i,...] = v
return L, ab
def foo2(N):
dt=np.dtype([('f0',int,(2,3,1)),('f1',float,(2,3,2))])
g = mk_array(N)
V=np.fromiter(g, dtype=dt)
return V['f0'], V['f1']
对于范围广泛的N
,这两个函数花费的时间几乎相同。在开始 foo1
.
的优势之前,我必须将 运行 次推到 1s
我想要一个形状为 (n_samples、n_cols、n_rows、n_channels 的数组 X。我想要一个形状为 (n_sample,n_cols,n_rows,n_channels)
的数组 y我试过了
import glob
from skimage import io, color
import numpy as np
def loadfunc(files)
for fl in files:
img = color.rgb2lab(io.imread(fl))
L = img[:,:,:1]
ab = img[:,:,1:]
yield L,ab
X,y = np.fromiter(loadfunc(glob.glob('path/to/images/*.png')),float)
我收到此错误:ValueError:设置带有序列的数组元素。
我认为这一定是一个有点常见的操作 - 任何时候有人想将图像数据加载到 numpy 中的数组中,所以我一定缺少某些东西?
numpy.fromiter
does not support simultaneous array creation and then return them as a tuple, (to be unpacked into X,y
) It is possible there is a way to do this in np
but not to my knowledge, you may need to split the iterator into a tee
改为
# the built in map in python 3 uses iteration,
# uncomment the added imap import if you are using python 2
from itertools import tee #, imap as map
from operator import itemgetter
iter_a, iter_b = tee(loadfunc(glob.glob('path/to/images/*.png')))
X = np.fromiter(map(itemgetter(0),iter_a), float) #array from the first elements
y = np.fromiter(map(itemgetter(1),iter_b), float) #array from the second elements
np.fromiter
要求您声明数据类型。如果您使用 dtype=float
,那么可迭代对象中的每个值都必须是浮点数。如果您从 loadfunc
生成单个 NumPy 数组,您可以使用它们的 flat
属性来获取平展数组值的迭代器,这些值可以与 itertools.chain.from_iterable
连接,然后传递给 np.fromiter
:
def loadfunc(files):
for fl in files:
img = skcolor.rgb2lab(skio.imread(fl)[..., :3])
yield img
arrs = loadfunc(files)
Z = np.fromiter(IT.chain.from_iterable([arr.flat for arr in arrs]), dtype=float)
由于 np.fromiter
returns 是一维数组,因此您需要对其进行整形:
Z = Z.reshape(len(files), h, w, n)
请注意,这依赖于每个具有相同形状的图像。
最后,将 L
值加载到 X
并将 ab
值加载到 y
:
X = Z[..., :1]
y = Z[..., 1:]
import glob
import itertools as IT
import numpy as np
import skimage.io as skio
import skimage.color as skcolor
def loadfunc(files):
for fl in files:
img = skcolor.rgb2lab(skio.imread(fl)[..., :3])
yield img
files = glob.glob('path/to/images/*.png')
arrs = loadfunc(files)
first = next(arrs)
h, w, n = first.shape
Z = np.fromiter(IT.chain.from_iterable(
[first.flat] + [arr.flat for arr in arrs]), dtype=float)
Z = Z.reshape(len(files), h, w, n)
X = Z[..., :1]
y = Z[..., 1:]
关于
If I wanted to do extra processing to L and ab, where would I do that?
我相信将加载与数据处理分开。通过保持这两个功能的不同,您可以将来自不同来源的不同数据传递到相同的处理功能。如果您将数据的加载和处理(例如 ab 值的 KNN 分类)都放入 loadfunc
中,那么如果不从文件中加载数据,就无法重用 KNN 分类代码。
如果你允许我们改变坐标轴的顺序
(n_samples, n_cols, n_rows, n_channels)
至
(n_cols, n_rows, n_channels, n_samples)
,
然后可以使用 np.stack
:
import glob
import numpy as np
import skimage.io as skio
import skimage.color as skcolor
def loadfunc(files):
for fl in files:
img = skcolor.rgb2lab(skio.imread(fl)[..., :3])
yield img
files = glob.glob('path/to/images/*.png')
Z = np.stack(loadfunc(files), axis=-1)
X = Z[..., :1, :]
Y = Z[..., 1:, :]
此代码更简单,因此比上面的代码(使用 np.fromiter
)更可取。
通常当我们用迭代创建一个数组时,我们要么收集列表中的值,然后从中创建数组。或者我们分配一个空列表并为插槽赋值。
这是一种进行赋值的方法,其中生成器 returns 一个数组元组:
def mk_array(N):
for i in range(N):
img=np.ones((2,3,3),int)
L=img[:,:,:1]*i
ab=img[:,:,1:].astype(float)*i/10
yield L,ab
我把一个设为整数数组,另一个设为浮点数数组。这减少了将它们连接成一个的诱惑。
In [157]: g=mk_array(4)
In [158]: for i,v in enumerate(g):
print(v[0].shape,v[1].shape)
.....:
(2, 3, 1) (2, 3, 2)
(2, 3, 1) (2, 3, 2)
(2, 3, 1) (2, 3, 2)
(2, 3, 1) (2, 3, 2)
让我们分配正确形状的目标数组;这里我把迭代轴放在第三位,但它可以在任何地方
In [159]: L, ab = np.empty((2,3,4,1),int), np.empty((2,3,4,2),float)
In [160]: for i,v in enumerate(g):
L[...,i,:], ab[...,i,:] = v
我猜这与任何 fromiter
或 stack
替代方案一样快。当通过读取文件生成组件时,该步骤必然是最昂贵的 - 比迭代机制或数组副本更昂贵。
================
如果迭代器返回一个标量元组,我们可以使用fromiter
:
def mk_array1(N):
for i in range(N):
img=np.ones((2,3,3),int)
L=img[:,:,:1]*i
ab=img[:,:,1:].astype(float)*i/10
for i,j in zip(L.ravel(),ab.ravel()):
yield i,j
In [184]: g=mk_array1(2)
In [185]: V=np.fromiter(g,dtype=('i,f'))
生成一维结构化数组:
In [186]: V
Out[186]:
array([(0, 0.0), (0, 0.0), (0, 0.0), (0, 0.0), (0, 0.0), (0, 0.0),
(1, 0.10000000149011612), (1, 0.10000000149011612),
(1, 0.10000000149011612), (1, 0.10000000149011612),
(1, 0.10000000149011612), (1, 0.10000000149011612)],
dtype=[('f0', '<i4'), ('f1', '<f4')])
可重塑,数组以字段名分隔:
In [187]: V['f0']
Out[187]: array([0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], dtype=int32)
In [188]: V.reshape(2,2,3)['f0']
Out[188]:
array([[[0, 0, 0],
[0, 0, 0]],
[[1, 1, 1],
[1, 1, 1]]], dtype=int32)
In [189]: V.reshape(2,2,3)['f1']
Out[189]:
array([[[ 0. , 0. , 0. ],
[ 0. , 0. , 0. ]],
[[ 0.1, 0.1, 0.1],
[ 0.1, 0.1, 0.1]]], dtype=float32)
================
如果我定义一个更复杂的 dtype
,每个字段都有一个数组会怎么样:
In [200]: dt=np.dtype([('f0',int,(2,3,1)),('f1',float,(2,3,2))])
In [201]: g=mk_array(2) # the original generator
In [202]: V=np.fromiter(g,dtype=dt)
In [203]: V['f0']
Out[203]:
array([[[[0],
[0],
[0]],
....
[[1],
[1],
[1]]]])
In [204]: _.shape
Out[204]: (2, 2, 3, 1)
在
中也描述了fromiter
对复合 dtype 的使用
实际上,这是从元组列表构建结构化数组的常用方法的变体。我不止一次使用表达式:
np.array([tuple(x) for x in something], dtype=dt)
总而言之,我们可以使用两种创建 2 个数组的方法:
def foo1(N):
g = mk_array(N)
L, ab = np.empty((N,2,3,1),int), np.empty((N,2,3,2),float)
for i,v in enumerate(g):
L[i,...], ab[i,...] = v
return L, ab
def foo2(N):
dt=np.dtype([('f0',int,(2,3,1)),('f1',float,(2,3,2))])
g = mk_array(N)
V=np.fromiter(g, dtype=dt)
return V['f0'], V['f1']
对于范围广泛的N
,这两个函数花费的时间几乎相同。在开始 foo1
.