opencv-python学习笔记【更新中】

opencv-python

基于明日科技的《Python OpenCV从入门到实践》的学习笔记

import cv2

1 图像处理的基本操作

(1)读取图像

image = cv2.imread(filename, flags)

  • filename为待读取图片的路径(相对路径或绝对路径均可,不允许有中文)
  • flags为读取图像颜色类型的标记。默认为1,表示读取彩色图像;如为0,表示读取灰度图像

(2)显示图像

cv2.imshow(winname, mat)

  • winname:显示图像的窗口名称,不能是中文,否则有乱码
  • mat:要显示的图像

retval = cv2.waitKey(delay)

  • retval:被按下的按键的ASCII码;如果没有按键被按下,waitKey()方法返回-1
  • delay:等待用户按下按键的时间,单位为ms;当为负数、0或者空时,表示无限等待

cv2.destoryAllWindows()

  • 销毁所有正在显示图像的窗口
import cv2

image = cv2.imread("1.1.jpg")
cv2.imshow("flower", image)
cv2.waitKey()				# 按下任意键后放行
cv2.destoryAllWindows()  

(3)保存图像

cv2.imwrite(filename, img)

(4)获取图像属性

shape:

  • 如果是彩色图像,则得到(图像像素行数,图像像素列数,通道数)数组,即(H,W,C)
  • 如果是灰度图像,则得到(图像像素行数,图像像素列数)数组,即(H,W)
    size:
  • 获取图像包含的像素个数,值为“像素列数* 像素行数 * 通道数”
    dtype:
  • 获得图像的数据类型

2 图像数字化基础

计算机把像素值处理为256个灰度级别,用[0, 255]中的数值表示,0表示纯黑色,255表示纯白色

(1)像素点

px = image[像素点所在的行号, 像素点所在的列号]

  • 获取某个位置的像素点
  • px(B,G,R)像素值
  • 获取B通道的值:blue = image[291, 218, 0]
  • 获取G通道的值:green = image[291, 218, 1]
  • 获取R通道的值:red = image[291, 218, 2]
  • 修改某个像素点的值:image[291, 218] = [255, 255, 255]
  • [255, 255, 255]为纯白
  • [0, 0, 0]为纯黑

(2)色彩空间

BGR色彩空间

GRAY色彩空间

  • 为[0, 255]个灰度级别的单色图像
  • 0表示纯黑色
  • 255表示纯白色

HSV色彩空间

  • H 色调:指光的颜色,赤橙黄绿青蓝紫,在[0, 180]内取值;红色为0,黄色为30,绿色为60,蓝色为120
  • S 饱和度:指色彩的深浅,在[0, 255]内取值;为0时,表示灰度图
  • V 亮度:指光的明暗,在[0, 255]内取值;亮度越大,图像越亮;为0时,图像为纯黑色

BGRA色彩空间

  • A alpha通道:值图像的透明度;0表示透明,255表示不透明
  • 从BGR转为BGRA时,A的值均为255
  • 针对不同的alpha值,使用cv2.imshow()显示的结果差异不大,需使用cv2.imwrite()保存为.png后,才能显示最终结果,因为PNG图像是一种典型的四通道格式。

色彩空间之间的转换

dst = cv2.cvtColor(src, code)

  • dst:转换后的图像
  • src:转换前的图像
  • code:色彩空间的转换码:
    • cv2.COLOR_BGR2RGB, cv2.COLOR_RGB2BGR
    • cv2.COLOR_BGR2GRAY, cv2.COLOR_RGB2GRAY
    • cv2.COLOR_BGR2HSV, cv2.COLOR_RGB2HSV
    • cv2.COLOR_BGR2BGRA

(3)通道

拆分通道

b, g, r = cv2.split(bgr_image)
h, s, v = cv2.split(hsv_image)

  • 如果直接用cv2.imshow('h', h)输出H通道的拆分结果的话,输出的结果为[H, H, H]

合并通道

bgr = cv2.merge([b, g, r])
rgb = cv2.merge([r, g, b])
hsv = cv2.merge([h, s, v])

(4)NumPy模块操作像素

import numpy as np

数据类型

常见的numpy数据类型:
np.bool_, np.int_, np.float_, np.complex_, np.int8, np.int16, np.uint8

创建数组

常规创建

np.array(object, dtype, copy, order, subok, ndmin)

  • object:任何具有数组接口方法的对象
  • copy:可选参数,布尔值,默认为True,表示object对象被复制;否则,只有当__array__返回副本,object参数为嵌套序列,或者需要副本满足数据类型和顺序要求时,才会生成副本
  • order:元素在内存中的出现顺序,值为K、A、C、F。如果object参数不是数组,则新创建的数组将按行排列(C),如果值为F,则按列排列;如果object参数是一个数组,则以下成立:C(按行)、F(按列)、A(原顺序)、K(元素在内存中的出现顺序)
  • subok:布尔值,如果为True,则传递子类;否则,返回的数组将强制为基类数组(默认为False)
  • ndmin:指定生成数组的最小维数
import numpy as np

list = [1, 2, 3]
n1 = np.array(list, dtype=np.float_)
n1 = np.array(list, dtype=float)   # 同上一行

# 创建三维数组
nd2 = np.array(list, ndmin=3)  # 创建了[[[1, 2, 3]]]
创建未初始化的数组

np.empty(size, dtype)

  • 例如:np.empty([2, 3])
创建全0数组

np.zeros(size, dtype)

创建全1数组

np.ones(size, dtype)

创建随机数组

np.random.randint(low, high, size)

  • low:随机数最小取值范围
  • high:可选参数,随机数最大取值范围;如果high为空,则取值范围为(0, low); 否则,为(low, high)
  • size:可选参数,数组维度

操作数组

import numpy as np

n1 = np.array([1, 2])
n2 = np.array([3, 4])

print(n1 + n2)  # 加法
print(n1 - n2)	# 减法
print(n1 * n2)	# 乘法
print(n1 / n2)	# 除法
print(n1 ** n2)	# 幂运算

print(n1 >= n2)	# 比较运算,输出同尺寸的bool数组,==, >, <, <=

# 复制
n2 = np.array(n1, copy=True)  # 复制得到副本
n2 = n1.copy()	# 复制得到副本

索引和切片

索引
  • arr[idx]
切片式索引
  • arr[start: stop: step]
  • start:索引起始位置;若省略,表示从0开始
  • stop:索引终止位置,不包括该位置,即arr[0:2],表示[arr[0], arr[1]];若省略,表示到末尾
  • step:步长
  • start、stop、step均可以为负值:
    • arr[::-1],表示arr的逆序
    • arr[:-3:-1],表示[arr[-1], arr[-2]]
二维数组索引

二维数组arr

  • 索引:arr[0, 0],表示第0行第0列处的元素
  • 切片:arr[:2, 1:]

创建图像

  • img = np.zeros((100, 200), dtype=np.uint8) 创建全黑图片
  • img = np.ones((100, 200), dtype=np.uint8) * 255 创建全白图片

拼接

  • arr = np.hstack((arr1, arr2)) 水平拼接
  • arr = np.vstack((arr1, arr2)) 垂直拼接

3 绘制图形

(1)线段

img = cv2.line(img, pt1, pt2, color, thickness)

  • img:画布
  • pt1:线段的起点坐标,(x, y)表示(横坐标,纵坐标),而表达像素位置时是(y, x)
  • pt2:线段的终点坐标
  • color:线段的颜色,为BGR元组,例如红色:color=(0, 0, 255)
  • thickness:线段的宽度

