简体   繁体   English

如何在不破坏图像外观的情况下使用 PIL 缩放图像?

[英]How can I scale an image with PIL without ruining its appearence?

I noticed that simply multyplying and dividing an array even for coefficents equivalent to 1, will deform the image.我注意到,即使对于等于 1 的系数,简单地乘法和除法数组也会使图像变形。

I need to rescale the image pixels because I need to feed them to a ML model, but I noticed there seems to be a huge loss of information in the process.我需要重新缩放图像像素,因为我需要将它们提供给 ML model,但我注意到在这个过程中似乎有大量信息丢失。

This is the original image (an example):这是原始图像(示例):

Image.fromarray((np.array(out_img.resize((224, 224)))),'L')

原图

If I divide it by 255, it somehow ends up like this:如果我将它除以 255,结果会变成这样:

Image.fromarray((np.array(out_img.resize((224, 224)))/255),'L')

在此处输入图像描述

A lot of information seems lost, and apparently I can't revert back to the original:很多信息似乎丢失了,显然我无法恢复到原来的状态:

(np.array(out_img.resize((224, 224)))/255*255==np.array(out_img.resize((224, 224)))).all()    
Image.fromarray((np.array(out_img.resize((224, 224)))/255*255),'L')

在此处输入图像描述 If you see I checked that multiplying and dividing by 255 will give us back the same array, but the images look different.如果你看到我检查过乘以和除以 255 将返回相同的数组,但图像看起来不同。

The same happens even if I naively divide and multiply by 1:即使我天真地除以 1 并乘以 1,也会发生同样的情况:

Image.fromarray((np.array(out_img.resize((224, 224)))*(1/1)),'L')

在此处输入图像描述

Is there an explanation for this behaviour or a way to prevent the information loss?是否有对此行为的解释或防止信息丢失的方法?

But you can't create a 'L' mode PIL image from a float array.但是您不能从浮点数组创建“L”模式 PIL 图像。 PIL.Image.fromarray just plug the data from the passed array into an image. PIL.Image.fromarray只是将传递的数组中的数据插入到图像中。 Those data, with L mode, are supposed to be bytes.那些具有L模式的数据应该是字节。 And what you gave are floats.而你给的是花车。

See following example请参见以下示例

from PIL import Image
import numpy as np
img = np.array([[3.141592653589793, 12, 13, 14], [15, 16, 17, 18]])
limg=np.array(Image.fromarray(img, 'L'))

limg is now an array of the same shape as img. limg 现在是一个与 img 形状相同的数组。 Since PIL image built from img has this resolution.由于从 img 构建的 PIL 图像具有此分辨率。 But data are 8 bytes (since there are 8 pixels, and we said that format is L), that are the 8 first bytes taken from img .但是数据是 8 个字节(因为有 8 个像素,我们说格式是 L),这是从img中获取的前 8 个字节。

See

img.tobytes()
# b'\x18-DT\xfb!\t@\x00\x00\x00\x00\x00\x00(@\x00\x00\x00\x00\x00\x00*@\x00\x00\x00\x00\x00\x00,@\x00\x00\x00\x00\x00\x00.@\x00\x00\x00\x00\x00\x000@\x00\x00\x00\x00\x00\x001@\x00\x00\x00\x00\x00\x002@'
limg.tobytes()
# b'\x18-DT\xfb!\t@'

We can even try to decode that我们甚至可以尝试解码

import struct
limg
# array([[ 24,  45,  68,  84],
#       [251,  33,   9,  64]], dtype=uint8)
struct.pack('BBBBBBBB', 24, 45, 68, 84, 251, 33, 9, 64)
# b'\x18-DT\xfb!\t@'
# See, it is the same things. Just the bytes of limg, that is the 8 1st bytes of img, shown as uint8

struct.unpack('d', struct.pack('BBBBBBBB', 24, 45, 68, 84, 251, 33, 9, 64))
# (3.141592653589793,)
# See, it is just the 8 bytes of float representation of the first float in img (the 7 other are lost

So, the image you have here are image of the bytes of the float data (of the 1st 8th of the float data, since there is no room for more).因此,您在此处拥有的图像是浮点数据字节的图像(浮点数据的第 1 个和第 8 个字节,因为没有更多空间)。 Each group of 8 pixels are the 8 bytes of a float.每组 8 个像素是一个浮点数的 8 个字节。

Same occurs for any operation that turn the ndarray of uint8 into a ndarray of float.将 uint8 的 ndarray 转换为 float 的 ndarray 的任何操作都会发生同样的情况。 Including multiplying by (1/1) .包括乘以(1/1)

Solution解决方案

I don't know what ML model you use.我不知道你用的是什么ML model。 I doubt it requires PIL images.我怀疑它需要 PIL 图像。 So, you could pass it ndarray.所以,你可以将它传递给 ndarray。 Including floats if needed.如果需要,包括花车。

If you really need to use PIL image, then you could use 'F' mode instead of 'L' (which means 8 bits grayscale).如果你真的需要使用 PIL 图像,那么你可以使用“F”模式而不是“L”(这意味着 8 位灰度)。

Note that if you just hadn't passed 'L' argument to fromarray , it would have guessed by itself the mode (grayscale because of the H×W shape — not H×W×3 that would be RGB, or H×W×2 that would be LA,... — 'F' because of the float dtype)请注意,如果您只是没有将 'L' 参数传递给fromarray ,它会自己猜测模式(灰度,因为 H×W 形状 - 而不是 H×W×3,即 RGB,或 H×W× 2 将是 LA,... — 'F' 因为 float dtype)

Also note that your question has nothing to do with scaling.另请注意,您的问题与缩放无关。 You would have had the exact same problem without any resize .如果没有任何resize ,您会遇到完全相同的问题。 Image.fromarray(np.array(img)*1.0, 'L') would have the same problem. Image.fromarray(np.array(img)*1.0, 'L')会有同样的问题。 This is not a scaling quality problem.这不是缩放质量问题。 It is an image format, even a data format, problem;它是一种图像格式,甚至是一种数据格式,问题; you are using memory that contains floats and ask PIL to interpret it as if it were containing uint8.您正在使用包含浮点数的 memory,并要求 PIL 将其解释为包含 uint8。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在没有PIL的情况下使图像的背景显得透明? - How can I make the background of an image appear transparent without PIL? 如何在 python PIL 中不使用 .resize() 调整图像大小 - How can I resize an image without using .resize() in python PIL 如何通过在 Python 中使用 PIL 或 opencv 比较其坐标值,将图像粘贴到另一个图像? - How can I paste an image to another image by comparing its coordinate values using PIL or opencv in Python? 如何使用 OpenCV 删除图像中的一条线而不破坏图像的其余部分? - How do I remove a line in an image with OpenCV without ruining the rest of the image? 如何使用 PIL 保存图像? - How can I save an image with PIL? 如何不能在 PIL 中保存图像? - How can I NOT save an image in PIL? 如何在不保存图像的情况下将 PIL Image 对象上传到 Discord 聊天? - How can I upload a PIL Image object to a Discord chat without saving the image? 如何修复图像的透明度? 太平船务 - How can i fix transparency in image? PIL 在不超过图像尺寸的情况下在 python PIL 中缩放和裁剪图像 - Scale and crop an image in python PIL without exceeding the image dimensions 如何在没有 OpenCV 的情况下通过 ROS 发布 PIL 图像二进制文件? - How can I publish PIL image binary through ROS without OpenCV?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM