Bootstrap

Python图像读取,图像的PIL.Image, numpy.darray, Tensor形式相互转换

PyCharm中调用远程Python解释器显示opencv图像

20210106记:
  暂时没有找到可以直接在本地Pycharm中显示opencv图像的方法。只好通过以下这种install PyCharm plugins OpenCV Image Viewer的方式暂时先用着。
python - Pycharm, OpenCV execute on remote server and display Image locally - Stack Overflow 20200728
OpenCV Image Viewer - plugin for IntelliJ IDEs | JetBrains

Python读取图像的两种推荐方式

  uint8是无符号八位整型,表示的是区间[0, 255]内的整数。

使用PIL读取图像

from PIL import Image
img = Image.open('./lena.png')  # PIL读入的图像自然就是uint8格式

使用opencv-python读取图像

import cv2
from PIL import Image

img_cv2_color = cv2.imread('lena.png')  # cv2读入的图像默认是uint8格式的numpy.darray, BGR通道
img_cv2_gray = cv2.imread('lena.png', 0)  # img_cv2_gray.shape (512,512)
cv2.imwrite('img_cv2_color.jpg', img_cv2_color)
img = Image.fromarray(img_cv2_color)

  cv2.imread()返回numpy.darray,可直接用Image.fromarray()转换成PIL.Image,读取灰度图像的shape为(H,W),读取彩色图像的shape为(H,W,3), BGR通道。
  cv2写图像时,输入的灰度图像的shape可以为(H,W)或(H,W,1),输入的彩色图像的shape应该为(H,W,3);
  若要从numpy.ndarray得到PIL.Image,灰度图像的shape必须为(H,W),彩色图像的shape必须为(H,W,3);

Python显示图像的五种方式

时间戳: 20200828
Python的imread()函数_Mr. Chen-CSDN博客20180810

方式一:opencv-python

import cv2

img = cv2.imread()
cv2.imshow("Image", img)   
cv2.waitKey(0)  
cv2.destroyAllWindows()

方式二:matplotlib

import numpy as np
from PIL import Image
%matplotlib inline
import matplotlib.image as mpimg
import matplotlib.pyplot as plt

img = mpimg.imread()
plt.imshow(img)
plt.show()

方式三:PIL + matplotlib

import numpy as np
from PIL import Image
import matplotlib.pyplot as plt

img = Image.open()  # PIL读入的图像自然就是uint8格式
# img.show()

# 统一使用plt进行显示, 不管是plt还是cv2.imshow, 在python中只认numpy.ndarray
img = np.array(img)  # 获得numpy对象, np.ndarray, RGB通道
plt.imshow(img)
plt.show()

方式四:scipy + matplotlib

from scipy.misc import imread, imshow, imsave
%matplotlib inline
import matplotlib.pyplot as plt

img = imread()
plt.imshow(img)
plt.show()
imsave("img.jpg",img)

方式五:skimage + matplotlib

import numpy as np
from PIL import Image
from skimage import io
import matplotlib.pyplot as plt

img = io.imread()
plt.imshow(img)
plt.show()

numpy.darray 与 Tensor 相互转换

>>> import numpy as np
>>> import torch
>>> a = np.arange(5)
>>> a
array([0, 1, 2, 3, 4])
>>> b = torch.from_numpy(a)  # numpy.darray 转换成 Tensor
>>> b
tensor([0, 1, 2, 3, 4], dtype=torch.int32)
>>> print(a, '\n', b)
 [0 1 2 3 4] 
tensor([0, 1, 2, 3, 4], dtype=torch.int32)

>>> c = torch.arange(5)
>>> c
tensor([0, 1, 2, 3, 4])
>>> d = c.numpy()  # Tensor 转换成 numpy.darray
>>> d
array([0, 1, 2, 3, 4], dtype=int64)
>>> e = np.array(c)  # Tensor 转换成 numpy.darray
>>> e
array([0, 1, 2, 3, 4], dtype=int64)
>>> print(c, '\n', d, '\n', e)
tensor([0, 1, 2, 3, 4]) 
 [0 1 2 3 4] 
 [0 1 2 3 4]

PIL.Image 与 numpy.ndarray 相互转换

from PIL import Image
import numpy as np
img_pil = Image.open('./lena.png')   # PIL读入的图像自然就是uint8格式
a = np.array(img_pil)  # PIL.Image 转换成 numpy.darray
# a = np.asarray(img_pil)  # PIL.Image 转换成 numpy.darray


# 先把numpy.darray转换成np.unit8, 确保像素值取区间[0,255]内的整数
# 灰度图像需保证numpy.shape为(H,W),不能出现channels,可通过执行np.squeeze()剔除channels;
# 彩色图象需保证numpy.shape为(H,W,3)
a = a.astype(np.uint8)  # a.astype('uint8')  # a = np.uint8(a)
# 再转换成PIL Image形式
img = Image.fromarray(a)  # numpy.darray 转换成 PIL.Image

  若要从numpy.ndarray得到PIL.Image,灰度图像的shape必须为(H,W),彩色图像的shape必须为(H,W,3);