(2)矩形框

img = cv2.rectangle(img, pt1, pt2, color, thickness)

  • img:画布
  • pt1:矩形的起点坐标
  • pt2:矩形的终点坐标
  • color:矩形的线条颜色,为BGR元组,例如红色:color=(0, 0, 255)
  • thickness:矩形的线条宽度,如果为-1,则表示实心矩形

(3)圆形

img = cv2.circle(img, center, radius, color, thickness)

  • img:画布
  • center:圆心坐标
  • radius:半径,当半径为0时,绘制一个点
  • color:线条颜色,为BGR元组,例如红色:color=(0, 0, 255)
  • thickness:线条宽度,如果为-1,则表示实心矩形
    生成随机的颜色,可用以下代码:
    color = np.random.randint(255, size=(3,)).tolist()

(4)多边形

img = cv2.polylines(img, [pts], isClosed, color, thickness)

  • img:画布
  • pts:列表,指各顶点的坐标值,必须是Numpy类型
  • isClosed:布尔值,表示多边形是否封闭
  • color:线条颜色,为BGR元组,例如红色:color=(0, 0, 255)
  • thickness:线条宽度,如果为-1,则表示实心矩形
    例如,绘制等腰梯形:
import cv2  
import numpy as np  
  
canvas = np.zeros((300, 300, 3), np.uint8)  
pts = np.array([[100, 50], [200, 50], [250, 250], [50, 250]], np.int32)  
canvas = cv2.polylines(canvas, [pts], True, (0, 0, 255), 5)  
  
cv2.imshow("polylines", canvas)  
cv2.waitKey()  
cv2.destroyAllWindows()

(5)文字

img = cv2.putText(img, text, org, fontFace, fontScale, color, thickness, lineType, bottomLeftOrigin)

  • img:画布
  • text:文字内容,不能有中文
  • org:文字在画布中的左下角坐标
  • fontFace:文字样式,即cv2.FONT_******, 其中,cv2.FONT_ITALIC表示斜体,可以与其他样式一起使用,用“+”联合
  • fontScale:字体大小
  • color:线条颜色
  • thickness:线条宽度
  • lineType:线型(指线的产生算法,4或8,默认为8)
  • bottomLeftOrigin:布尔值,绘制文字时的方向;默认为False

4 阈值

(1)阈值处理函数

retval, dst = cv2.threshold(src, thresh, maxval, type)

  • src:被处理的图像
  • thresh:阈值,在125~150范围内取值的效果最好
  • maxval:阈值处理采用的最大值
  • type:阈值处理类型:
    • cv2.THRESH_BINARY:二值化阈值处理:将大于阈值的像素值变为最大值(一般为设为255),小于或等于阈值的像素值变为0
    • cv2.THRESH_BINARY_INV:反二值化阈值处理:将大于阈值的像素值变为0,小于或等于阈值的像素值变为最大值
    • cv2.THRESH_TOZERO:低于阈值零处理:将低于或等于阈值的像素值变为0,其他像素值不变;彩色图像会让深色区域颜色更深,甚至变黑
    • cv2.THRESH_TOZERO_INV:超出阈值零处理:将大于阈值的像素值变为0,其他像素值不变;彩色图像会让浅色区域彻底变黑
    • cv2.THRESH_TRUNC:截断阈值处理:将大于阈值的像素值变为和阈值一样的值,其他像素值不变;彩色图像会降低亮度,且浅色区域颜色更浅
  • retval:处理时所采用的阈值
  • dst:经过阈值处理后的图像

(2)自适应阈值处理

自适应阈值处理能够保留图像中更多的细节信息,更明显的保留图像主体的轮廓
dst = cv2.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C)

  • src:被处理的图像,必须是灰度图
  • maxValue:阈值处理采用的最大值
  • adaptiveMethod:自适应阈值的计算方法:
    • cv2.ADAPTIVE_THRESH_MEAN_C:对一个正方形区域内的所有像素平均加权
    • cv2.ADAPTIVE_THRESH_GAUSSIAN_C:根据高斯函数按照像素与中心点的距离对一个正方形区域内的所有像素进行加权计算
  • thresholdType:阈值处理类型,只能是下面的两者之一
    • cv2.THRESH_BINARY
    • cv2.THRESH_BINARY_INV
  • block_size:一个正方形区域的大小
  • C:常量,阈值等于均值或者加权值减去这个常量
  • dst:经过阈值处理后的图像

(3)Otsu方法

人为指定阈值往往不能找到最合适的阈值,可以使用Otsu方法,其会遍历所有可能的阈值,从中找到最合适的阈值。使用时,仍基于(1)中的阈值处理函数,需在参数type上多加一个cv2.THRESH_OTSU;例如:
retval, dst = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

5 几何变换

(1)缩放

dst = cv2.resize(src, dsize, fx, fy, interpolation)

  • src:原始图像
  • dsize:输出图像的大小,格式为(宽,高),单位为像素
  • fx:可选参数,水平方向的缩放比例
  • fy:可选参数,竖直方向的缩放比例
  • interpolation:可选参数,缩放的插值方式,建议使用默认值
  • dst:缩放后的图像

dsize实现缩放

import cv2  
  
img = cv2.imread('demo.png')  
dst1 = cv2.resize(img, (100, 100))  
dst2 = cv2.resize(img, (400, 400))  
  
cv2.imshow('img', img)  
cv2.imshow('dst1', dst1)  
cv2.imshow('dst2', dst2)  
  
cv2.waitKey()  
cv2.destroyAllWindows()

fx,fy实现缩放

使用fx, fy控制缩放时,参数dsize必须设置为None,否则fx,fy会失效
fx,fy:小于1表示缩小,大于1表示放大。计算公式为:
新图像宽度 = round(fx * 原图像宽度)
新图像高度 = round(fy * 原图像高度)

import cv2  
  
img = cv2.imread('demo.png')  
dst1 = cv2.resize(img, dsize=None, fx=1/3, fy=1/3)  
dst2 = cv2.resize(img, dsize=None, fx=2, fy=2)  
cv2.imshow('img', img)  
cv2.imshow('dst1', dst1)  
cv2.imshow('dst2', dst2)  
cv2.waitKey()  
cv2.destroyAllWindows()

(2)翻转

dst = cv2.flip(src, flipCode)

  • src:原始图像
  • flipCode:翻转类型:
    • 0:沿着X轴翻转
    • 正数:沿着Y轴翻转
    • 负数:同时沿着X轴、Y轴翻转
  • dst:翻转之后的图像

(3)仿射变换

仿射变换是仅在二维平面中发生的几何变换;变换后,原来的直线仍然是直线,原来的平行线仍然保持平行。
dst = cv2.warpAffine(src, M, dsize, flags, borderMode, borderValue)

  • src:原始图像
  • M:仿射矩阵,一个2行3列矩阵(np矩阵,值为float32类型),根据此矩阵的值变换原图中的像素未知
    • M格式为:[[a, b, c], [d, e, f]]
    • 新x = 原x * a + 原y * b + c
    • 新y = 原x * d + 原y * e + f
  • dsize:输出图像的尺寸
  • flags:可选参数,插值方式,建议使用默认值
  • borderMode:可选参数,边界类型,建议使用默认值
  • borderValue:可选参数,边界值,默认为0,建议使用默认值
  • dst:变换后的图像

