本文代码全部可运行,笔者运行环境:python3.7+pycharm+opencv4.6。此文是学习记录,记录opencv的入门知识,对各知识点并不做深入探究。文章的目的是让阅读者在极短的时间达到入门水平。在学习过程中,我们应养成 查询opencv官方文档的好习惯。
OpenCV是一个(开源)发行的跨平台计算机视觉库,可以运行在Linux、Windows和Mac OS操作系统上。它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。
目录
8.3. 设置cv2.SimpleBlobDeterctor参数
1. 图像的读取、显示与写入
图像的读取、显示与写入分别对应三个函数,cv2. imread()
、cv2.imshow()
、cv2.imwrite()
。
1.1. 读取图像
语法:cv2.imread(filename[, flags])--->image
参数:
filename---文件路径(相对路径和绝对路径),路径中不要带有中文。
flags---可选标志,用于指定读取图像的样式,常见的有cv2.IMREAD_UNCHANGED(-1)
、cv2.IMREAD_GRAYSCALE(0)
、cv2.IMREAD_COLOR(1)
。默认为1。
注意:opencv读取彩色图像的格式是BGR,而大多数视觉库使用的是RGB,因此当将 OpenCV 与其他工具包一起使用时,当从一个库切换到另一个库时,不要忘记交换蓝色和红色通道。
1.2. 显示图像
语法:cv2.imshow(window_name, image)--->None
参数:
window_name---显示图像的窗口的名字。
image---显示图像的变量名。
注意:该函数一般和cv2.waitKey()
、cv2.destroyAllWindows()
、cv2.destroyWindow()
一起使用。cv2.waitKey()
函数是键盘绑定函数,等待键击任意键或指定键继续程序。cv2.destroyAllWindows()
用于销毁全部窗口(从内存中清除)、cv2.destroyWindow()
销毁指定窗口(从内存中清除)。
# 读取、显示图像
import cv2
# 查看opencv版本
print(cv2.getVersionString())
# 读取图像
image_unchanged = cv2.imread("image\\cat.jpg", cv2.IMREAD_UNCHANGED)
image_grayscale = cv2.imread("image\\cat.jpg", cv2.IMREAD_GRAYSCALE)
image_color = cv2.imread("image\\cat.jpg", cv2.IMREAD_COLOR)
# 显示图像
cv2.imshow('unchanged', image_unchanged)
cv2.imshow('grayscale', image_grayscale)
cv2.imshow('color', image_color)
# 永远暂停程序直到键击任意键
cv2.waitKey(0)
# 销毁所有窗口
cv2.destroyAllWindows()
运行结果:
1.3. 写入图像
语法:cv2.imwrite(filename, image[, params])
参数:
filename---文件名,它必须包含文件的扩展名(如,.jpg
、.png
)
image---要保存的图像变量名。
# 写入图像
import cv2
image_grayscale = cv2.imread("image\\cat.jpg", cv2.IMREAD_GRAYSCALE)
cv2.imshow('grayscale', image_grayscale)
cv2.imwrite("image\\cat_grayscale.jpg", image_grayscale)
cv2.waitKey(0)
cv2.destroyAllWindows()
运行结果如下:
2. 图像的色彩空间
常用的图像色彩空间有RGB、Lab、YCrCb、HSV等模式,
RGB模式:通过对红(R)、绿(G)、蓝(B)三个颜色通道的变化以及它们相互之间的叠加来得到各种颜色。依赖于光线。R、G、B的取值范围:[0, 255]。容易理解,但连续变换时不直观。
详见:RGB_百度百科
Lab模式:它是一种设备无关的颜色模型,也是一种基于生理特征的颜色模型。它由亮度(L)、颜色(a:绿色到洋红色;b:蓝色到黄色)组成。
详见:Lab颜色模型_百度百科
YCrCb模式:它派生自RGB颜色模式,主要应用在优化彩色视频信号的传输,使其向后相容老式黑白电视。Y:伽马校正后从RGB获得的亮度或亮度分量;Cr:反映了RGB输入信号红色部分与RGB信号亮度值之间的差异;Cb:反映的是RGB输入信号蓝色部分与RGB信号亮度值之间的差异。
HSV模式:它是H、S、V三维颜色空间中的一个可见光子集。是为了数字化图像提出来的,不能很好的表示人眼解释图像的过程。H:色相;S:饱和度;V:明度。取值范围,H---[0, 179],S---[0, 255],V---[0, 255]。
详见:HSV颜色模型_百度百科
灰度图:图像是有不同灰度的像素组成的,每个像素都是在[0, 255]取值。根据人眼敏感度,把RGB图片转换为灰度图,不是简单把RGB每个通道取平均值而是:Y = 0.299*R + 0.587*G + 0.114*B
注意:必须要指出的是图像就是一个数组,因此可以使用image.shape
查询形状,其输出结果为 (pixel_height, pixel_width, 3)
。pixel_height
、pixel_width
代表图像的像素尺寸,3
代表每个像素的颜色是由一个三维数组确定的(opencv中是BGR模式的数组)。
如何查看某像素的RGB、Lab、YCrCb、HSV值?
由于在读取图像时直接读取的是RGB值,因此可通过cv2.imshow()
函数直接查看。
利用cv2.cvtColor(np.uint8([[[image[x, y]]]]), cv2.COLOR_BGR2Lab)[0][0]
查看位置(x, y)处的Lab值。YCrCb、HSV与Lab类似。
注意:图像中某位置的图像色彩空间转换为其他时,必须要使其BGR "空间值"(由三个通道组成)三维化。
练习:如何通过鼠标的移动实时获取指定图片的不同色彩空间值?
import cv2
import glob
import numpy as np
# 定义鼠标回调的‘动作’函数
def showPixelValue(event, x, y, flags, param):
# 定义全局变量
global img, combinedResult, placeholder
# 判断鼠标是否移动
if event == cv2.EVENT_MOUSEMOVE:
# 获取鼠标坐标的RGB值
bgr = img[y, x]
# 转换色彩空间值
ycb = cv2.cvtColor(np.uint8([[bgr]]), cv2.COLOR_BGR2YCrCb)[0][0]
lab = cv2.cvtColor(np.uint8([[bgr]]), cv2.COLOR_BGR2Lab)[0][0]
hsv = cv2.cvtColor(np.uint8([[bgr]]), cv2.COLOR_BGR2HSV)[0][0]
# 创建一个与载入图片高度相同的黑色图块,作为结果区域
placeholder = np.zeros((img.shape[0], 400, 3), dtype=np.uint8)
# 在结果区域内显示鼠标位置不同色彩空间的值
cv2.putText(placeholder, "BGR {}".format(bgr), (20, 70), cv2.FONT_HERSHEY_COMPLEX, .9, (255, 255, 255), 1,
cv2.LINE_AA)
cv2.putText(placeholder, "HSV {}".format(hsv), (20, 140), cv2.FONT_HERSHEY_COMPLEX, .9, (255, 255, 255), 1,
cv2.LINE_AA)
cv2.putText(placeholder, "YCrCb {}".format(ycb), (20, 210), cv2.FONT_HERSHEY_COMPLEX, .9, (255, 255, 255), 1,
cv2.LINE_AA)
cv2.putText(placeholder, "LAB {}".format(lab), (20, 280), cv2.FONT_HERSHEY_COMPLEX, .9, (255, 255, 255), 1,
cv2.LINE_AA)
# 合并加载的图片和结果区域
combinedResult = np.hstack([img, placeholder])
# 显示合并后的图像
cv2.imshow('PRESS P for Previous, N for Next Image', combinedResult)
if __name__ == '__main__':
# 读取指定的图片,并转换尺寸
files = glob.glob('image/rub*.jpg')
files.sort()
img = cv2.imread(files[0])
img = cv2.resize(img, (400, 400))
# 显示转换尺寸后的图像(在‘PRESS...’显示框加载)
cv2.imshow('PRESS P for Previous, N for Next Image', img)
# 创建一个无加载图像的显示框,并覆盖了原‘PRESS...’显示框
cv2.namedWindow('PRESS P for Previous, N for Next Image')
# 创建一个鼠标回调,加载回调‘动作’函数,并且该动作在‘PRESS...’显示框内实现
cv2.setMouseCallback('PRESS P for Previous, N for Next Image', showPixelValue)
i = 0
while 1:
k = cv2.waitKey(1) & 0xFF
# 键击‘n’切换到下一张图片
if k == ord('n'):
i += 1
img = cv2.imread(files[i % len(files)])
img = cv2.resize(img, (400, 400))
cv2.imshow('PRESS P for Previous, N for Next Image', img)
# 键击‘p’切换到上一张图片
elif k == ord('p'):
i -= 1
img = cv2.imread(files[i % len(files)])
img = cv2.resize(img, (400, 400))
cv2.imshow('PRESS P for Previous, N for Next Image', img)
# 键击‘Esc’退出程序
elif k == 27:
cv2.destroyAllWindows()
break
运行结果如下(静态展示):
3. 图像编辑
图像编辑主要包括调整图像大小、裁剪图像、图像的旋转和移动、翻转,透视变换。
3.1. 调整大小
在opencv中使用image.shape
获得图像大小,image.shape
获得结果是(heigh, width, channels)
即高度、宽度、通道数。在opencv中使用resize()函数调整图像的大小。
语法:cv2.resize(src, dsize[, dst[, fx[, fy[, interpolation]]]])--->dst
参数:
src---源图像。
dsize---可为tuple参数或None。目标图像的大小,即新的图像宽高。需要注意的是,dsize=(width, height)中第 一个参数是图像宽度第二个是高度,与shape=(height, width, channels)的相对位置刚好相反。
dst---目标图像,在python中无任何意义,一般不传参或设成None。
fx---沿水平轴的比例因子。fy---沿垂直轴的比例因子。
interpolation---插值方式,提供了调整图像大小的不同方法。其本质是一个int数值,不过一般用opencv内置的参 数名称以提高可读性。默认为cv2.INTER_LINEAR
。其他还有cv2.INTER_AREA
、cv2.INTER_CUBIC
、cv2.INTER_NEAREST
。
注意:当目标图像与源图像的宽高比不一致,代表经缩放后图像失真。关于插值参数,①要缩小图片选用cv2.INTER_AREA
;②放大图片选用cv2.INTER_CUBIC
(速度慢)或cv2.INTER_LINEAR
(速度快,效果还行)。
# 调整图像的大小
import cv2
cat = cv2.imread('image\\cat.jpg')
# 指定目标图像的宽高
# 图像不失真
cat_down_0 = cv2.resize(cat, (150, 150))
cat_up_0 = cv2.resize(cat, (500, 500))
cv2.imshow('cat_down-No distortion', cat_down_0)
cv2.imshow('cat_up-No distortion', cat_up_0)
# 图像失真
cat_distortion = cv2.resize(cat, (200, 300))
cv2.imshow('cat distortion', cat_distortion)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 指定图像的比例因子(需要指出的是dsize必须要传参,None)
# 图像不失真
cat_down_1 = cv2.resize(cat, None, fx=0.75, fy=0.75)
cat_up_1 = cv2.resize(cat, None, fx=1.2, fy=1.2)
cv2.imshow('cat_down-No distortion1', cat_down_1)
cv2.imshow('cat_up-No distortion1', cat_up_1)
# 图像失真
cat_distortion1 = cv2.resize(cat, None, fx=0.75, fy=1.2)
cv2.imshow('cat distortion1', cat_distortion1)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 指定图像缩放方法
cat_scale0 = cv2.resize(cat, (150, 150), interpolation=cv2.INTER_AREA)
cat_scale1 = cv2.resize(cat, (450, 450), interpolation=cv2.INTER_CUBIC)
cat_scale2 = cv2.resize(cat, (450, 450), interpolation=cv2.INTER_LINEAR)
cat_scale3 = cv2.resize(cat, (150, 150), interpolation=cv2.INTER_NEAREST)
cv2.imshow('cat_scale0', cat_scale0)
cv2.imshow('cat_scale1', cat_scale1)
cv2.imshow('cat_scale2', cat_scale2)
cv2.imshow('cat_scale3', cat_scale3)
cv2.waitKey(0)
cv2.destroyAllWindows()
运行结果(部分)如下:
3.2. 图像裁剪
裁剪图像是为了从图像中删除不需要的对象或区域;也就是删除其他,保留想要的图像区域。
opencv中的图像裁剪是利用numpy数组切片的方法来实现的。首先,我们要知道图像就是一个数组,其由高、宽、通道数三个维度组成。仅对图像进行裁剪,就是意味着对宽和高两个维度进行切片操作。具体如下:
语法:image[start_row : end_row, start_col : end_col]--->dst
参数:start_row 、end_row---图像的开始与结束的行坐标。
start_col :、end_col---图像的开始与结束的列坐标。
注意:图像可视为坐标系,坐标原点为图像的左上角顶点,裁剪区域即是四条直线的围合区域。
# 图像裁剪
import cv2
cat = cv2.imread('image\\cat.jpg')
print(cat.shape)
# 裁剪图像
cropped_cat = cat[25:190, 50:300]
cv2.imshow('original', cat)
cv2.imshow('cropped', cropped_cat)
cv2.waitKey(0)
cv2.destroyAllWindows()
运行结果如下:
3.3. 旋转和平移
图像的旋转和平移是图像编辑中最基本的操作之一。旋转和平移都属于同一种图像编辑类型&