OpenCV | 图像的显示与存储

一、python-opencv的安装

方法一:使用pip命令

  • opencv依赖于Numpy和wheel两个包,需要提前安装
  • 若下载很慢可以使用 -i 设置使用清华源镜像
  • opencv-python为基础包,opencv-contrib-python则包含额外的模块
1
2
3
pip install wheel
pip install numpy
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple opencv-contrib-python

方法二:去官网下载安装包,后手动安装

下载链接: https://sourceforge.net/projects/opencvlibrary/files/

二、图像的读取、显示与保存

​ 使用函数 cv2.imread() 读入图像,该函数包含两个参数

/image/CSDN-20200223121923591.png

  • 第一个参数以字符串形式提供图像的路径,可以是相对该程序的相对路径,或绝对路径

  • 第二个参数表示如何读取这幅图片,如下为常用的flag

    • cv2.IMREAD_GRAYSCALE:读入灰度模式图像,也可以用0表示
    • cv2.IMREAD_COLOR:读入彩色图像(不包含透明度),也可以用1表示,为空缺时的默认参数
    • cv2.IMREAD_UNCHANGED:读入一幅图像,并包括图像的alpha通道

    注意: OpenCV 也不会提醒你路径是否错的,但是使用命令print img时得到的结果为None

1
2
3
4
5
6
7
# 引包
import numpy as np
import cv2
from matplotlib import pyplot as plt

# 读入图像
img = cv2.imread('image/01.png',0)

方法一:使用Matplotlib显示图像

​ Matplotib是python的一个绘图库,其中包含各种各样的绘图方法,可以借助Matplotib编排、显示图像

​ 这里使用plt.imshow()的方法来显示图像,

  • 该方法忽略了原图像的尺寸,其大小可以通过plt.figure(figsize=(width, height))手动设置

  • 对于强制缩放的图像可以使用interpolation = 'bicubic'参数调整插值的方法以确保图像清晰

  • 对于彩色图像,由于opencv的读取是按照BGR的顺序读入并存放数据,但matplotlib则以RGB的顺序显示,因而需要在显示时手动修改顺序,即plt.imshow(img[,,::-1])

    /image/CSDN-20200223122210169.png

  • 对于灰度图片,需要手动添加cmap=gray(0为黑色,255为白色)

  • 默认显示图片含有坐标轴标签,使用plt.xticks([])plt.yticks([])取消

1
2
3
4
5
6
7
8
import numpy as np
import cv2
from matplotlib import pyplot as plt

img = cv2.imread('image/01.jpg',1)
plt.imshow(img, cmap = 'gray', interpolation = 'bicubic')
plt.xticks([]), plt.yticks([])
plt.show()

方法二:使用opencv内置引擎

​ 使用函数 cv2.imshow() 显示图像,返回结果为一个自动调整为图像大小的窗体

  • 第一个参数是窗口的名字,多个窗口需给定不同的名字

  • 第二个参数是需要展示的图像

  • 该结果需要配合cv2.waitKey(0)cv2.destroyAllWindows()命令使窗口暂时停留

  • 在服务器端没有安装X Serve,因而图片使用cv2.imshow(img)无法直接调用图形界面显示,可以直接使用Matplotlib来返回显示结果