平移

同时沿着水平、或垂直方向移动
M = [[1, 0, 水平移动的距离], [0, 1, 垂直移动的距离]],结果为:
新x = 原x * 1 + 原y * 0 + 水平移动的距离 = 原x + 水平移动的距离
新y = 原x * 0 + 原y * 1 + 垂直移动的距离 = 原y + 垂直移动的距离
若水平移动的距离为正,则图像向右移动;垂直移动的距离为正,则图像向下移动

import cv2  
import numpy as np  

img = cv2.imread('demo.png')  
dsize = img.shape[:-1]  

M = np.float32([[1, 0, 50],  
			   [0, 1, 100]])  
dst = cv2.warpAffine(img, M, dsize)  
cv2.imshow('img', img)  
cv2.imshow('dst', dst)  
cv2.waitKey()  
cv2.destroyAllWindows()

旋转

M = cv2.getRotationMatrix2D(center, angle, scale)

  • center:旋转的中心点坐标
  • angle:旋转的角度(不是弧度);正数表示逆时针旋转
  • scale:缩放比例
import cv2  

img = cv2.imread('demo.png')  
center = (img.shape[0]/2 , img.shape[1] / 2)  
M = cv2.getRotationMatrix2D(center, 30, 0.8)  
dst = cv2.warpAffine(img, M, img.shape[:-1])  
cv2.imshow('img', img)  
cv2.imshow('dst', dst)  
cv2.waitKey()  
cv2.destroyAllWindows()

倾斜

倾斜,是给定原图上一个矩形的三个顶点:左上点A、右上点B、左下点C,再给定倾斜后A、B、C三点的新坐标,实现倾斜效果。
倾斜后,原A、B、C所在的矩形,变为平行四边形,而且原直线依然是直线,原平行线依然保持平行。
M = cv2.getAffineTransform(src, dst)

  • src:原图A、B、C三个点坐标,浮点数列表,形如:[[0, 1], [1, 0], [1, 1]]
  • dst:倾斜后A、B、C三点的新坐标

(4)透视

透视是让图像在三维空间中变形。从不同角度观察物体,离观察点越近的边宽度与原宽度越接近,离观察点越远的边,就会越缩小。
给定原图上一个矩形的四个顶点:左上点A、右上点B、左下点C、右下点D,再给定透视后的A、B、C、D的新坐标,实现透视效果。
dst = cv2.warpPerspective(src, M, dsize, flags, borderMode, borderValue)

  • src:原始图像
  • M:透视矩阵,三行三列,用M = cv2.getPerspectiveTransform(src_points, dst_points)计算
    • src_points:原图像上一个矩形的四个顶点坐标,必须是numpy类型
    • dst_points:四个顶点的新坐标
  • dsize:输出图像的尺寸
  • flags:可选参数,插值方式,建议使用默认值
  • borderMode:可选参数,边界类型,建议使用默认值
  • borderValue:可选参数,边界值,默认为0,建议使用默认值
  • dst:变换后的图像
import cv2  
import numpy as np  

img = cv2.imread('demo.png')  
rows = len(img)  
cols = len(img[0])  
p1 = np.zeros((4, 2), np.float32)  
p1[0] = [0, 0]  
p1[1] = [cols - 1, 0]  
p1[2] = [0, rows - 1]  
p1[3] = [cols - 1, rows - 1]  
p2 = np.zeros((4, 2), np.float32)  
p2[0] = [90, 0]  
p2[1] = [cols - 90, 0]  
p2[2] = [0, rows - 1]  
p2[3] = [cols - 1, rows - 1]  
M = cv2.getPerspectiveTransform(p1, p2)  
print(M) # 3行3列  

dst = cv2.warpPerspective(img, M, (cols, rows))  
cv2.imshow('img', img)  
cv2.imshow('dst', dst)  
cv2.waitKey()  
cv2.destroyAllWindows()

6 图像运算

(1)掩模

掩模,也叫掩码(mask),在程序用二值图像来表示:0值(纯黑)区域表示被遮盖的部分,255值(纯白)区域表示暴露的部分。
通常使用Numpy库提供的方法来创建掩模图像。

	mask = np.zeros((150, 150, 3), np.uint8)  
	mask[50:100, 20:80, :] = 255

(2)图像的加法运算

dst = cv2.add(src1, src2, mask, dtype)

  • src1:第一幅图像
  • src2:第二幅图像
  • mask:可选参数,掩模,建议使用默认值
  • dtype:可选参数,图像深度,建议使用默认值
  • dst:相加之后的结果图像,如相加后值大于255,则取255
  • 注意:如果直接用+将两幅图相加,即src1 + src2,相加后值大于255的,会进行取模运算(除以255的余数),像素值会变得更小;图像会由浅色变成深色。而add()方法的计算结果超过255,就取值255,图像中很多浅色像素会变成纯白色。
	import cv2  

	img = cv2.imread('beach.jpg')  
	sum1 = img + img  
	sum2 = cv2.add(img, img)

利用掩模遮盖相加结果:(将img1img2相加后,再通过掩模遮盖结果,将掩模为1的区域通过,为0的区域遮挡)

import cv2  
import numpy as np  

img1 = np.zeros((150, 150, 3), np.uint8)  
img1[:, :, 0] = 255  
img2 = np.zeros((150, 150, 3), np.uint8)  
img2[:, :, 2] = 255  

img = cv2.add(img1, img2)  
cv2.imshow('no mask', img)  

m = np.zeros((150, 150, 1), np.uint8)     # 掩模使用1通道
m[50:100, 50:100, :] = 255  
cv2.imshow('m', m)  

img = cv2.add(img1, img2, mask=m)  
cv2.imshow('use mask', img)  

cv2.waitKey()  
cv2.destroyAllWindows()

(3)图像的位运算

按位与

dst = cv2.bitwise_and(src1, src2, mask)

  • src1:第一幅图像
  • src2:第二幅图像
  • mask:可选参数,掩模
  • dst:与运算之后的结果图像
    与运算有两个特点:
  • 如果某个像素与纯白色像素做与运算,结果仍然是该像素的原值
  • 如果某个像素与纯黑色像素做与运算,结果是纯黑色像素

按位或

dst = cv2.bitwise_or(src1, src2, mask)

  • src1:第一幅图像
  • src2:第二幅图像
  • mask:可选参数,掩模
  • dst:或运算之后的结果图像
    或运算有两个特点:
  • 如果某个像素与纯白色像素做或运算,结果为纯白像素
  • 如果某个像素与纯黑色像素做或运算,结果是原像素值
    如果原图与掩模做或运算,原图仅会保留掩模中黑色区域所覆盖的内容,其他区域全部变为白色

按位取反

dst = cv2.bitwise_not(src, mask)

  • src:参与运算的图像
  • mask:可选参数,掩模
  • dst:取反运算之后的结果图像

按位异或

dst = cv2.bitwise_or(src1, src2, mask)

  • src1:第一幅图像
  • src2:第二幅图像
  • mask:可选参数,掩模
  • dst:异或运算之后的结果图像
    异或运算的两个特点:
  • 如果将原图像与掩模进行异或运算,则掩模白色区域所覆盖的内容呈现取反效果,黑色区域覆盖的内容保持不变
  • 执行一次异或运算得到一个结果,在执行第二次异或运算,则会还原成最初的值;利用这个特点,可以实现图像内容的加密、解密
