
一、PIL
PIL(Python Imaging Library)是Python中一个图像处理标准库。PIL功能非常强大,但API却非常简单易用。PIL仅支持到Python 2.7,后来在PIL的基础上创建了兼容的版本,名字叫Pillow,支持最新Python 3.x,又加入了许多新特性,因此,我们可以直接安装使用Pillow。
1. 安装
sudo pip3 install pillow
2. 基本使用
打开图像文件
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
# 定义一个函数后面用
def show_img(pos,title, img):
plt.subplot(pos)
plt.title(title)
plt.imshow(img)
# 打开图像文件
img = Image.open('/root/workspace/liuzhen/dataset/cat.png')
# 看看长啥样
plt.imshow(img)
plt.show()

查看基本属性
print(img.format)
print(img.size)
print(img.mode)
# Output
JPEG
(1044, 722)
RGB
裁剪与Resize
crop_box = (400, 0, 1000, 600)
img_crop = img.crop(crop_box)
img_resize = img.resize((1024, 720))
plt.figure()
show_img(121, 'Corp Image', img_crop)
show_img(122, 'Resize Image', img_resize)
plt.show()plt.imshow(img_crop)
plt.show()

旋转与翻转
img_gray = img.convert('F') # 灰度图,这里不展开介绍了
img_rotate = img.rotate((90)) # 旋转90度
img_transpose_1 = img.transpose(Image.FLIP_LEFT_RIGHT) # 左右翻转
img_transpose_2 = img.transpose(Image.FLIP_TOP_BOTTOM) # 上下翻转
plt.figure(figsize=(8,8))
show_img(221, 'Gray', img_gray)
show_img(222, 'Rotate', img_rotate)
show_img(223, 'Transpose_left_right', img_transpose_1)
show_img(224, 'Transpose_top_bottom', img_transpose_2)
plt.show()

二、OpenCV
OpenCV的强大就不废话了。这部分主要是对 @YE Y 《给深度学习入门者的Python快速教程 - 番外篇之Python-OpenCV》的学习过程与笔记。
import cv2
新手需要注意的是,在三通道图片中,最常见的是RGB,但是由于历史遗留问题,cv2默认读取的是BGR。如果你发现自己读取或者保存的图片泛着紫光或者绿光,多半是没注意这个问题。
bgr_color_image = cv2.imread('/root/workspace/liuzhen/dataset/cat.png')
rgb_color_image = cv2.cvtColor(bgr_color_image, cv2.COLOR_BGR2RGB)
plt.figure(figsize=(8, 8))
show_img(121, 'BGR Color Image', bgr_color_image)
show_img(122, 'RGB Color Image', rgb_color_image)
plt.show()

裁剪与Resize
patch_color_image = rgb_color_image[0:600, 400:1000]
resize_color_image = cv2.resize(rgb_color_image, (1024, 720))
plt.figure()
show_img(121, 'Patch Image', patch_color_image)
show_img(122, 'Resize Image', resize_color_image)
plt.show()

HSV空间
HSV空间是由美国的图形学专家A. R. Smith提出的一种颜色空间,HSV分别是色调(Hue),饱和度(Saturation)和明度(Value)。在HSV空间中进行调节避免了直接在RGB空间中调节时还需要考虑三个通道的相关性。OpenCV中H的取值是[0, 180),其他两个通道的取值都是[0, 256)
# HSV空间:HSV分别是色调(Hue),饱和度(Saturation)和明度(Value)
img_hsv = cv2.cvtColor(bgr_color_image, cv2.COLOR_BGR2HSV)
# 调整H
change_h = img_hsv.copy()
change_h[:, :, 0] = (change_h[:, :, 0] + 15) % 180
chagne_h_img = cv2.cvtColor(change_h, cv2.COLOR_HSV2RGB)
# 调整S 图片会损失鲜艳,变得更灰
change_s = img_hsv.copy()
change_s[:, :, 1] = 0.5 * change_s[:, :, 1]
change_s_img = cv2.cvtColor(change_s, cv2.COLOR_HSV2RGB)
# 调整V 图片变暗
change_v = img_hsv.copy()
change_v[:, :, 2] = 0.5 * change_v[:, :, 2]
change_v_img = cv2.cvtColor(change_v, cv2.COLOR_HSV2RGB)
# plot image
plt.figure(num=1, figsize=(8, 8))
show_img(221, 'Origin', color_image)
show_img(222, 'Change H', turn_h_img)
show_img(223, 'Change S', turn_s_img)
show_img(224, 'Change V', turn_v_img)
plt.show()

