numpy.ndarray 如何标准化?
Posted
技术标签:
【中文标题】numpy.ndarray 如何标准化?【英文标题】:how numpy.ndarray can be normalized? 【发布时间】:2021-08-25 08:42:27 【问题描述】:我正在使用 numpy.ndarray
,包括 286 张形状为 (286, 16, 16, 3)
的图像。每个图像包含 3 个波段,其像素值不同,数据类型为 float32。每个波段的像素值最大值可以超过255。是否可以将这个numpy.ndarray归一化在[0-1]之间?
图像读取代码:
inputPath='E:/Notebooks/data'
images = []
# Load in the images
for filepath in os.listdir(inputPath):
images.append(cv2.imread(inputPath+'/0'.format(filepath),flags=(cv2.IMREAD_ANYCOLOR | cv2.IMREAD_ANYDEPTH)))
【问题讨论】:
对 286 幅图像中的每幅图像或所有图像进行归一化? 规范化是什么意思?取最小值和最大值 float32 并将它们放在 0 和 255 之间并在 0 到 255 范围内的值之间分配?还是别的什么? 标准化该数据集中的 256 张图像。 这样我相信它更难。这里:***.com/questions/1735025/… 我发现 # Normalized [0,255] as integer:不要忘记 astype(int) c = (255*(a - np.min(a))/np.ptp(a)) 之前的括号。 astype(int) 但我相信它会对所有图像进行规范化,我只能将你的数组拆分为 286 个图像并应用它。也许还有其他方法 ii = (255*(i - np.min(i))/np.ptp(i)).astype(int) 给出 RuntimeWarning: 在 true_divide 中遇到的无效值与 float32 类型的 numpy 数组!!!需要弄清楚原因 【参考方案1】:向量化比迭代快得多
如果您只想使用numpy
数组来缩放所有图像的像素值,您可能希望保持操作的矢量化特性(通过避免循环)。
这是一种缩放图像的方法:
# Getting min and max per image
maxis = images.max(axis=(1,2,3))
minis = images.min(axis=(1,2,3))
# Scaling without any loop
scaled_images = ((images.T - minis) / (maxis - minis) * 255).T
# timeit > 178 µs ± 1.24 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
这里需要转置.T
才能正确广播减法。
我们可以检查这是否正确:
print((scaled_images.min(axis=(1,2,3)) == 0).all())
# > True
print((scaled_images.max(axis=(1,2,3)) == 255).all())
# > True
缩放到 [0, 1] 范围
如果您想要0
和1
之间的像素值,我们只需删除x255乘法:
scaled_images = ((images.T - minis) / (maxis - minis)).T
仅适用于 numpy 数组等
您还必须确保首先处理的是numpy array
,而不是list
:
import numpy as np
images = np.array(images)
OpenCV
移动缩放
由于您使用opencv
一张一张地读取图像,因此您可以随时随地对图像进行标准化:
inputPath='E:/Notebooks/data'
max_scale = 1 # or 255 if needed
# Load in the images
images = [cv2.normalize(
cv2.imread(inputPath+'/0'.format(filepath),flags=(cv2.IMREAD_ANYCOLOR | cv2.IMREAD_ANYDEPTH)),
None, 0, max_scale, cv2.NORM_MINMAX)
for filepath in os.listdir(inputPath)]
确保文件夹中有图片
inputPath='E:/Notebooks/data'
images = []
max_scale = 1 # or 255 if needed
# Load in the images
for filepath in os.listdir(inputPath):
image = cv2.imread(inputPath+'/0'.format(filepath),flags=(cv2.IMREAD_ANYCOLOR | cv2.IMREAD_ANYDEPTH))
# Scale and append the list if it is an image
if image is not None:
images.append(cv2.normalize(image, None, 0, max_scale, cv2.NORM_MINMAX))
open-cv 3.4 之前版本的错误
正如here 报告的那样,opencv 的normalize
方法产生低于alpha parameter
的值存在一个错误。它已在 3.4 版中更正。
这是一种使用旧版本的 open-cv 随时随地缩放图像的方法:
def custom_scale(img, max_scale=1):
mini = img.min()
return (img - mini) / (img.max() - mini) * max_scale
max_scale = 1 # or 255 if needed
images = [custom_scale(
cv2.imread(inputPath+'/0'.format(filepath),flags=(cv2.IMREAD_ANYCOLOR | cv2.IMREAD_ANYDEPTH)), max_scale)
for filepath in os.listdir(inputPath)]
【讨论】:
我添加了用于读取问题中图像的代码。是否可以标准化 [0-1] 之间的图像?当我应用您的代码时,它返回错误:AttributeError: 'list' object has no attribute 'max' 我更新了答案。你说你有一个numpy ndarray
,但在你的情况下,images
似乎是一个list
。
感谢您的回复。我使用列表读取 286 幅图像。当我检查print(type(images[1]))
结果是class 'numpy.ndarray
。如果我使用images = np.array(images)
,我可以阅读所有图像吗?
是的,numpy arrays
在名为“图像”的list
中。我在上次编辑中提到您应该使用opencv
在旅途中规范化您的图像,因为您已经在使用它并迭代地添加图像。为此,您无需使用 numpy 或将列表转换为数组。
感谢您的帮助和时间。我可以在google colab中运行它,负值为0。我不知道为什么我不能升级甚至从anaconda卸载open cv。【参考方案2】:
如果您希望每个图像的值范围在 0 到 255 之间,您可以遍历图像,计算原始图像的最小值和最大值并压缩它们,因此最小值为 0,最大值为 255。
import numpy as np
#images = np.random.rand(286,16,16,3)
images = np.random.rand(286,16,16,3).astype(np.float32)
for nr,img in enumerate(images):
min = np.min(img)
max = np.max(img)
# images[nr] = (img - min) * (255/(max-min))
images[nr] = (img - min) / (max - min) * 255
【讨论】:
每张图片包含 3 个波段,具有不同的像素值,采用 float32 数据类型 工作方式相同,不是吗?只需使用images = np.random.rand(286,16,16,3).astype(np.float32)
没查,有时间我试试
试过你的代码(原来的)我得到:我已经弄清楚了这段代码:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Jun 8 13:19:17 2021
@author: Pietro
https://***.com/questions/67885596/how-numpy-ndarray-can-be-normalized
"""
import numpy as np
arrayz = np.array(np.random.randn(286,16,16,3), dtype=np.float32)
print(arrayz.shape)
print((arrayz.size))
print(arrayz[0,0,0,:],' ',type(arrayz[0,0,0,:]))
print(arrayz[0,0,0,0],' ',type(arrayz[0,0,0,0]))
print(np.min(arrayz),' ',np.max(arrayz))
print(np.min(arrayz),' ',np.max(arrayz))
arrayz_split = np.split(arrayz,286,0)
print(type(arrayz_split))
for i in arrayz_split:
print(i.size,' ', i.shape,' ', np.min(i),' ', np.max(i))
arrayz_split_flat = []
for i in arrayz_split:
ii = i[0]
arrayz_split_flat.append(ii)
for i in arrayz_split_flat:
print(type(i),' ',i.size,' ', i.shape,' ', np.min(i),' ', np.max(i))
arrayz_split_flat_norm = []
for i in arrayz_split_flat:
minz = np.min(i)
manz = np.max(i)
ii = ((i-minz)/(manz-minz)*255).astype(np.uint8)
arrayz_split_flat_norm.append(ii)
for i in arrayz_split_flat_norm:
print(type(i),' ',i.size,' ', i.shape,' ', np.min(i),' ', np.max(i))
out_arr1 = np.stack((arrayz_split_flat_norm), axis = 0)
print(type(out_arr1), out_arr1.size, ' ', out_arr1.shape, ' ',np.min(out_arr1),np.max(out_arr1), out_arr1[0,0,0,:],out_arr1[0,0,0,0])
我不明白为什么:
arrayz = np.array(np.random.randn(286,16,16,3), dtype=np.float32)
使用时似乎可以工作:
arrayz1 = np.ndarray((286,16,16,3), dtype="float32")
arrayz = np.nan_to_num(arrayz1)
有效但抛出:
RuntimeWarning: overflow encountered in float_scalars
ii = ((i-minz)/(manz-minz)*255).astype(np.uint8)
RuntimeWarning: invalid value encountered in true_divide
ii = ((i-minz)/(manz-minz)*255).astype(np.uint8)
我最终得到了一系列 16x16x3 的数组,全是零
【讨论】:
据我了解,他希望对每个图像本身进行归一化,而不是对整个数据进行归一化。所以我认为你需要将最小/最大计算移到循环中。 是的,谢谢你的指出,这就是为什么我应该总是有测试用例来检查我的脚本! 是的,我想是的。 @pippo1980 在回答问题时,请尝试创建最高效、最简单和格式化的代码。所有的印刷品都是无用的;所有的行距都是无用的;他们让你的答案很难 1. 理解; 2. 感谢那些不需要运行代码来理解它的作用的人。 @pippo1980 此外,您用于获取类型、形状等信息的所有打印都直接显示在 IDE 的变量资源管理器中。您不需要打印它们。以上是关于numpy.ndarray 如何标准化?的主要内容,如果未能解决你的问题,请参考以下文章
如何解决 TypeError:'numpy.ndarray' 对象在 Python 上不可调用
如何在 Python3 中解码编码文字/字符串的 numpy 数组? AttributeError:“numpy.ndarray”对象没有属性“解码”