import cv2  
import numpy as np  


def encode(img, img_key):  
	result = cv2.bitwise_xor(img, img_key)  
	return result  


flower = cv2.imread('amygdalus triloba.png')  
img_key = np.random.randint(0, 256, flower.shape, np.uint8)  
cv2.imshow('flower', flower)  
cv2.imshow('img_key', img_key)  
result = encode(flower, img_key)  
cv2.imshow('encode', result)  
result2 = encode(result, img_key)  
cv2.imshow('decode', result2)  
cv2.waitKey()  
cv2.destroyAllWindows()

(4)合并图像

加权和

目的:将两幅图像融合到一起,类似摄影上的多次曝光。
加权和,按照不同的权重取两幅图像的像素之和,最后组合成新图像。加权和不会像纯加法运算那样丢失信息,而是尽可能保留原图像信息的基础上把两幅图像融合到一起。
dst = cv2.addWeighted(src1, alpha, src2, beta, gamma)

  • src1:第一幅图像
  • alpha:第一幅图像的权重
  • src2:第二幅图像
  • beta:第二幅图像的权重
  • gamma:在结果上添加的标量,相当于偏置量;该值越大,结果图像越亮,相反则越暗,可以是负数
  • dst:叠加之后的结果

覆盖

目的:每幅图像提供一部分内容,将这些内容拼接成一幅图像
覆盖,是直接把前景图像显示在背景图像中,前景图像会遮挡注背景图像。
操作:从A图像中取像素值,直接赋值给B图像的像素

import cv2  

beach = cv2.imread('beach.jpg')  
cat = cv2.imread('cat.jpg')  
cat = cat[75:400, 120:260, :]  
cat = cv2.resize(cat, (70, 160))  
cv2.imshow('cat', cat)  
cv2.imshow('beach', beach)  
beach[100:100 + cat.shape[0], 260:260 + cat.shape[1], :] = cat  
cv2.imshow('beach2', beach)  
cv2.waitKey()  
cv2.destroyAllWindows()

注意:
如前景图像是4通道(含alpha通道)图像,则不能按上述操作直接替换。因为前景中有透明像素,理应不能挡住背景,因此赋值时应排除所有透明的前景图像像素

7 滤波器

滤波器用于进行图像平滑处理,或者叫图像模糊处理(去除图像内噪声、降低细节层次信息等,并且尽量保留原图像信息)

(1)均值滤波器

也称为低通滤波器,将核心像素值修改为滤波核内所有像素的平均值
dst = cv2.blur(src, ksize, anchor, borderType)

  • src:被处理的图像
  • ksize:滤波核大小,格式为(高度,宽度),建议使用等高宽的奇数边长,如(3, 3), (5, 5);滤波核越大,处理后的图像越模糊
  • anchor:可选参数,滤波核的锚点,建议使用默认值
  • borderType:可选参数,边界样式,建议使用默认值
  • dst:经过滤波后的图像

(2)中值滤波

将核心像素值修改为滤波核内所有像素值的中值(滤波核内所有像素值升序排列,取中间的值)
dst = cv2.medianBlur(src, ksize)

  • src:被处理的图像
  • ksize滤波核边长,必须是大于1的奇数,如3,5,7;滤波核边长越长,处理后的图像就越模糊
  • dst:经过滤波后的图像
	dst1 = cv2.medianBlur(img, 3)

中值滤波处理的图像比均值滤波丢失更多细节

(3)高斯滤波

也称为高斯模糊、高斯平滑,是目前应用最广泛的平滑处理算法;可有效降低图片噪声、细节层次,并保留更多的图像信息,处理后的图片呈”磨砂玻璃“的滤镜效果。
高斯滤波中,给定滤波核的尺寸,会自动生成滤波核,指代对应未知像素的权重,越靠近滤波核心的像素权重越大,滤波过程是在做卷积操作。
dst = cv2.GaussianBlur(src, ksize, sigmaX, dst, sigmaY, borderType)

  • src:被处理的图像
  • ksize:滤波核大小,格式为(高度,宽度),宽高必须是奇数边长,如(3, 3), (5, 5);滤波核越大,图像越模糊
  • sigmaX:卷积核水平方向上的标准差
  • sigmaY:卷积核垂直方向上的标准差;修改sigmaXsigmaY均可改变卷积核中的权重比例。如不知道如何设置,可直接设置为0,会自动根据滤波核大小计算出合适的权重比例
  • borderType:可选参数,边界样式,建议使用默认值
  • dst:经过滤波后的图像
    与均值滤波、中值滤波相比,高斯滤波处理的图像更平滑,保留的图像信息更多,更容易辨认;但是三种滤波方式都会使边界模糊不清

(4)双边滤波

一种可有效保护边界信息的滤波操作:

  • 自动判断滤波核处于”平坦“区域,还是”边缘“区域
  • 如处于平坦区域,会进行类似高斯滤波操作
  • 如处于边缘区域,会加大”边缘“像素的权重,尽可能的让这些像素值保持不变
    dst = cv2.bilateralFilter(src, d, sigmaColor, sigmaSpace, borderType)
  • src:被处理的图像
  • d:以当前像素为中心的整个滤波区域的直径;如果d<0,则自动根据sigmaSpace参数计算得到;该值与保留的边缘信息数量成正比,与方法运行效率成反比
  • sigmaColor:参与计算的颜色范围;是像素颜色值与周围颜色值的最大差值,只有颜色值之差小于这个值时,周围的像素才会进行滤波计算;值为255时,表示所有颜色都参与计算
  • sigmaSpace:空间坐标的 σ ( s i g m a ) \sigma(sigma) σ(sigma)值,越大,参与计算的像素数量越多
  • borderType:可选参数,边界样式,建议使用默认值
  • dst:经过滤波后的图像
import cv2  

img = cv2.imread('amygdalus triloba.png')  
dst2 = cv2.bilateralFilter(img, 15, 120, 100)  
cv2.imshow('img', img)  
cv2.imshow('bilateral', dst2)  
cv2.waitKey()  
cv2.destroyAllWindows()

8 腐蚀与膨胀

(1)腐蚀

可让图像沿着自己的边界向内收缩;给定核,核会在图像的边缘移动,移动时核会将图像边缘那些与核重合但又没有越过核心的像素点都抹除,类似于削土豆的过程;图像经过腐蚀后,可抹除一些外部信息
dst = cv2.erode(src, kernel, anchor, iterations, borderType, borderValue)

  • src:被处理的图像
  • kernel:腐蚀使用的核;一般核大小为3*35*59*911*11,行列数越大,计算出的效果越粗糙
  • anchor:可选参数,核的锚点位置
  • iterations:可选参数,腐蚀操作的迭代次数,默认值为1
  • borderType:可选参数,边界样式,建议使用默认值
  • borderValue:可选参数,边界值,建议使用默认值
  • dst:经过腐蚀后的图像
import cv2  
import numpy as np  
  
img = cv2.imread('cactus.jpg')  
k = np.ones((3, 3), np.uint8)  
cv2.imshow('img', img)  
dst = cv2.erode(img, k)  
cv2.imshow('erode', dst)  
cv2.waitKey()  
cv2.destroyAllWindows()

(2)膨胀

可让图像沿着自己的边界向外扩张;给定核,核会在图像的边缘移动,移动时核会向图像边缘填充新的像素;图像经过膨胀后,可放大一些外部信息;膨胀后,会将图像加工成“近视眼”效果,图像会变得模糊
dst = cv2.dilate(src, kernel, anchor, iterations, borderType, borderValue)

  • src:被处理的图像
  • kernel:膨胀使用的核
  • anchor:可选参数,核的锚点位置
  • iterations:可选参数,膨胀操作的迭代次数,默认值为1
  • borderType:可选参数,边界样式,建议使用默认值
  • borderValue:可选参数,边界值,建议使用默认值
  • dst:经过膨胀后的图像
import cv2  
import numpy as np  
  
img = cv2.imread('sunset.jpg')  
cv2.imshow('img', img)  
k = np.ones((3, 3), np.uint8)  
dst = cv2.dilate(img, k)  
cv2.imshow('dilate', dst)  
cv2.waitKey()  
cv2.destroyAllWindows()

(3)开运算

开运算,即先腐蚀后膨胀;可用来抹除图像外部的细节(或者噪声)

import cv2  
import numpy as np  
  
img = cv2.imread('nigella.png')  
cv2.imshow('img', img)  
k = np.ones((5, 5), np.uint8)  
dst = cv2.erode(img, k)  
cv2.imshow('erode', dst)  
dst = cv2.dilate(dst, k)  
cv2.imshow('dst', dst)  
cv2.waitKey()  
cv2.destroyAllWindows()

(4)闭运算

闭运算,即先膨胀后腐蚀;可用来抹除图像内部的细节(或噪声)

(5)形态学方法

dst = cv2.morphologyEx(src, op, kernel, anchor, iterations, borderType, borderValue)

  • src:被处理的图像
  • op:操作类型:
    • cv2.MORPH_ERODE:腐蚀操作
    • cv2.MORPH_DILATE:膨胀操作
    • cv2.MORPH_OPEN:开运算
    • cv2.MORPH_CLOSE:闭运算
    • cv2.MORPH_GRADIENT:梯度运算,膨胀图减腐蚀图,可以得出简易的轮廓,并不精准
    • cv2.MORPH_TOPHAT:顶帽运算,原始图像减开运算图像,即包含外部细节的图片减去不带外部细节的图片,得到外部细节
    • cv2.MORPH_BLACKHAT:黑帽运算,闭运算图像减原始图像,即无内部细节的图片减去带内部细节的图片,得到内部细节
  • kernel:使用的核
  • anchor:可选参数,核的锚点位置
  • iterations:可选参数,膨胀操作的迭代次数,默认值为1
  • borderType:可选参数,边界样式,建议使用默认值
  • borderValue:可选参数,边界值,建议使用默认值
  • dst:操作后的图像

9 图形检测

(1)图像的轮廓

通过计算图像梯度来判断出图像的边缘,然后将边缘的点封装成数组返回
contours, hierarchy = cv2.findContours(image, mode, method, contours, hierachy)

  • image:被检测的图像,必须是8位单通道二值图像,即如果是彩色图像,必须转为灰度图,在进行二值化阈值处理
  • mode:轮廓检索的模式:
    • cv2.RETR_EXTERNAL:只检测外轮廓
    • cv2.RETR_LIST:检测所有轮廓,但不建立层次关系
    • cv2.RETR_CCOMP:检测所有轮廓,并建立两级层次关系
    • cv2.RETR_TREE:检测所有轮廓,并建立树状结构的层次关系
  • method:检测轮廓时使用的方法:
    • cv2.CHAIN_APPROX_NONE:存储轮廓上的所有点
    • cv2.CHAIN_APPROX_SIMPLE:只保存水平、垂直或对角线轮廓的端点
    • cv2.CHAIN_APPROX_TC89_L1Ten-Chinl近似算法的一种
    • cv2.CHAIN_APPROX_TC89_KCOSTen-Chinl近似算法的一种
  • contours:检测出的所有轮廓,list类型,每一个元素都是某个轮廓的像素坐标值
  • hierarchy:轮廓之间的层次关系

检测出轮廓之后,可通过drawContours()方法绘制出轮廓
image = cv2.drawContours(image, contours, contourIdx, color, thickness, lineType, hierachy, maxLevel, offset)

  • image:被绘制轮廓的原始图像
  • contoursfindContours()方法得到的轮廓列表
  • contoursIdx:绘制轮廓的索引,如果为-1则绘制所有轮廓
  • color:绘制颜色,BGR格式
  • thickness:可选参数,画笔的粗细程度,如果为-1,则绘制实心轮廓
  • lineType:可选参数,绘制轮廓的线型
  • hierachy:可选参数,findContours()方法获得的层次关系
  • maxLevel:可选参数,绘制轮廓的层次深度,最深绘制到第maxLevel层
  • offset:可选参数,偏移量,可改变绘制结果的位置
import cv2
img = cv2.imread("shape1.png")  # 读取原图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 彩色图像转为变成单通道灰度图像
t, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)  # 灰度图像转为二值图像
# 检测图像中出现的所有轮廓,记录轮廓的每一个点
contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
# 绘制所有轮廓,宽度为5,颜色为红色
cv2.drawContours(img, contours, -1, (0, 0, 255), 5)
cv2.imshow("img", img)  # 显示绘制结果
cv2.waitKey()  # 按下任何键盘按键后
cv2.destroyAllWindows()  # 释放所有窗体

(2)轮廓拟合

使用cv2.findContours()计算出的轮廓,可以计算出拟合曲线,即轮廓的包围框,包围框可以使矩形、圆形

矩形包围框

x, y, w, h = cv2.boundingRect(array)

  • x, y, w, h:包围框左上角坐标(x, y),包围框的宽w,高h
  • array:轮廓数组
import cv2  
  
img = cv2.imread('shape2.png')  
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  
t, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)  
contours, hierachy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)  
  
x, y, w, h = cv2.boundingRect(contours[0])  
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 0, 255), 2)  
cv2.imshow('img', img)  
cv2.waitKey()  
cv2.destroyAllWindows()

圆形包围框

center, radius = cv2.minEnclosingCircle(points)

  • points:轮廓数组
  • center:圆形包围框的中心点坐标
  • radius:圆形包围框的半径
# 注意:使用cv2.circle()绘制时,要确保center, radius参数必须是整形
import cv2  
  
img = cv2.imread('shape2.png')  
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  
t, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)  
contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)  
  
center, radius = cv2.minEnclosingCircle(contours[0])  
x = int(round(center[0]))  
y = int(round(center[1]))  
radius = int(round(radius))                   
cv2.circle(img, (x, y), radius, (0, 0, 255), 2)  
cv2.imshow('img', img)  
cv2.waitKey()  
cv2.destroyAllWindows()

(3)凸包

凸包是最逼近轮廓的多边形,凸包的每一处都是凸出来的,即任意三点所组成的内角均小于180度
hull = cv2.convexHull(points, clockwise, returnPoints)

  • points:轮廓数组
  • clockwise:可选参数,布尔值;为True时,凸包中的点按顺时针排列
  • returnPoints:可选参数,布尔值;为True时,返回点坐标
  • hull:凸包的点阵数组

(4)Canny边缘检测