Gamma变换
在图像处理中,Gamma变换用于将漂白(相机过曝)的图片或者过暗(曝光不足)的图片进行修正。其数学表达式如下:

画个图看一下这个函数:
x = np.arange(0, 1, 0.01)
y_ = x
plt.plot(x, y_, label='Original')
for gamma in [0.1, 0.2, 0.5, 2.5, 5, 10]:
y = x ** gamma
plt.plot(x, y, label= 'gamma=%.1f' % gamma)
plt.legend(loc='upper right', bbox_to_anchor=(1.35, 1.02))
# plt.legend(loc='upper right')
plt.xlabel('Input Intensity Level')
plt.ylabel('Output Intensity Level')
plt.show()

可以看出,gamma值小于1时,会拉伸图像中灰度级较低的区域,同时会压缩灰度级较高的部分,gamma值大于1时,会拉伸图像中灰度级较高的区域,同时会压缩灰度级较低的部分。
无论是HSV还是RGB,我们都较难一眼就对像素中值的分布有细致的了解,这时候就需要直方图。如果直方图中的成分过于靠近0或者255,可能就出现了暗部细节不足或者亮部细节丢失的情况。这个时候,一个常用方法是考虑用Gamma变换来提升暗部细节。Gamma变换是矫正相机直接成像和人眼感受图像差别的一种常用手段,简单来说就是通过非线性变换让图像从对曝光强度的线性响应变得更接近人眼感受到的响应。
from mpl_toolkits.mplot3d import Axes3D
hist_b = cv2.calcHist([bgr_color_image], [0], None, [256], [0, 256])
hist_g = cv2.calcHist([bgr_color_image], [1], None, [256], [0, 256])
hist_r = cv2.calcHist([bgr_color_image], [2], None, [256], [0, 256])
# 定义Gamma矫正的函数
def gamma_trans(img, gamma):
# 具体做法是先归一化到1,然后gamma作为指数值求出新的像素值再还原
gamma_table = [np.power(x/255.0, gamma)*255.0 for x in range(256)]
gamma_table = np.round(np.array(gamma_table)).astype(np.uint8)
# 实现这个映射用的是OpenCV的查表函数
return cv2.LUT(img, gamma_table)
# 执行Gamma矫正,小于1的值让暗部细节大量提升,同时亮部细节少量提升
img_corrected = gamma_trans(bgr_color_image, 1.5)
# 分通道计算Gamma矫正后的直方图
hist_b_corrected = cv2.calcHist([img_corrected], [0], None, [256], [0, 256])
hist_g_corrected = cv2.calcHist([img_corrected], [1], None, [256], [0, 256])
hist_r_corrected = cv2.calcHist([img_corrected], [2], None, [256], [0, 256])
fig = plt.figure(figsize=(8, 8))
pix_hists = [
[hist_b, hist_g, hist_r],
[hist_b_corrected, hist_g_corrected, hist_r_corrected]
]
pix_vals = [[i] for i in range(256)]
for sub_plt, pix_hist in zip([121, 122], pix_hists):
ax = fig.add_subplot(sub_plt, projection='3d')
for c, z, channel_hist in zip(['b', 'g', 'r'], [20, 10, 0], pix_hist):
cs = [c] * 256
ax.bar(pix_vals, channel_hist, zs=z, zdir='y', color=cs, alpha=0.618, edgecolor='none', lw=0)
ax.set_xlabel('Pixel Values')
ax.set_xlim([0, 256])
ax.set_ylabel('Channels')
ax.set_zlabel('Counts')
plt.show()

gamma_corrected_image = cv2.cvtColor(img_corrected, cv2.COLOR_BGR2RGB)
plt.figure()
show_img(121, 'Gamma Corrected Image', gamma_corrected_image)
show_img(122, 'Origin Image', rgb_color_image)
plt.show()
