目前接触过的python图像处理代码涉及到多种的图像库,其中最常用的当属opencv和PIL。惭愧的是,以前只是拿来用,却一直迷惑为什么不同的代码会选择不同的图像库、这些图像库的联系和区别又是什么,这些迷惑也迟迟没有解决。现在,我终于要好好整理一下了!
OpenCV是一个开源的计算机视觉库,该项目由Intel发起,采用C/C++语言编写,可以运行在Linux/Windows/Mac等操作系统上,还提供了Python、Ruby、MATLAB以及其他语言的接口。OpenCV的设计目标是执行速度尽量快,主要关注实时应用,帮助开发人员更便捷地设计更复杂的计算机视觉相关应用程序。
1. 安装
最简单直接的方式:
$ pip install opencv-python
2. 图像读取
import cv2
img = cv2.imread('image.jpg') #读取图像,默认得到的是一个BGR模式的彩色图像,存储为numpy矩阵
#opencv在读取图像时,若path错误,仅会返回None,而不会报错
#img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB) #将颜色模式从BGR转化成RGB
CV2.imwrite('new_image.jpg',img) #保存图像,仍是以正常读入图像的色彩保存
cv2.imshow('window_name',img) #将图像以窗口的形式显示在屏幕上
cv2.waitKey() #在imshow之后如果没有waitKey语句则不会正常显示图像,程序等待用户触发按键操作
cv2.destroyAllWindows() #销毁所有创建的窗口
为什么OpenCV读取的图像格式是BGR?
答: OpenCV在1999年由Intel建立,当时主流的摄像头制造商和软件供应商提供的摄像头采集的图像的通道排列顺序为BGR,另外对于图片,位图BMP是最简单的,也是Windows显示图片的基本格式,其文件扩展名为*.BMP。在Windows下,任何格式的图片文件(包括视频播放)都要转化为位图才能显示出来,各种格式的图片文件也都是在位图格式的基础上采用不同的压缩算法生成的,值得注意的是位图BMP的格式就是BGR。正是基于BGR在当时被广泛使用,于是早期OpenCV开发者就选择BGR颜色格式,这也就成为了一种规范一直用到现在。
3. 图像属性
h,w,c = img.shape #tuple的第一维度是图像高度,对应numpy行数;第二维度是宽度,对应numpy列数;第三维度是通道数。
print('图像的像素: ',img.size) #如果img.shape=(224,224,3),则输出224*224*3=150528
print('图像的数据类型: ',img.dtype) #uint8
4. 图像处理
#平滑处理/图像模糊
img_Blur = cv2.blur(img,(5,5)) #均值滤波,5×5邻域
img_medianBlur = cv2.medianBlur(img,5) #中值滤波
img_GaussianBlur = cv2.GaussianBlur(img,(7,7),0) #高斯滤波
img_bilateral = cv2.bilateralFilter(img,9,75,75) #双边滤波,颜色和空间双线性3×3滤波
#形态学处理
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5)) #矩形结构
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5)) #椭圆结构
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (5, 5)) #十字形结构
kernel = np.ones((5, 5), np.uint8) #自定义kernel
erosion = cv2.erode(img, kernel) #腐蚀
dilation = cv2.dilate(img, kernel) #膨胀
opened = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel) #开运算,先腐蚀后膨胀,消除灰度高于其邻近点的孤立点
closed = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel) #闭运算,先膨胀后腐蚀,消除灰度低于其邻近点的孤立点
#图像缩放
img_resize = cv2.resize(img,(h,w),interpolation=cv2.INTER_AREA) #插值方式为区域插值
# 插值方式默认为线性插值 cv2.INTER_LINEAR
# 其他插值方式:最近邻插值 cv2.INTER_NN,三次样条插值 cv2.INTER_CUBIC
#阈值化
ret,mask = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY) #ret是阈值,mask是二值化图像
# 其他阈值化方式:
cv2.THRESH_BINARY_INV
cv2.THRESH_TRUNC
cv2.THRESH_TOZERO_INV
cv2.THRESH_TOZERO
#自适应二值阈值化
mask = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2) #11是block_size,2是对block区域所有像素平均加权后减去2这个常数,即为阈值。
#cv2.ADAPTIVE_THRESH_GAUSSIAN_C 是按照周围像素按高斯函数离中心点的距离进行加权计算。
5. 图像变换
img_rotate = cv2.rotate(img, 0) #旋转90°,或者改变0为1(180°)、2(270°)
# 另一种方式旋转
mat_rotate = cv2.getRotationMatrix2D((image_height*0.5,image_weight*0.5),45,1) #获得仿射变换矩阵,参数分别为中心点、旋转角度、缩放比例
dst_rotate = cv2.warpAffine(img,mat_rotate,(image_height,image_weight))
#仿射
mat_src = np.float32([[0,0],[0,image_height-1],[image_weight-1,0]])
mat_dst = np.float32([[50,50],[300,image_height-200],[image_weight-300,100]])
mat_Affine = cv2.getAffineTransform(mat_src,mat_dst) #以三个点为基准对应变换
dst = cv2.warpAffine(img,mat_Affine,(image_height,image_weight))
#翻转
img_filp = cv2.flip(img,0) #0:垂直翻转;1:水平翻转;-1:垂直+水平翻转
PIL(Python Imaging Library),是python的第三方图像处理库,但是由于其强大的功能与众多的使用人数,几乎已经被认为是python官方图像处理库了。 PIL历史悠久,原来是只支持python2.x的版本,后来出现了移植到python3的pillow库,pillow相比opencv更为轻巧、容易安装。
1. 安装
$ pip install pillow
2. 图像读取
from PIL import Image #Image类是PIL中的核心类
import numpy as np
img = Image.open('image.jpg')
#PIL读取图片获得的不是矩阵,而是Image格式,可以利用numpy进行转化
im.show() #显示图像
array = np.asarray(img) #img->array
img = Image.fromarray(array) #array->img
new_img = im.convert("L") #'RGB'(真彩图)、'L'(灰度图)、'CMYK'(压缩图)
new_img.save('new_image.jpg') #保存图像
3. 图像属性
w,h = img.size #图像的宽度和高度
print('图像的格式: ',img.format) #常见的有JPEG,PNG等
print('图像的模式: ',img.mode) #常见的有RGB,HSV等
4. 图像处理
from PIL import ImageFilter
#图像滤波
img_blur = img.filter(ImageFilter.BLUR) #模糊滤波
img_contour = img.filter(ImageFilter.CONTOUR) #轮廓滤波
img_detail = img.filter(ImageFilter.DETAIL) #细节滤波
img_edge_enhance = img.filter(ImageFilter.EDGE_ENHANCE) #边界增强滤波
img_smooth = img.filter(ImageFilter.SMOOTH) #平滑滤波
img_sharp = img.filter(ImageFilter.SHARPEN) #锐化滤波
img_gauss = img.filter(ImageFilter.GaussianBlur(radius=2)) #高斯模糊滤波,radius指定平滑半径,也就是模糊的程度。
#图像缩放
img_resize = img.resize((200,200)) #插值方式默认为最近邻插值,Image.NEAREST
# 其他插值方式:双线性插值 Image.BILINEAR,三次样条插值 Image.BICUBIC,Lanczos重采样 Image.LANCZOS
#剪裁
region = img.crop((upper_left_x,upper_left_y,lower_right_x,lower_right_y))
from PIL import ImageEnhance
#图像增强
img_color = ImageEnhance.Color(img).enhance(0.1) #颜色增强,增强因子决定图像的颜色饱和度,为0.0将产生黑白图像;为1.0将给出原始图像
im_bright = ImageEnhance.Brightness(img).enhance(0.2) #用于调整图像的亮度
im_contrast = ImageEnhance.Contrast(img).enhance(0.5) #用于调整图像的对比度
im_sharp =ImageEnhance.Sharpness (img).enhance(2.0) #增强因子为0.0将产生模糊图像;为1.0将保持原始图像,为2.0将产生锐化过的图像
5. 图像变换
im_30 = img.rotate(30)
img_rotate = img.transpose(Image.ROTATE_90) #旋转90°,或者改变为180、270
im_flip = im.transpose(Image.FLIP_LEFT_RIGHT) #左右翻转,或者上下翻转 Image.FLIP_TOP_BOTTOM
matplotlib是python受MATLAB的启发构建的2D绘图库,能够生成各种格式的图形(诸如折线图,散点图,直方图等等),界面可交互(可以利用鼠标对生成图形进行点击操作)。同时,该2D图形库跨平台,即既可以在Python脚本中编码操作,也可以在Jupyter Notebook中使用,以及其他平台都可以很方便的使用matplotlib图形库,而且生成图形质量较高,甚至可以达到出版级别。
1. 安装
$ pip install matplotlib
2. 图像读取
import matplotlib.pyplot as plt
import numpy as np
img = plt.imread('image.jpg') #读取图像,类型为numpy矩阵,并且进行了归一化操作
plt.imshow(img)
plt.show() #matplotlib在执行imshow之后,必须跟着执行show()
plt.savefig('new_img.jpg') #保存当前的图表fig
img.imsave('new_img.jpg') #保存img
由于matplotlib是一个绘图的库,因此没有图像处理相关的算法。
3. 图像绘制
#常用的plt方法
x = np.linspace(0,10,1000)
y = np.sin(x)
z = np.cos(x**2)
plt.figure(figsize=(8,4),dpi=200) #新建一个figure(图表)并将他作为当前figure对象,(8,4)为宽和高,dpi为分辨率,即每英寸有多少个像素
plt.plot(x,y,label = '$sin(x)$',color='g',linewidth = 2) #label将在图示中显示,如前后有$,则将其转化为数学公式,linewidth可缩写为lw
plt.plot(x,z,"b--",label = '$cos(x)$') #"b--":b代表蓝色,--代表虚线
plt.xlabel('Times')
plt.ylabel('Volt')
plt.legend()#显示图示
plt.show()
plt.savefig('image.png',dpi = 120)#设置分辨率为120,本例figsize=(8,4),所以图像分辨率是960x480
fig,axes = plt.subplots(2,2)#subplots同时创建多个子图,并返回当前的figure(图表)和子图列表
[ax1,ax2],[ax3,ax4] = axes
ax1.plot(x, x) #子图1
ax2.plot(x, -x) #子图2
ax3.plot(x, x**2) #子图3
ax3.grid(color='r', linestyle='--', linewidth=1, alpha=0.3)
ax4.plot(x, np.log(x)) #子图4
ax4.set_title('y=logx')
plt.show()
skimage即是scikit-Image,是基于python脚本语言开发的数字图片处理库,提供了一组用于图像处理和计算机视觉的算法。 PIL和Pillow只提供最基础的数字图像处理,功能有限;opencv实际上是一个c++库,只是提供了python接口,更新速度非常慢。scikit-image是基于scipy的一款图像处理包,它将图片作为numpy数组进行处理,正好与matlab一样。
1. 安装
$ pip install scikit-image
2. 图像读取
from skimage import io,color
img = io.imread('image.jpg') #读取图像,类型为numpy矩阵
img_grey = color.rgb2grey(img) #彩色转灰度
io.imshow(img)
io.show()
io.imsave('new_img.jpg',img_grey)
#与plt用法很相似
3. 图像处理
from skimage import filters
#图像滤波
img_gaussian = filters.gaussian(img) #是一种平滑滤波,可以消除高斯噪声
img_sobel = filters.sobel(img) #边缘检测
img_roberts = filters.roberts(img) #边缘检测
th_ostu = filters.threshold_otsu(img_grey) #返回一个阈值,最大类间方差法,是一种对灰度图像进行二值化的算法,根据图像灰度分成前景和背景两部分,使前景和背景图像的类间方差最大。
mask = filters.threshold_adaptive(img, block_size=13, method='gaussian') #默认为‘gaussian’
#其他确定自适应阈值的方法有'mean', 'generic', 'median'
4. 图像变换
from skimage import transform
img_resize = transform.resize(img, (80, 60)) #图像缩放
img_rotate=transform.rotate(img, 60) #旋转60°大小不变
还有其他的算法可以对照表格进行查找,就不一一举例了。
模块 | 功能 |
---|---|
io | 读取、保存和显示图片或视频 |
data | 提供一些测试图片和样本数据 |
color | 颜色空间变换 |
filters | 图像增强、边缘检测、排序滤波器、自动阈值等 |
draw | 操作于numpy数组上的基本图形绘制,包括线条、矩形、圆和文本等 |
transform | 几何变换或其它变换,如旋转、拉伸和拉东变换等 |
morphology | 形态学操作,如开闭运算、骨架提取等 |
exposure | 图片强度调整,如亮度调整、直方图均衡等 |
feature | 特征检测与提取等 |
measure | 图像属性的测量,如相似性或等高线等 |
segmentation | 图像分割 |
restoration | 图像恢复 |
util | 通用函数 |