根据像素的梯度变化寻找图像边缘,最终绘制出十分精细的而之边缘图像
edges = cv2.Canny(image, threshold1, threshold2, apertureSize, L2gradients)

  • image:原始图像
  • threshold1:计算过程中使用的第一个阈值,可以是最小阈值,也可以是最大阈值;通常用来设置最小阈值
  • threshold2:计算过程中使用的第二个阈值,最大阈值
  • apertureSize:可选参数,Sobel算子的孔径大小
  • L2gradient:可选参数,计算梯度的标识,默认为False;为True时采用更精准的算法进行计算
  • edges:计算结果,二值灰度图
    通常通过调整最小阈值和最大阈值来控制边缘检测的精细程度;当两个阈值都比较小时,会检测出更多细节
import cv2  
  
img = cv2.imread('flower.png')  
r1 = cv2.Canny(img, 10, 50)  
r2 = cv2.Canny(img, 100, 200)  
r3 = cv2.Canny(img, 400, 600)  
  
cv2.imshow('img', img)  
cv2.imshow('r1', r1)  
cv2.imshow('r2', r2)  
cv2.imshow('r3', r3)  
  
cv2.waitKey()  
cv2.destroyAllWindows()

(5)霍夫变换

通过算法识别图像特征,从而判断出图像的特殊形状,如直线和圆

直线检测

  • 检测无限延长的直线
    lines = cv2.HoughLines(image, rho, theta, threshold)
  • 检测线段
    lines = cv2.HoughLinesP(image, rho, theta, threshold, minLineLength, maxLineGap)
  • image:原始图像,可以是cv2.Canny()检测出的边缘图像
  • rho:检测直线使用的半径步长,值为1时,表示检测所有可能的半径步长
  • theta:搜索直线的角度,值为 π / 180 \pi/180 π/180时,表示检测所有角度
  • threshold:阈值,该值越小,表示检测出的直线就越多
  • minLineLength:线段的最小长度,小于该长度的直线不会记录到结果中
  • maxLineGap:线段之间的最大距离
  • lines:格式为:[[[x1, y1, x2, y2], [x1, y1, x2, y2], ...]]
    注意: 该方法前需进行降噪处理,否则检测结果不佳
import cv2  
import numpy as np  
  
img = cv2.imread('pen.jpg')  
o = img.copy()  
o = cv2.medianBlur(o, 5)  
gray = cv2.cvtColor(o, cv2.COLOR_BGR2GRAY)  
binary = cv2.Canny(o, 50, 150)  
lines = cv2.HoughLinesP(binary, 1, np.pi / 180, 15, minLineLength=100, maxLineGap=18)  
for line in lines:  
    x1, y1, x2, y2 = line[0]  
    cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 2)  
  
cv2.imshow('canny', binary)  
cv2.imshow('img', img)  
cv2.waitKey()  
cv2.destroyAllWindows()

圆环检测

circles = cv2.HoughCircles(image, method, dp, minDist, param1, param2, minRadius, maxRadius)

  • image:原始图像
  • method:检测方法:cv2.HOUGN_GRADIENT
  • dp:累加器分辨率与原始图像分辨率之比的倒数;为1时,累加器分辨率=原始图像分辨率;为2时,累加器分辨率=0.5 * 原始图像分辨率;通常设为1
  • minDist:圆心之间的最小距离
  • param1:可选参数,Canny边缘检测使用的最大阈值
  • param2:可选参数,检测圆环结果的投票数;第一轮筛选时,投票数超过该阈值的圆才能进入第二轮筛选;值越大,检出的圆越少,越精准
  • minRadius:可选参数,圆的最小半径
  • maxRadius:可选参数,圆的最大半径
  • circles:格式为:[[[x1, y1, r1], [x2, y2, r2], ...]]
    注意: 该方法前需进行降噪处理,否则检测结果不佳
import cv2  
import numpy as np  
  
img = cv2.imread('coin.jpg')  
o = img.copy()  
o = cv2.medianBlur(o, 5)  
gray = cv2.cvtColor(o, cv2.COLOR_BGR2GRAY)  
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, 70, param1=100, param2=25, minRadius=10, maxRadius=50)  
circles = np.uint(np.round(circles))  
  
for c in circles[0]:  
    x, y, r = c  
    cv2.circle(img, (x, y), r, (0, 0, 255), 3)  
    cv2.circle(img, (x, y), 2, (0, 0, 255), 3)  # 绘制圆心  
cv2.imshow('img', img)  
cv2.waitKey()  
cv2.destroyAllWindows()

10 模板匹配

result = cv2.matchTemplete(image, templ, method, mask)

  • image:原始图像
  • templ:模板图像,尺寸小于等于原始图像
  • method:匹配方法:
    • cv2.TM_SQDIFF:或0,差值平方和匹配,也叫平方差匹配;可以理解为差异程度;匹配程度越高,计算结果越小,完全匹配的结果为0
    • cv2.TM_SQDIFF_NORMED:或1,标准差值平方和匹配,也较标准差匹配
    • cv2.TM_CCORR:或2,相关匹配;可以理解为相似程度,匹配程度越高,计算结果越大
    • cv2.TM_CCORR_NORMED:或3,标准相关匹配
    • cv2.TM_CCOEFF:或4,相关系数匹配,也属于相似程度,计算结果为-1~1之间的浮点数,1表示完全匹配,0表示毫无关系,-1表示两张图片亮度刚好相反
    • cv2,TM_CCOEFF_NORMED:或5,标准相关系数匹配
  • mask:可选参数,掩模,建议使用默认值;cv2.TM_SQDIFFcv2.TM_CCORR_NORMED支持此参数
  • result:匹配结果;记原始图像宽高为WH,模板图像宽、高为whresult即为W-w+1H-h+1;其中每一个浮点数都是原始图像中对应像素位置的匹配结果

(1)单模板匹配

匹配中只用到一个模板

单目标匹配

最终只获得匹配程度最高那一个结果
minValue, maxValue, minLoc, maxLoc = cv2.minMaxLoc(src, mask)

  • srcmatchTemplete()方法计算得出的数组
  • mask:可选参数,掩模,建议使用默认值
  • minValue:数组中的最小值
  • maxValue:数组中的最大值
  • minLoc:最小值的坐标,(x, y)
  • maxLoc:最大值的坐标,(x, y)
# 示例一: 从background 中 匹配出 template
import cv2  
  
img = cv2.imread('background.jpg')  
templ = cv2.imread('template.png')  
height, width, _ = templ.shape  
results = cv2.matchTemplate(img, templ, cv2.TM_SQDIFF_NORMED)  
minValue, maxValue, minLoc, maxLoc = cv2.minMaxLoc(results)  
resultPoint1 = minLoc  
resultPoint2 = (minLoc[0] + width, minLoc[1] + height)  
cv2.rectangle(img, resultPoint1, resultPoint2, (0, 0, 255), 2)  
  
cv2.imshow('img', img)  
cv2.waitKey()  
cv2.destroyAllWindows()


# 示例二:从多个图片中匹配templ,找到最佳的匹配的那个原始图片
import cv2  
  
images = []  
images.append(cv2.imread('image_221.png'))  
images.append(cv2.imread('image_222.png'))  
templ = cv2.imread('templ.png')  
index = -1  
minValue = 1  
  
for i in range(len(images)):  
    results = cv2.matchTemplate(images[i], templ, cv2.TM_SQDIFF_NORMED)  
    if results.any() < minValue:  
        index = i  
        minValue = min(results)  
cv2.imshow('result', images[index])  
cv2.waitKey()  
cv2.destroyAllWindows()

多目标匹配

需同时获得所有匹配程度较高的结果
注意: 数组的列数在图像坐标系中为横坐标,数组的行数在图像坐标系中为纵坐标