1
2
3
4
img = cv2.imread('image/01.png',0)
cv2.show('image',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

​ 使用cv2.imwrite()方法保存图像,其第一个参数为保存文件的路径和命名(包括后缀和格式),第二个参数为需要保存的图像

1
cv2.imwrite('image/01.png',img)

三、颜色空间的转换与通道的拆合

颜色空间,是在某些标准下用通常可接受的方式对彩色加以说明的方式,常用的颜色空间有RGB、CMYK、HSV、EG

  • RGB 颜色空间为加法混色,常用于彩色显示器上,图像包含3个通道(RGB),一个像素包含3个值,值的取值范围为[0, 255]

    /image/CSDN-20200223122255174.jpg

  • CMYK颜色空间为减法混色,常用在印刷时,其数值越加越黑,每种颜色包含4个参数( 青色Cyan,洋红色Magenta,黄色Yellow,黑色Black)

  • HSV颜色空间依据人类视觉概念,由3个要素组成(H/Hue:色调,颜色种类、S/Saturation:饱和度、V/Value:明度,颜色明亮度),一个像素有3个值,构成了一个圆锥形的空间

/image/CSDN-20200223122331232.png

  • CIE-XYZ颜色空间是人类颜色视觉的直接测定的颜色系统

​ opencv提供了 超过150中进行颜色空间转换的方法 , 使用cv2.cvtColor(input_image ,flag)函数来进行转换,其中 flag就是转换类型 ,多使用如下两种flag:

  • 对于BGR←→Gray的转换,可以使用cv2.COLOR_BGR2GRAYCOLOR_GRAY2RGB
  • 对于BGR←→HSV的转换,我们用的flag就是cv2.COLOR_BGR2HSVCOLOR_HSV2BGR

​ 官网教程额外提醒了, 不同的软件使用的值可能不同,所以当需要拿OpenCV的HSV值与其他软件的HSV值进行对比时,一定要记得归一化

​ 可以通过如下代码查看opencv所提供的全部与颜色转换相关的 flag:

1
2
3
import cv2
flags=[i for i in dir(cv2) if i.startswith('COLOR_')]
print(flags)

​ 当然,这里的转化也可以手工操作,如RGB图像灰度化的常用公式为$ Gray=R0.3+G0.59+B*0.11$

  • RGB三通道图以三维矩阵的形式存储,其shape为[width,height,channel],注意channel的顺序为B、G、R

  • 灰度单通道图以二位矩阵的形式存储,其shape为[width,height]

    可以通过img.shape参数查看图片的大小和通道数量(元组),img.size获知像素的个数,img.dtype每个像素的获知数据类型,即位深(一般为8位uint8,即2^8范围内)

1
2
3
4
5
import cv2
import numpy as np
img=cv2.imread('image/01.png')
print(img.shape)
print(img.size, img.dtype)

​ 因而,可以直接使用Numpy结合下标访问或修改一张图片的某一像素值,甚至可以通过切片得到某一区域的图像

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 访问100,100位置处的颜色
px = img[100,100]
print(px)
>> [175 175 175]
# 访问100,100位置处B通道的值
blue = img[100,100,0]
print(blue)
>> 175
# 将100,100位置处的颜色修改为白色
img[100,100]=[255,255,255]
print(img[100,100])
>> [255 255 255]

​ 如下操作是通过切片将图像上的区域复制到另一个位置上

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import cv2
import numpy as np
from matplotlib import pyplot as plt

img=cv2.imread('image/01.jpg')
plt.figure(figsize=(14,5))
plt.subplot(121), plt.imshow(img[:,:,::-1]), plt.xticks([]), plt.yticks([])

hat=img[0:150,120:230]
img[0:150,300:410]=hat
plt.subplot(122), plt.imshow(img[:,:,::-1]), plt.xticks([]), plt.yticks([])
plt.show()

/image/CSDN-20200223122608123.png

​ 有时我们需要对BGR三个通道分别进行操作,需要将其拆分成单个通道,有两种方法可以实现该目的

  • 一种是利用Numpy的索引b = img[:,:,:,0]
  • 一种是利用b,g,r = cv1.split(img)

​ 相应的,也可以使用cv2.merge([b,g,r])将三层通道合并

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import cv2
import numpy as np
from matplotlib import pyplot as plt
fig=plt.figure(figsize=(15,5),dpi=80)
img=cv2.imread('image/01.jpg')

# 方法一(0--b, 1--g, 2--r)(imshow展示b通道)
plt.subplot(131);plt.imshow(img[:,:,0], cmap = 'gray', interpolation = 'bicubic')
plt.xticks([]), plt.yticks([])

# 方法二(展示g,r通道)
b,g,r=cv2.split(img)
plt.subplot(132);plt.imshow(g, cmap = 'gray', interpolation = 'bicubic')
plt.xticks([]), plt.yticks([])
plt.subplot(133);plt.imshow(r, cmap = 'gray', interpolation = 'bicubic')
plt.xticks([]), plt.yticks([])
plt.show()

/image/CSDN-20200223122635217.png

提示:cv2.split() 是一个比较耗时的操作,若非必要尽可能使用Numpy 索引完成对图像的操作!

2020年2月23日 本性之初