PIL.Image 转换成 Tensor

from PIL import Image
import torch
import torchvision.transforms as transforms

path_img = "./lena.png"  # your path to image
img_pil = Image.open(path_img).convert('RGB')  # 0~255
img_transforms = transforms.Compose([
    # transforms.Resize((224, 224)),
    transforms.ToTensor(),
    # transforms.Normalize(norm_mean, norm_std),
    ])
img_tensor = img_transforms(img_pil)
# img_tensor.unsqueeze_(0)  # CHW --> BCHW
# fmap_1 = convlayer1(img_tensor)

Tensor 转换成 PIL.Image

# 先把Tensor转换成numpy.darray,再把numpy.darray 转换成 PIL.Image
import numpy as np
import torch
import torchvision.transforms as transforms
from PIL import Image
from matplotlib import pyplot as plt

img_transforms = transforms.Compose([
    # transforms.Resize((224, 224)),
    transforms.ToTensor(),
    # transforms.Normalize(norm_mean, norm_std),
    ])


def transform_invert(img_, transform_train):
    """
    将data 进行反transfrom操作
    :param img_: Tensor
    :param transform_train: torchvision.transforms
    :return: PIL image
    """
    if 'Normalize' in str(transform_train):
        norm_transform = list(filter(lambda x: isinstance(x, transforms.Normalize), transform_train.transforms))
        mean = torch.tensor(norm_transform[0].mean, dtype=img_.dtype, device=img_.device)
        std = torch.tensor(norm_transform[0].std, dtype=img_.dtype, device=img_.device)
        img_.mul_(std[:, None, None]).add_(mean[:, None, None])

    # img_ = img_.transpose(0, 2).transpose(0, 1)  # C*H*W --> H*W*C
    img_ = img_.permute(1, 2, 0)  # C*H*W --> H*W*C
    if 'ToTensor' in str(transform_train):
        img_ = np.array(img_)  # 先把Tensor转换成numpy.darray
        img_ -= np.min(img_)
        img_ /= np.max(img_)
        img_ = img_ * 255

    # 再把numpy.darray转换成PIL.Image
    if img_.shape[2] == 3:
        img_ = Image.fromarray(img_.astype('uint8')).convert('RGB')
    elif img_.shape[2] == 1:
        img_ = Image.fromarray(img_.astype('uint8').squeeze())
    else:
        raise Exception("Invalid img shape, expected 1 or 3 in axis 2, but got {}!".format(img_.shape[2]) )

    return img_


# img_pil = Image.open('./lena.png').convert('RGB')  # 彩色图像
img_pil = Image.open('./lena.png').convert('L')  # 灰度图像
# plt.imshow(img_pil)
# plt.show()
img_tensor = img_transforms(img_pil)
img = transform_invert(img_tensor, img_transforms)
plt.imshow(img)
plt.show()

参考链接

python、PyTorch图像读取与numpy转换_Python_便纵有千种风情 20180615

python处理图像何时要将图像转化为uint8格式?uint8是什么?用array()方法打开图像后图像是什么格式?20190214

(待阅读) cv2.imshow()和plt.imshow()显示的色差问题_Python_Max 20190308

PIL报错

PIL/ImageFile.py, OSError: broken data stream when reading image file, LOAD_TRUNCATED_IMAGES

20210426记:
通过findout_truncated_images.py脚本,找出truncated image并输出其文件名;
Python程序中PIL Image "image file is truncated"问题分析与解决_楚小菜的博客-CSDN博客 20190421
20210520记:
如何找出truncated images可参考:
How to root out corruption in your image folders | Opensource.com 20170217
IOError: broken data stream when reading image file · Issue #1510 · python-pillow/Pillow · GitHub

Corrupt JPEG data: premature end of data segment.
OSError: broken data stream when reading image file