import cv2  
  
img = cv2.imread('background2.jpg')  
templ = cv2.imread('template.png')  
height, width, _ = templ.shape  
results = cv2.matchTemplate(img, templ, cv2.TM_CCOEFF_NORMED)  
for y in range(len(results)):  
    for x in range(len(results[y])):  
        if results[y][x] > 0.99:  
            cv2.rectangle(img, (x, y), (x+width, y+height), (0,0,255), 2)  
cv2.imshow('img', img)  
cv2.waitKey()  
cv2.destroyAllWindows()

(3)多模板匹配

同时查找多个模板的操作,实际上进行了n次(n为模板总数)单模板多目标匹配

import cv2  
  
  
def myMatchTemplate(img, templ):  
    height, width, _ = templ.shape  
    results = cv2.matchTemplate(img, templ, cv2.TM_CCOEFF_NORMED)  
    location = []  
    for y in range(len(results)):  
        for x in range(len(results[y])):  
            if results[y][x] > 0.99:  
                location.append((x, y, x + width, y + height))  
    return location  
  
  
img = cv2.imread('background2.jpg')  
templs = list()  
templs.append(cv2.imread('template.png'))  
templs.append(cv2.imread('template2.png'))  
templs.append(cv2.imread('template3.png'))  
locations = []  
for t in templs:  
    locations += myMatchTemplate(img, t)  
  
for l in locations:  
    cv2.rectangle(img, (l[0], l[1]), (l[2], l[3]), (0, 0, 255), 2)  
cv2.imshow('result', img)  
cv2.waitKey()  
cv2.destroyAllWindows()

11 视频处理

(1)读取并显示摄像头视频

摄像头初始化

capture = cv2.VideoCapture(index)

  • capture:要打开的摄像头
  • index:摄像头的设备索引,如使用笔记本,当index=0时,表示笔记本的内置摄像头;当index=1时,表示外置摄像头

检查摄像头是否初始化成功

retval = cv2.VideoCapture.isOpen()

  • retval:摄像头是否初始化成功,如果为True,表示初始化成功
    也可以简写:
    retval = capture.isOpen()

从摄像头读取帧

retval, image = capture.read()

  • retval:是否读取到帧,布尔值
  • image:读取到的帧

关闭摄像头

capture.release()
打开摄像头操作示例:

import cv2  
  
capture = cv2.VideoCapture(0)  
while capture.isOpened():  
    retval, image = capture.read()  
    cv2.imshow('Video', image)  
    key = cv2.waitKey(1) # 等待1ms  
 if key == 32:  # 按下空格后  
 break  
capture.release()  
cv2.destroyAllWindows()

把摄像头采集到的图片转换为灰度图显示:

import cv2  
  
capture = cv2.VideoCapture(0)  
while capture.isOpened():  
    retval, image = capture.read()  
    cv2.imshow('rgb', image)  
    image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)  
    cv2.imshow('gray', image_gray)  
    if cv2.waitKey(1) == 32:  
        break  
capture.release()  
cv2.destroyAllWindows()

按下空格键,保存当前帧:

import cv2  
  
cap = cv2.VideoCapture(0)  
while cap.isOpened():  
    retval, image = cap.read()  
    cv2.imshow('Video', image)  
    if cv2.waitKey(1) == 32:  
        cap.release()  
        cv2.destroyWindow('Video')  
        cv2.imwrite('copy.png', image)  
        break  
cv2.destroyAllWindows()

(2)播放视频文件

video = cv2.VideoCapture(filename)

  • video:要打开的视频
  • filename:视频文件的文件名

读取并显示视频文件

import cv2  
  
video = cv2.VideoCapture('公司宣传.avi')  
while video.isOpened():  
    retval, image = video.read()  
    if not retval:  
        break  
	cv2.imshow('video', image)  
    if cv2.waitKey(1) == 27: # Esc   
 break  
video.release()  
cv2.destroyAllWindows()

cv2.waitKey(1)时,视频播放速度非常快,可设置为cv2.waitKey(50)减缓播放速度

暂停和继续播放

import cv2  
  
video = cv2.VideoCapture('公司宣传.avi')  
while video.isOpened():  
    retval, image = video.read()  
    if not retval:  
        break  
 cv2.imshow('video', image)  
    key = cv2.waitKey(1)  
    if key == 32:  # 按下空格键,暂停  
 key = cv2.waitKey(0)      # 无限等待用户按下任意键  
 continue # 按下任意键后继续  
 if key == 27:  
        break  
video.release()  
cv2.destroyAllWindows()

获取视频文件的属性

retval = cv2.VideoCapture.get(propId)

  • retval:获取到与propId对应的属性值
  • propId:属性ID:
    • cv2.CAP_PROP_POS_MSEC:视频文件播放时的当前位置(单位:ms)
    • cv2.CAP_PROP_POS_FRAMES:帧的索引,从0开始
    • cv2.CAP_PROP_POS_RATIO:视频文件的相对位置,0表示开始播放,1表示结束播放
    • cv2.CAP_PROP_FRAME_WIDTH:视频文件的帧宽度
    • cv2.CAP_PROP_FRAME_HEIGHT:视频文件的高度
    • cv2.CAP_PROP_FPS:帧速率
    • cv2.CAP_PROP_FOURCC:用4个字符表示的视频编码格式
    • cv2.CAP_PROP_FRAME_COUNT:视频文件的帧数
    • cv2.CAP_PROP_FORMATretrieve()方法返回的Mat对象格式
    • cv2.CAP_PROP_MODE:指当前捕获模式的后端专用的值
    • cv2.CAP_PROP_CONVERT_RGB:指示是否应将图像转换为RGB
import cv2

video = cv2.VideoCapture("公司宣传.avi") # 打开视频文件
fps = video.get(cv2.CAP_PROP_FPS) # 获取视频文件的帧速率
frame_Num = 1 # 用于记录第几幅图像(即第几帧),初始值为1(即第1幅图像)
while (video.isOpened()): # 视频文件被打开后
   retval, frame = video.read() # 读取视频文件
   # 设置“Video”窗口的宽为420,高为300
   cv2.namedWindow("Video", 0)
   cv2.resizeWindow("Video", 420, 300)
   if retval == True: # 读取到视频文件后
      # 当前视频播放到第几帧
      cv2.putText(frame, "frame: " + str(frame_Num), (0, 100),
               cv2.FONT_HERSHEY_SIMPLEX, 2, (0, 0, 255), 5)
      # 该帧对应着视频的第几秒
      cv2.putText(frame, "second: " + str(round(frame_Num / fps, 2)) + "s",
               (0, 200), cv2.FONT_HERSHEY_SIMPLEX, 2, (0, 0, 255), 5)
      cv2.imshow("Video", frame) # 在窗口中显示读取到的视频文件
   else: # 没有读取到视频文件
      break
   key = cv2.waitKey(50) # 窗口的图像刷新时间为50毫秒
   frame_Num += 1 #
   if key == 27: # 如果按下Esc键
      break
video.release() # 关闭视频文件
cv2.destroyAllWindows() # 销毁显示视频文件的窗口

(3)保存视频文件

创建VideoWriter类对象

