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] 范围

如果您想要01之间的像素值,我们只需删除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) 没查,有时间我试试 试过你的代码(原来的)我得到: 768 (16, 16, 3) 0.0 255.00000000000003 768 (16, 16, 3) 0.0 255.0 768 (16, 16, 3) 0.0 255.0 768 (16, 16, 3) 0.0 255.0 768 ( 16, 16, 3) 0.0 254.99999999999997 不确定是否允许浮动 images = np.random.rand(286,16,16,3).astype(np.float32) 适用于与 float64 相同的故障【参考方案3】:

我已经弄清楚了这段代码:

#!/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 如何标准化?的主要内容,如果未能解决你的问题,请参考以下文章

如何numpy.ndarray数组如何删除某一行

如何解决 TypeError:'numpy.ndarray' 对象在 Python 上不可调用

如何将 numpy ndarray 写入文本文件?

如何在 Python3 中解码编码文字/字符串的 numpy 数组? AttributeError:“numpy.ndarray”对象没有属性“解码”

如何使用 numpy.ndarray 对熊猫框架进行切片

如何将PyTorch张量转换为Numpy ndarray