[04/26 10:33:28 d2.utils.events]:  eta: 1:21:10  iter: 399  total_loss: 0.6431  loss_cls: 0.1832  loss_box_reg: 0.3118  loss_rpn_cls: 0.05991  loss_rpn_loc: 0.06856  time: 0.5855  data_time: 0.1716  lr: 0.007982  max_mem: 3240M
Traceback (most recent call last):
  File "/media/username/win10文件目录/usrname_workdir/usr/Pytorch_WorkSpace/OpenSourcePlatform/AdelaiDet/tools/./train_net_Detectron2_hcy.py", line 303, in <module>
    launch(
  File "/home/username/miniconda2/envs/usr_detectron2/lib/python3.9/site-packages/detectron2/engine/launch.py", line 55, in launch
    mp.spawn(
  File "/home/username/miniconda2/envs/usr_detectron2/lib/python3.9/site-packages/torch/multiprocessing/spawn.py", line 199, in spawn
    return start_processes(fn, args, nprocs, join, daemon, start_method='spawn')
  File "/home/username/miniconda2/envs/usr_detectron2/lib/python3.9/site-packages/torch/multiprocessing/spawn.py", line 157, in start_processes
    while not context.join():
  File "/home/username/miniconda2/envs/usr_detectron2/lib/python3.9/site-packages/torch/multiprocessing/spawn.py", line 118, in join
    raise Exception(msg)
Exception: 

-- Process 1 terminated with the following error:
Traceback (most recent call last):
  File "/home/username/miniconda2/envs/usr_detectron2/lib/python3.9/site-packages/torch/multiprocessing/spawn.py", line 19, in _wrap
    fn(i, *args)
  File "/home/username/miniconda2/envs/usr_detectron2/lib/python3.9/site-packages/detectron2/engine/launch.py", line 94, in _distributed_worker
    main_func(*args)
  File "/media/username/win10文件目录/usrname_workdir/usr/Pytorch_WorkSpace/OpenSourcePlatform/AdelaiDet/tools/train_net_Detectron2_hcy.py", line 297, in main
    return trainer.train()
  File "/home/username/miniconda2/envs/usr_detectron2/lib/python3.9/site-packages/detectron2/engine/defaults.py", line 419, in train
    super().train(self.start_iter, self.max_iter)
  File "/home/username/miniconda2/envs/usr_detectron2/lib/python3.9/site-packages/detectron2/engine/train_loop.py", line 134, in train
    self.run_step()
  File "/home/username/miniconda2/envs/usr_detectron2/lib/python3.9/site-packages/detectron2/engine/defaults.py", line 429, in run_step
    self._trainer.run_step()
  File "/home/username/miniconda2/envs/usr_detectron2/lib/python3.9/site-packages/detectron2/engine/train_loop.py", line 222, in run_step
    data = next(self._data_loader_iter)
  File "/home/username/miniconda2/envs/usr_detectron2/lib/python3.9/site-packages/detectron2/data/common.py", line 179, in __iter__
    for d in self.dataset:
  File "/home/username/miniconda2/envs/usr_detectron2/lib/python3.9/site-packages/torch/utils/data/dataloader.py", line 435, in __next__
    data = self._next_data()
  File "/home/username/miniconda2/envs/usr_detectron2/lib/python3.9/site-packages/torch/utils/data/dataloader.py", line 1065, in _next_data
    return self._process_data(data)
  File "/home/username/miniconda2/envs/usr_detectron2/lib/python3.9/site-packages/torch/utils/data/dataloader.py", line 1111, in _process_data
    data.reraise()
  File "/home/username/miniconda2/envs/usr_detectron2/lib/python3.9/site-packages/torch/_utils.py", line 428, in reraise
    raise self.exc_type(msg)
OSError: Caught OSError in DataLoader worker process 2.
Original Traceback (most recent call last):
  File "/home/username/miniconda2/envs/usr_detectron2/lib/python3.9/site-packages/torch/utils/data/_utils/worker.py", line 198, in _worker_loop
    data = fetcher.fetch(index)
  File "/home/username/miniconda2/envs/usr_detectron2/lib/python3.9/site-packages/torch/utils/data/_utils/fetch.py", line 44, in fetch
    data = [self.dataset[idx] for idx in possibly_batched_index]
  File "/home/username/miniconda2/envs/usr_detectron2/lib/python3.9/site-packages/torch/utils/data/_utils/fetch.py", line 44, in <listcomp>
    data = [self.dataset[idx] for idx in possibly_batched_index]
  File "/home/username/miniconda2/envs/usr_detectron2/lib/python3.9/site-packages/detectron2/data/common.py", line 43, in __getitem__
    data = self._map_func(self._dataset[cur_idx])
  File "/home/username/miniconda2/envs/usr_detectron2/lib/python3.9/site-packages/detectron2/data/dataset_mapper.py", line 125, in __call__
    image = utils.read_image(dataset_dict["file_name"], format=self.image_format)
  File "/home/username/miniconda2/envs/usr_detectron2/lib/python3.9/site-packages/detectron2/data/detection_utils.py", line 183, in read_image
    return convert_PIL_to_numpy(image, format)
  File "/home/username/miniconda2/envs/usr_detectron2/lib/python3.9/site-packages/detectron2/data/detection_utils.py", line 75, in convert_PIL_to_numpy
    image = image.convert(conversion_format)
  File "/home/username/miniconda2/envs/usr_detectron2/lib/python3.9/site-packages/PIL/Image.py", line 893, in convert
    self.load()
  File "/home/username/miniconda2/envs/usr_detectron2/lib/python3.9/site-packages/PIL/ImageFile.py", line 284, in load
    raise_oserror(err_code)
  File "/home/username/miniconda2/envs/usr_detectron2/lib/python3.9/site-packages/PIL/ImageFile.py", line 67, in raise_oserror
    raise OSError(message + " when reading image file")
OSError: broken data stream when reading image file

(usr_detectron2) username@username-System-Product-Name:~/usrname_workdir/usr/Pytorch_WorkSpace/OpenSourcePlatform/AdelaiDet/tools$ /home/username/miniconda2/envs/usr_detectron2/lib/python3.9/multiprocessing/resource_tracker.py:216: UserWarning: resource_tracker: There appear to be 20 leaked semaphore objects to clean up at shutdown
  warnings.warn('resource_tracker: There appear to be %d '

;