图像加载【Image.open(),cv2.imread()】和转换格式【Image.convert(format_str),cv2.cvtColor()】详解

引 言 视觉任务处理的图片按照图像通道深度分为单通道图像和多通道图像。单通道图像有grayscale灰度图、binary二值图、PNG图,多通道图像有三通道24位真彩色RGB图,8位伪彩色图像,YCbCr图像等。本文先着重介绍各种格式图像的特点,随后讲解图像的多种加载方法【Image.open()和cv2.imread()】及格式转换语句【Image.convert(),cv2.cvtColor()】,并说明图像矩阵数据不同存储方式ndarray和tensor的维度变化,最后列举一个提取RGB每个通道图片的示例,让读者更清晰的了解图像深度的意义。

一、常见图像格式介绍

1.1 grayscale灰度图

灰度图为单通道图像,每个像素值为8bit,像素取值范围:0~255,其中0:黑,255:白,其他像素值表示不同的灰度等级。
示例:模仿灰度图像素值的示例代码及显示效果

img_gray = np.array([[0,120,230],[255,60,150],[100,60,30]])
print('image pixel values:\n',img_gray)
plt.imshow(img_gray,cmap=plt.cm.gray) 
plt.title('Display image pixel values')
plt.axis('off')		#取消坐标系
plt.show()

###
image pixel values:
 [[  0 120 230]
 [255  60 150]
 [100  60  30]]

在这里插入图片描述

1.2 二值图像

图像中只有两种像素值黑与白,黑:0,白:1。
示例:将上例中的灰度图像转换成二值图

img_gray = np.array([[0,120,230],[255,60,150],[100,60,30]])
#像素值>127变成1,否则变成0
img_binary = np.where(img_gray>127,1,0)
print('binary image pixel values:\n',img_binary)
plt.imshow(img_binary,cmap='gray')
plt.title('Display binary image pixel values')
plt.show()

###
binary image pixel values:
 [[0 0 1]
 [1 0 1]
 [0 0 0]]

在这里插入图片描述

1.3 PNG格式图像

png格式图像一般为8bit图像,每个像素值对应的RGB三分量通过查阅调色板获取。不同png图片的调色板可能相同也可能不同,主要取决于图像所用的颜色集合是否相同。调色板数据样式:

索引号RGB
0000
255255255255
  1. 获取图像调色板代码如下
img_path = r'F:\pytorch_project\panda.png'
image = Image.open(img_path).convert('P')

if image.mode == 'P':
    palette = image.getpalette()
else:
    print('picture has no palette')
  1. 打印调色板信息列举了两种常用的方法。方法一:由于调色板每个索引编号对应三个颜色分量,可以对调色板列表直接变成ndarray数组,对数组实施变形操作变成最后维度为3的数组。方法二:对列表中相邻3个元素封装成一个颜色元组。
    调色板(palette)结果应存储成字典格式{索引号:color元素}文件,在语义分割任务中,对于使用相同颜色集合的图片,深度模型预测的像素值索引查阅调色板绘制png语义分割图片。
# 方法一:对palette数组直接变形
palette_reshape = np.reshape(palette, (-1, 3)).tolist()
# 转换成字典子形式
palette_dict = dict((i, color) for i, color in enumerate(palette_reshape))
print(palette_dict)
print('-'*50)

