我想要一个形状的数组X(n_samples,n_cols,n_rows,n_channels)。我想要一个带有形状的数组y(n_sample,n_cols,n_rows,n_channels)
我试过了
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中的数组中,所以必须有一些东西我不见了?
答案 0 :(得分:1)
numpy.fromiter
不支持同时创建数组,然后将它们作为元组返回(要解压缩到X,y
中)有可能在np
中执行此操作但是据我所知,您可能需要将迭代器拆分为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
答案 1 :(得分:1)
np.fromiter
要求您说明dtype。如果使用dtype=float
,则iterable中的每个值都必须为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
返回1D数组,因此您需要重新整形:
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:]
如果我想对L和ab做额外处理,我会在哪里做?
我相信将加载与数据处理分开。通过保持两个函数不同,您可以将来自不同源的不同数据传递给相同的处理函数。如果将数据的加载和处理(例如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
)。
答案 2 :(得分:0)
通常当我们使用迭代创建数组时,我们要么在列表中收集值,要么从中创建数组。或者我们分配一个空列表并为插槽分配值。
这是一种执行赋值的方法,其中生成器返回一个数组元组:
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)
让我们分配正确形状的目标数组;这里我把迭代轴放在第3位,但它可以在任何地方
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'))
生成1d结构化数组:
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)
https://stackoverflow.com/a/12473478/901925
中也描述了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
的优势之前,我必须将运行时间推到1秒。