= cv2.VideoWriter(filename, fourcc, fps, frameSize)

  • :创建的VideoWriter类对象
  • filename:保存视频的路径
  • fourcc:用四个字符表示的视频编码格式:
    • 使用cv2.VideoWriter_fourcc()来确定编码格式:
    • cv2.VideoWriter_fourcc('I', '4', '2', '0'),表示未压缩的YUV颜色编码格式,兼容性好,但文件较大,扩展名为.avi
    • cv2.VideoWriter_fourcc('P', 'I', 'M', 'I'),MPEG-1编码格式,扩展名为.avi
    • cv2.VideoWriter_fourcc('X', 'V', 'I', 'D'),MPEG-4编码格式,视频文件的大小为平均值,扩展名为.avi
    • cv2.VideoWriter_fourcc('T', 'H', 'E', 'O'),Ogg Vorbis编码格式,兼容性差,扩展名为.ogv
    • cv2.VideoWriter_fourcc('F', 'L', 'V', 'I'),Flash视频编码格式,扩展名为.flv
  • fps:帧速率
  • frameSize:每一帧的大小,格式为(宽,高)
    例如:
fourcc = cv2.VideoWriter_fourcc('X', 'V', 'I', 'D')   # 或 cv2.VideoWriter_fourcc(* 'XVID')
output = cv2.VideoWriter('output.avi', fourcc, 20, (640, 480))

写入

output.write(frame)

  • frame:读取到的帧
    注意: 写入的frame的宽高必须和创建VideoWriter时指定的宽高frameSize尺寸相同,否则写不进去

释放

output.release()

import cv2  
  
cap = cv2.VideoCapture(0)  
size = (640, 480)  
cap.set(cv2.CAP_PROP_FRAME_WIDTH, size[0])   # 设定摄像头读取的宽、高
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, size[1])  
fourcc = cv2.VideoWriter_fourcc(*'XVID')  
out = cv2.VideoWriter('demo11-11.avi', fourcc, 20.0, size)  
while cap.isOpened():  
    ret, frame = cap.read()  
    out.write(frame)  
    cv2.imshow('frame', frame)  
    if cv2.waitKey(1) == 27:  
        break  
cap.release()  
out.release()  
cv2.destroyAllWindows()

12 人脸识别

(1)人脸跟踪

OpenCV依靠级联分类器.../Python/Lib/site-package/cv2/data/*.xml)对样本进行识别,分两步进行:

  • 第一步:加载分类器: = cv2.CascadeClassifier(filename)
    • filename:级联分类器的XML文件名
    • object:分类器对象
  • 第二步:使用分类器进行识别:objects = cascade.detectMultiScale(image, scaleFactor, minNeighbors, flags, minSize, maxSize)
    • cascade:第一步创建的分类器对象
    • image:待识别的图像
    • scaleFactor:可选参数,扫描图像时的缩放比例
    • minNeighbors:可选参数,每个候选区域至少保留多少个检测结果才可以判定为人脸;值越大,分析的误差越小
    • flags:可选参数,旧版本OpenCV参数,建议使用默认值
    • minSize:可选参数,最小的目标尺寸
    • maxSize:可选参数,最大的目标尺寸
    • objects:捕捉到的目标区域的数组,每个元素都是一个目标区域,每个区域包含[左上角点横坐标,左上角点纵坐标,区域宽,区域高];objects格式形如:[[244 203 111 111] [432 81 133 133]]
import cv2  
  
img = cv2.imread('IMG_1286.JPG')  
faceCascade = cv2.CascadeClassifier('cascades/haarcascade_frontalface_default.xml')  # 该级联分类器存放在当前目录下
faces = faceCascade.detectMultiScale(img, 1.15)  
for (x, y, w, h) in faces:  
    cv2.rectangle(img, (x, y), (x + w, y + h), (0, 0, 255), 5)  
cv2.imshow('img', img)  
cv2.waitKey()  
cv2.destroyAllWindows()

(2)人脸识别

三种人脸识别方法,三种方法识别过程均分为三步:创建识别器、训练识别器、识别

Eigenfaces人脸识别器

通过PCA将人脸数据转换至另一个空间维度进行相似度计算

  • 第一步:创建人脸识别器:recognizer = cv2.face.EigenFaceRecognizer_create(num_components, threshold)
    • num_components:可选参数,PCA方法中保留的分量个数,建议使用默认值
    • threshold:可选参数,人脸识别时使用的阈值,建议使用默认值
    • recognizer:创建的人脸识别器对象
  • 第二步:训练识别器:recoginzer.train(src, labels)
    • src:训练用的人脸图像样本,为list类型,样本的尺寸必须一致
    • labels:训练用的人脸标签,必须和src一一对应
  • 第三步:用新样本预测:label, confidence = recognizer.predict(src)
    • src:测试用例,尺寸必须和训练样本一致
    • label:与样本匹配度最高的标签
    • confidence:匹配度最高的信用度评分,评分小于5000即可认为匹配度较高,0表示完全匹配
  
import cv2  
import numpy as np  
  
photos = list()  # 样本图像列表  
lables = list()  # 标签列表  
photos.append(cv2.imread("face/summer1.png", 0))  # 记录第1张人脸图像  
lables.append(0)  # 第1张图像对应的标签  
photos.append(cv2.imread("face/summer2.png", 0))  # 记录第2张人脸图像  
lables.append(0)  # 第2张图像对应的标签  
photos.append(cv2.imread("face/summer3.png", 0))  # 记录第3张人脸图像  
lables.append(0)  # 第3张图像对应的标签  
  
photos.append(cv2.imread("face/Elvis1.png", 0))  # 记录第4张人脸图像  
lables.append(1)  # 第4张图像对应的标签  
photos.append(cv2.imread("face/Elvis2.png", 0))  # 记录第5张人脸图像  
lables.append(1)  # 第5张图像对应的标签  
photos.append(cv2.imread("face/Elvis3.png", 0))  # 记录第6张人脸图像  
lables.append(1)  # 第6张图像对应的标签  
  
names = {"0": "Summer", "1": "Elvis"}  # 标签对应的名称字典  
  
recognizer = cv2.face.EigenFaceRecognizer_create()  # 创建特征脸识别器  
recognizer.train(photos, np.array(lables))  # 识别器开始训练  
  
i = cv2.imread("face/summer4.png", 0)  # 待识别的人脸图像  
label, confidence = recognizer.predict(i)  # 识别器开始分析人脸图像  
print("confidence = " + str(confidence))  # 打印评分  
print(names[str(label)])  # 数组字典里标签对应的名字  
cv2.waitKey()  # 按下任何键盘按键后  
cv2.destroyAllWindows()  # 释放所有窗体

Fisherfaces人脸识别器

通过LDA(线性判别分析)方法将人脸数据转换到其他空间去做投影计算
recoginzer = cv2.face.FisherRecognizer_create(num_components, threshold)

Local Binary Pattern Histgram 人脸识别器

简称LBPH,即局部二值模式直方图,是一种基于局部二值模式算法,善于捕获局部纹理特征
recognizer = cv2.face.LBPHFaceRecognizer_create(radius, neighbors, grid_x, grid_y, threshold)

  • radius:可选参数,圆形局部二值模式的半径,建议默认
  • neighbors:可选参数,圆形局部二值模式的采样点数目,建议默认
  • grid_x:可选参数,水平方向上的单元格数目,建议默认
  • grid_y:可选参数,垂直方向上的单元格数目,建议默认
  • threshold:可选参数,人脸识别使用的阈值,建议默认

你可能感兴趣的:(学习笔记,opencv,python,计算机视觉)