# 方法二:对列表中相邻3个元素封装成一个颜色元组
palette_dict = {}
for i in range(0,len(palette),3):

    color = (palette[i],palette[i+1],palette[i+2])
    palette_dict[i//3] = color
    
print(palette_dict)

将字典数据存入json格式文件中,便于使用相同颜色集合的语义分割任务对图片实施语义分割。

#将字典写入文件
json_str = json.dumps(palette_dict)
with open("palette.json", "w") as f:
    f.write(json_str)

1.4 RGB格式图像

传统的红绿蓝三色图有三个通道,每个通道分量8bit,取值范围:0~255,每个像素值共有24bit。

1.5 RGBA图像

图像为32bit,前24bit存储RGB三通道像素值,最后8bit存储透明度信息。

1.6 8位伪彩色图

每个像素值代表像素表的索引地址,在像素表中RGB三分量不完全相同。

索引号RGB
25500
绿02550
2552550

二、图像加载和格式转换

2.1 图像加载方式

图像加载可以通过调用PIL库加载,也可以调用cv2库加载图像。

2.1.1 调用Image.open(img_path)加载图像
img_path = r'F:\pytorch_project\plane.jpg'
image = Image.open(img_path)
img = np.array(image)
2.1.2 调用cv2.imread(img_path,flags=1)加载图像

flags属性:flags=0,提取单通道黑白图像。flags=1提取三通道彩色图像。

注意cv2.imread()提取的彩色图像格式为【H,W,C】,最后的通道维度顺序是BGR正好与RGB相反,在使用过程中需要对最后一个维度的数据进行逆序操作变成熟悉的RGB格式(使用列表逆序操作list[::-1])。

# 1.加载单通道图片并展示
import cv2
import numpy as np
import matplotlib.pyplot as plt

img_path = r'F:\pytorch_project\plane.jpg'
image = cv2.imread(img_path,flags=0)
img = np.array(image)
plt.imshow(img,cmap='gray')
plt.show()

# 2.加载彩色图片并展示
img_path = r'F:\pytorch_project\plane.jpg'
image = cv2.imread(img_path,flags=1)
img = np.array(image)
plt.imshow(img[:,:,::-1])
plt.show()

也可以直接使用cv2模块内的imshow()显示图片,但需要设置等待按键响应否则图像一闪而过。

img_path = r'F:\pytorch_project\plane.jpg'
image = cv2.imread(img_path,flags=1)	
cv2.imshow('image',image)

## 等待显示
k = cv2.waitKey(0)
## 键入esc时退出,s保存退出
if k == 27:
    cv2.destoryAllWindows()
elif k == ord('s'):
    cv2.imwrite('img_1.jpg', image)
    cv2.destoryAllWindows()

2.2 图像格式转换

2.2.1 Image.open(img_path).convert(format_str)

图像转换成项目需要的格式可以调用PIL库的函数:Image.open(img_path).convert(format_str)
format_str:‘RGB’,‘L’, ‘1’,‘P’,‘RGBA’, 'YCbCr’等。

## 1.RGB格式图像
image_RGB = Image.open(img_path).convert('RGB')

## 2.grayscale灰度图
image_gray = Image.open(img_path).convert('L')
## 此外,`convert('I')`表示32位整型灰度图,`convert('F')`表示32为浮点型灰度图。

## 3.二值图像
image_binary = Image.open(img_path).convert('1')

## 4.PNG格式图像
image_P = Image.open(img_path).convert('P')

## 5.RGBA图像
## 图像为32bit,前24bit存储RGB三通道像素值,最后8bit存储透明度信息
image_RGBA = Image.open(img_path).convert('RGBA')

## 6.YCbCr图像
## YCbCr图为24bit彩色图,Y表示亮度通道,Cb和Cr表示两个色度通道,肉眼对亮度通道敏感,对两个色度通道进行下采样
image_Ycbcr = Image.open(img_path).convert('YCbCr')

## 图像展示
titles = ['RGB','gray','binary','P','RGBA','YCbCr']
img_list = [image_RGB,image_gray,image_binary,image_P,image_RGBA,image_Ycbcr]
for i in range(len(img_list)):
    plt.subplot(2,3,i+1)
    plt.title(titles[i])
    plt.imshow(img_list[i],cmap='gray')

plt.show()
2.2.2 cv2.cvtColor(image, code)

调用OpenCV库的cv2.cvtColor(image, code)函数同样可以进行图像格式转换。

## 1.RGB格式图像
image_RGB = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
## 2.灰度图
image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
## 3.HSV格式图
image_HSV = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
## 4.YCrCb格式图
image_YCbCr = cv2.cvtColor(image, cv2.COLOR_BGR2YCbCr)
2.2.3 图像灰度化处理

彩色图像变成灰度图除了直接调用格式转换语句,也可以针对不同色度通道的像素进行处理获得理想的灰度图,处理方式常见的有:像素最大值,像素平均值和像素加权求和。
(1)RGB像素最大值灰度化

## 1.RGB三通道像素最大值
## gray = max(R,G,B)

img_path = r'F:\pytorch_project\plane.jpg'
image = Image.open(img_path)
img = np.array(image)
h,w = img.shape[0],img.shape[1]
img_gray = np.zeros((h,w),dtype=np.uint8)

## 方法一:
for i in range(h):
    for j in range(w):
        gray = max(img[i,j,0],img[i,j,1],img[i,j,2])
        img_gray[i,j] = gray
        
## 方法二:
img_gray1 = np.zeros_like(img[...,0])
img_gray1[...] = np.max(img,axis=-1).astype(np.uint8)

## 方法三:
img_gray2 = np.zeros_like(img[..., 0]).astype(np.uint8)
inter = np.maximum(img[..., 0],img[..., 1])
img_gray2[...] = np.maximum(inter,img[..., 2])

## 展示图片
plt.imshow(img_gray,cmap='gray')
plt.show() 

(2)RGB三通道像素平均值灰度化

## 2.RGB三通道像素平均值
## gray = mean(R,G,B)

## 方法一:
img_gray = np.zeros((h,w),dtype=np.uint8)
for i in range(h):
    for j in range(w):
        gray = np.array([img[i,j,0],img[i,j,1],img[i,j,2]]).mean().astype(np.uint8)
        img_gray[i,j] = gray
## 方法二:
img_gray1 = np.zeros_like(img[...,0])
img_gray1[...] = np.mean(img,axis=-1).astype(np.uint8)

(3)RGB三通道像素加权和灰度化

## 3.RGB三通道像素加权和
## gray = 0.299*R+0.587*G+0.114*B

## 方法一:
img_gray = np.zeros((h,w),dtype=np.uint8)
for i in range(h):
    for j in range(w):
        gray = img[i,j,0]*(299/1000)+img[i,j,1]*(587/1000)+img[i,j,2]*(114/1000)
        img_gray[i,j] = gray

## 方法二:
img_gray1 = np.zeros_like(img[...,0]).astype(np.uint8)
img_gray1[...] = img[:,:,0]*(299/1000)+img[:,:,1]*(587/1000)+img[:,:,2]*(114/1000)

三、区分numpy.array和torch.tensor存储图像维度变化

numpy.ndarray存储的图像维度为(宽、高、通道)【W,H,C】,torch.tensor存储的图像维度为(通道、宽、高)【C,W,H】,在使用过程中要根据具体使用需求对图像矩阵进行维度转换。

import numpy as np
from PIL import Image
from torchvision import transforms

img_path = r'F:\pytorch_project\plane.jpg'

image = Image.open(img_path).convert('RGB')

# image变成numpy.ndarray
img_np = np.array(image)
# image变成torch.tensor
img_tensor = transforms.ToTensor()(image)

print("numpy.array shape: {}".format(img_np.shape))
print("torch.tensor shape: {}".format(img_tensor.shape))

###
numpy.array shape: (1200, 1920, 3)
torch.tensor shape: torch.Size([3, 1200, 1920])

四、RGB各通道图像提取

对RGB各图层图像提取并展示有利于更直观了解图像的情况。

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


img_path = r'F:\pytorch_project\plane.jpg'

# 获取图像数据
image = Image.open(img_path).convert('RGB')
img = np.array(image) #[w,h,c]

img_list = []

# 获取各通道图层数据
for i in range(img.shape[-1]):
    temp = np.zeros_like(img)
    temp[...,i] = img[:,:,i]
    img_list.append(temp)

# 图像展示
fig,axes = plt.subplots(1,3)
titles = ['the image of {} channel'.format(channel) for channel in ['R','G','B']]

for i in range(len(img_list)):
    axes[i].imshow(img_list[i])
    axes[i].set_title(titles[i])
    
plt.show()

在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值