Opencv图像处理基础

一、 图片读取
import matplotlib.pyplot as plt
import cv2


def main():
    image = cv2.imread('1.jpg')  # (H,W,C)
    print('height:{} pixels'.format(image.shape[0])) # 第0行为高
    print('width:{} pixels'.format(image.shape[1])) # 第1行为宽
    print('channels:{} pixels'.format(image.shape[2])) # 第2行为通道数
    plt.imshow(image) # 读入图像,进行处理
    plt.axis('off')
    plt.show()


if __name__ == '__main__':
    main()

在这里插入图片描述
可以看到我们用 cv2.imread() 读取的图片和原图颜色不一样,原因在于 opencv 读取的格式是 BGR 的格式,而 matplotlib 显示的又是 RGB 的格式,所以根据代码中的变量image的像素值以 RGB 格式显示的和原图有差别。

解决办法:RB 的像素点的值对换

image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
二、 图片切分
	image = cv2.imread('2.jpg')
    h, w, c = image.shape
    lu = image[0:h//2, 0:w//2]  # 切取左上部分图片
    ru = image[0:h//2, w//2:w]  # 切取右上部分图片
    ld = image[h//2:h, 0:w//2]  # 切取左下部分图片
    rd = image[h//2:h, w//2:w]  # 切取右下部分图片
三、 修改图片
image[0:h//2, 0:w//2] = (0, 0, 255) # RGB,左上部分改成蓝色
show(image)

在这里插入图片描述

四、 移动图片
def show(image):
    plt.imshow(image)
    plt.axis('off')
    plt.show()


def image_read(path):
    image = cv2.imread(path)
    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    return image


def main():
    image = image_read('1.jpg')
    h, w = image.shape[:2]
    # 水平方向向右平移250个像素,竖直方向向上平移500个像素
    M = np.float32([[1,0,250],[0,1,500]])
    shift_image = cv2.warpAffine(image, M, (w,h))
    show(shift_image)

在这里插入图片描述

五、 旋转图片
	image = image_read('1.jpg')
    h, w = image.shape[:2]
    cX, cY = w//2, h//2
    # (cX,cY)表示旋转中心点
    # 45表示逆时针旋转角度
    # 0.5 表示缩放比例
    M = cv2.getRotationMatrix2D((cX,cY), 45, 0.5)
    image = cv2.warpAffine(image, M, (w,h))
    show(image) # 自定义函数,见上面代码

在这里插入图片描述

六、 重塑图片
	image = image_read('1.jpg')
    width = image.shape[1]
    height = image.shape[0]
    image = cv2.resize(image, (width//10, height//10))  # 将像素点的数量变为原来的1/100
    show(image)

在这里插入图片描述

很明显,像素点减少后,图片变得很模糊

def detectFace():
    image = image_read('huge.jpg')
    detector = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
    rects = detector.detectMultiScale(image, scaleFactor=1.1, minNeighbors=3, minSize=(10, 10),flags=cv2.CASCADE_SCALE_IMAGE)
    # 画出绿色的矩形框
    for (x, y, w, h) in rects:
        cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)
    show(image)

在这里插入图片描述

haarcascade_frontalface_default.xml

七、 画图

画线和矩形

	image = np.zeros((400, 300, 3), dtype='uint8') # 一张全黑图片
    w = image.shape[1]
    h = image.shape[0]
    cv2.line(image, (0, 0), (w, h), (0,255,0), 2)  # 绿色线
    cv2.line(image, (w, 0), (w//2, h//2), (0,0,255), 4)  # 蓝色线
    cv2.rectangle(image, (10,10), (60,60), (255,0,0), 6) # 红色矩形
    cv2.rectangle(image, (w//2, h//2), (w-50, h-50), (0,255,0), -1) # 填充绿色
    

在这里插入图片描述
画圆

	image = np.zeros((400, 400, 3), dtype='uint8') # 一张全黑图片
    w = image.shape[1]
    h = image.shape[0]
    for r in range(0, w//2, 15):
        color = np.random.randint(0,255,size=(3,)).tolist()
        cv2.circle(image, (w//2, h//2), r, color, 2)
    show(image)

在这里插入图片描述
填充

	image = np.zeros((400, 400, 3), dtype='uint8') # 一张全黑图片
    w = image.shape[1]
    h = image.shape[0]
    for i in range(1, 10):
        color = np.random.randint(0,255,size=(3,)).tolist()  # 可以不是元组
        center = tuple(np.random.randint(0,255,size=(2,)))  # 必须是元组
        radius = np.random.randint(5, 200) # 半径随机
        cv2.circle(image, center, radius, color, -1)  # 圆心 半径 颜色 填充
    show(image)

在这里插入图片描述

八、翻转
	image = cv2.flip(image, 1) # 1 表示水平翻转
    image = cv2.flip(image, 0)  # 0 表示竖直翻转
    image = cv2.flip(image, -1)  # -1 表示水平 + 垂直翻转
九、 加减法
	 # 图像加法
    print(cv2.add(np.uint8([200]), np.uint8([100])))  # 300超过255就显示255
    # 普通加法
    print(np.uint8([200]) + np.uint8([100]))  # 44 因为255 + 1 = 0
    # 图像减法
    print(cv2.subtract(np.uint8([100]), np.uint8([200])))  # -100小于0就显示0
    # 普通减法
    print(np.uint8([100]) - np.uint8([200]))  # 156 ,因为256-100 = 156
	image = image_read('huge.jpg')
    M = np.ones(image.shape, dtype='uint8')*100  # 生成和图片形状相同的并且全为100的数据
    image = cv2.add(image, M)  # 像素值变大,偏白
    image = cv2.subtract(image, M)  # 像素值变小,偏黑

在这里插入图片描述

十、位运算
	rectangle = np.zeros((300, 300, 3), dtype='uint8')
    cv2.rectangle(rectangle, (25,25), (275,275), (255,255,255), -1)  # 左上 右下 颜色 填充
    circle = np.zeros((300, 300, 3), dtype='uint8')
    cv2.circle(circle, (150, 150), 150 , (255, 255, 255), -1) # 圆心 半径 颜色 填充(线宽) 

在这里插入图片描述

1. 与操作
	image = cv2.bitwise_and(rectangle, circle)  # 有0结果就是0,有黑就是黑

在这里插入图片描述

2. 或运算
	image = cv2.bitwise_or(rectangle, circle)  # 有1结果就是1,有白就是白

在这里插入图片描述

image = cv2.bitwise_xor(rectangle, circle)  # 同0异1,白白或黑黑变黑,黑白变白  

在这里插入图片描述

3. 取反
image = cv2.bitwise_not(circle)  

在这里插入图片描述

4. 位运算对图片进行遮挡
	image = image_read('huge.jpg')
    mask = np.zeros(image.shape, dtype='uint8')
    white = (255,255,255)
    cv2.circle(mask, (image.shape[1]//2, image.shape[0]//2-20), 100, white, -1) # 圆心,半径,颜色,填充
    # 对原始图片进行遮挡
    # 和白色区域与运算结果不变,和黑色区域与运算结果为黑色
    masked = cv2.bitwise_and(image, mask)
    show(masked)

在这里插入图片描述

十一、 切分合并通道
	image = image_read('huge.jpg')
    print(image.shape)
    R, G, B = cv2.split(image)  # 拿到三个通道的数据
    print(R.shape, G.shape, B.shape)  # shape和图片大小一样 
    cv2.imshow('R', R)  # 单通道显示,显示的黑白颜色
    cv2.imshow('G', G)
    cv2.imshow('B', B)
    merged = cv2.merge([R,G,B])  # 三个通道合并后就是原图
    show(merged)  # 显示原图
十二、 图像金字塔

图像金字塔是图像多尺度表达的一种,是一种以多分辨率来解释图像的有效但概念简单的结构。一幅图像的金字塔是一系列以金字塔形状排列的分辨率逐步降低,且来源于同一张原始图的图像集合。我们将一层一层的图像比喻成金字塔,层级越高,则图像越小,分辨率越低。

在这里插入图片描述

1. 高斯金字塔

高斯金字塔的顶部通过将底部图像中 连续的行和列去除 得到。顶部图像的每个像素值相当于下一层图像中5个像素的高斯加权平均值。操作一次就会将一个M*N 的图像变成一个M/2 * N/2的图像,图像面积变为原来的1/4。在python中我们通过函数 cv2.pyrDown()cv2.pyrUp() 构建图像金字塔

cv2.pyrDown() 对图像的向下取样操作,即缩小图像

  • 对图像进行高斯内核卷积,进行高斯模糊;

  • 将所有偶数行和列去除。

cv2.pyrUp() 对图像的向上取样,即放大图像

  • 将图像在每个方向扩大为原来的两倍,新增的行和列以0填充

  • 使用先前同样的内核(乘以4)与放大后的图像卷积,获得 “新增像素”的近似值

	image = image_read('huge.jpg')
    print('原始大小:{}'.format(image.shape))
    for i in range(4):
        image = cv2.pyrDown(image)
        print(image.shape)
    show(image)

在这里插入图片描述

在这里插入图片描述
缩小为原图的1/16 后,已经全部都是马赛克了

十三、 腐蚀和膨胀

原理: 通过卷积的方式,在原图的小区域内取得局部最小值,会使得一些黑色的点向外扩张。这个卷积核也叫结构元素,结构元素可以是矩形、椭圆、十字形,可用 c v 2. g e t S t r u c t u r i n g E l e m e n t ( ) cv2.getStructuringElement() cv2.getStructuringElement() 生成不同形状的结构元素(卷积核)

	# 矩形卷积核
	rec_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))  
    # 椭圆卷积核
    ellipse_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
    # 十字形卷积核
    cross_kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (5,5))
1. 利用腐蚀去除白色的点
	image = image_read('night.jpg')
	erosion = cv2.erode(image, rec_kernel)
    show(erosion)

在这里插入图片描述

: 由于卷积核选取区域最小的像素值形成新的图片,像素值减小了,整体颜色会偏暗,也会去除白色的点

2. 利用膨胀操作去除黑色的点
	dilation = cv2.dilate(image, rec_kernel)
    show(dilation)

在这里插入图片描述

:因为膨胀操作是选取局部像素 最大的,故会把图片整体变白,白色的点也会变成白色方块

3. Gradient形态学梯度

膨胀图 - 腐蚀图,可提取物体轮廓

gradient = cv2.morphologyEx(image, cv2.MORPH_GRADIENT, rec_kernel)
show(gradient)

在这里插入图片描述

十四、开闭运算
1. 开运算

先腐蚀后膨胀,可去除图片中的白点

opened = cv2.morphologyEx(image, cv2.MORPH_OPEN, rec_kernel)
2. 闭运算

先膨胀后腐蚀,可去除图片中的黑点

closed = cv2.morphologyEx(image, cv2.MORPH_CLOSE, rec_kernel)
十五、 白帽和黑帽
1. 白帽

原图 - 开运算,src - opened,可显示被去掉的白色部分

	whiteHat = cv2.morphologyEx(image, cv2.MORPH_TOPHAT, rec_kernel)
    show(whiteHat)

在这里插入图片描述

2. 黑帽

闭运算 - 原图,closed - src,可显示被去掉的黑色部分

	blackHat = cv2.morphologyEx(image, cv2.MORPH_BLACKHAT, rec_kernel)
    show(blackHat)
十六、 图像平滑
1. 平均平滑

计算卷积框覆盖区域所有像素的平均值得到卷积的结果,此时的卷积核为N*N的矩阵

	image = image_read('lixian.jpg')
    kernel_sizes = [(3,3), (9,9), (15,15)]
    plt.figure(figsize=(15, 15))
    for i, kernel in enumerate(kernel_sizes):
        plt.subplot(1,3, i+1)
        blur = cv2.blur(image, kernel)  # 平均平滑,卷积窗口越大,图片越模糊
        plt.axis('off')
        plt.title('Blurred' + str(kernel))
        plt.imshow(blur)
    plt.show()

在这里插入图片描述

2. 高斯模糊

卷积核内的值是符合高斯分布的,方框中心的值最大,其余方框根据距离中心的距离递减,构成一个高斯小山包。原来的 求平均数 现在变成 求加权平均数,权就是方框里的值

	image = image_read('lixian.jpg')
    kernel_sizes = [(3,3), (9,9), (15,15)]
    plt.figure(figsize=(15, 15))
    for i, kernel in enumerate(kernel_sizes):
        plt.subplot(1,3, i+1)
        blur = cv2.GaussianBlur(image, kernel, 0)  # 0是标准差
        plt.axis('off')
        plt.title('Blurred' + str(kernel))
        plt.imshow(blur)
    plt.show()

在这里插入图片描述

3. 中值模糊

可对方框中的像素点取中值,会使得颜色鲜明的点被周围颜色的点 “同化”

	image = image_read('night.jpg')
    kernel_sizes = (3,9,15)
    plt.figure(figsize=(15, 15))
    for i, kernel in enumerate(kernel_sizes):
        plt.subplot(1,3, i+1)
        blur = cv2.medianBlur(image, kernel) 
        plt.axis('off')
        plt.title('Blurred' + str(kernel))
        plt.imshow(blur)
    plt.show()

在这里插入图片描述
可以看到,当卷积核比较大时,白色的点都被周围的黑色 “同化” 了

4. 双边滤波

作用:能在保持边界清晰的情况下有效去除噪音。

我们已经知道高斯滤波器是求中心点临近区域像素的 高斯加权平均值 。这种高斯滤波器 只考虑像素之间的空间关系 ,而不会考虑像素值之间的关系(像素的相似度),故这种方法会导致 边界模糊 ,而这不是我们想要的。

双边滤波同时使用 高斯加权平均值灰度值相似性高斯权重

  1. 空间高斯函数确保只有临近区域的像素对中心点有影响
  2. 灰度值相似性高斯函数确保只有 与中心像素灰度值相近的 才会用来做模糊运算

由于 边界处灰度值变化比较大,所以这种方法不会使得边界模糊。

	image = image_read('man.jpg')
    params = [(11,21,7), (11,41,21), (30,75,75)]
    plt.figure(figsize=(15, 15))
    # 邻域直径
    # 灰度值相似性高斯函数标准差
    # 空间高斯函数标准差
    for i, (diameter, sigmaColor, sigmaSpace) in enumerate(params):
        plt.subplot(1,3, i+1)
        blur = cv2.bilateralFilter(image, diameter, sigmaColor, sigmaSpace)
        plt.axis('off')
        plt.title('Blurred' + str((diameter, sigmaColor, sigmaSpace)))
        plt.imshow(blur)
    plt.show()
十七、颜色空间转换
1. RGB
	image = image_read('lixian.jpg')
    (R, G, B) = cv2.split(image)
    zeros = np.zeros(image.shape[:2], dtype='uint8')
    for i in range(3):
        plt.subplot(1, 3, i + 1)
        plt.axis('off')
        if i == 0:
            plt.imshow(cv2.merge([R, zeros, zeros]))
        elif i == 1:
            plt.imshow(cv2.merge([zeros, G, zeros]))
        else:
            plt.imshow(cv2.merge([zeros, zeros, B]))
    plt.show()

在这里插入图片描述

十八、图像二值化
  • 灰度值:图像灰度化就是让像素点矩阵中的每一个像素点都满足下面的关系:R=G=B,此时的这个值叫做 灰度值

  • 灰度图:灰度图只有一个通道,有256个灰度等级,255代表全白,0表示全黑。在python中 彩色 图片每个像素点包含三个值(分别表示BGR三种颜色),而 灰度图 每个像素点只有一个值

  • 二值化:就是让图像的像素点矩阵中的每个像素点的灰度值为0(黑色)或者255(白色),也就是让整个图像呈现只有黑和白的效果。在灰度化的图像中灰度值的范围为0~255,在二值化后的图像中的灰度值范围是0或者255

1. 二值化处理:
thresh, ret = cv2.threshold (src, thresh, maxval, type)
参数含义
thresh阈值,同形参
ret处理后的图片
src源图片,必须是单通道
thresh阈值,取值范围0~255
maxval填充色,取值范围0~255
type阈值类型
type含义
THRESH_BINARY二进制阈值化,非黑即白
THRESH_BINARY_INV反二进制阈值化,非白即黑
THRESH_TRUNC截断阈值化 ,大于阈值设为阈值
THRESH_TOZERO阈值化为0 ,小于阈值设为0
THRESH_TOZERO_INV反阈值化为0 ,大于阈值设为0

在这里插入图片描述

	image = image_read('coin.jpg')
    gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)  # 转成灰度图
    thresh1, ret1 = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY)  # 进行二值化,127为阈值,255为最大值
    thresh2, ret2 = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY_INV)  # ret为图片处理的结果,thresh为阈值
    thresh3, ret3 = cv2.threshold(gray, 200, 255, cv2.THRESH_TRUNC)
    thresh4, ret4 = cv2.threshold(gray, 200, 255, cv2.THRESH_TOZERO)
    thresh5, ret5 = cv2.threshold(gray, 200, 255, cv2.THRESH_TOZERO_INV)
    titles = ['gray', 'BINARY', 'BINARY_INV', 'TRUNC','TOZERO','TOZERO_INV']
    images = [gray, ret1, ret2, ret3, ret4, ret5]
    plt.figure(figsize=(15, 5))
    for i in range(len(images)):
        plt.subplot(2,3,i+1)
        plt.imshow(images[i], 'gray')
        plt.axis('off')
        plt.title(titles[i])
    plt.show()

在这里插入图片描述

2. 自适应阈值
thresh1, ret1 = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)  # 进行二值化,127为阈值,255为最大值
thresh2, ret2 = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)

在这里插入图片描述

3. 不同区域选取不同阈值
dst = cv2.adaptiveThreshold(src, maxval, thresh_type, type, BlockSize, C)
参数含义
dst输出图
src输入图,只能输入单通道图像,通常来说为灰度图
maxval当像素值超过了阈值(或者小于阈值,根据type来决定),所赋予的值
thresh_type阈值的计算方法,包含以下2种类型:cv2.ADAPTIVE_THRESH_MEAN_C; cv2.ADAPTIVE_THRESH_GAUSSIAN_C
type二值化操作的类型,与固定阈值函数相同,包含以下5种类型: cv2.THRESH_BINARY; cv2.THRESH_BINARY_INV; cv2.THRESH_TRUNC; cv2.THRESH_TOZERO;cv2.THRESH_TOZERO_INV.
BlockSize邻域大小,用于计算阈值区域的大小
C是一个常数,计算公式为【阈值 = 平均值(加权平均值)- C】
	image = image_read('license.jpg')
    gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)  # 转成灰度图
    _, ret1 = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)  # 普通二值化
    ret2 = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 3)  # 阈值取自相邻区域的平均值
    ret3 = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 3)  # 阈值取自相邻区域的加权和,权重为一个高斯窗口
    titles = ['Origin', 'Global Threshold', 'Adaptive Mean Threshold', 'Adaptive Gaussian Threshold']
    images = [gray, ret1, ret2, ret3]
    plt.figure(figsize=(15, 5))
    for i in range(len(images)):
        plt.subplot(2,2,i+1)
        plt.imshow(images[i], 'gray')
        plt.axis('off')
        plt.title(titles[i])
    plt.show()

在这里插入图片描述

  1. 原图中由于左侧较亮,像素值较大,普通二值化时直接将像素点的值置为255,故没有保留下来
  2. 而自适应阈值可以根据图片不同区域的亮度,对每个区域选取不同的阈值
十九、Canny边缘检测
  1. 噪声去除:我们知道梯度算子可以用于增强图像,本质上是通过增强边缘轮廓来实现的,也就是说是可以检测到边缘的。但是,它们受噪声的影响都很大。那么,我们第一步要先去除噪声,因为噪声就是灰度变化很大的地方,所以容易被识别为伪边缘

  2. 计算图像梯度:计算图像梯度能够得到图像的边缘,因为梯度是灰度变化明显的地方,而边缘也是灰度变化明显的地方。当然这一步只能得到可能的边缘。因为灰度变化的地方可能是边缘,也可能不是边缘。这一步就有了所有可能是边缘的集合。

  3. 非极大值抑制:非极大值抑制。通常灰度变化的地方都比较集中,将局部范围内的梯度方向上,灰度变化最大的保留下来,其它的不保留,这样可以剔除掉一大部分的点。将有多个像素宽的边缘变成一个单像素宽的边缘。即“胖边缘”变成“瘦边缘”。如下所示:
    在这里插入图片描述
    上图中的数字代表了像素点的梯度强度,箭头方向代表了梯度方向。以第二排第三个像素点为例,由于梯度方向向上,则将这一点的强度(7)与其上下两个像素点的强度(5和4)比较,由于这一点强度最大,则保留。

  4. 双阈值筛选:通过非极大值抑制后,仍然有很多的可能边缘点,进一步的设置一个双阈值,即低阈值(minVal),高阈值(maxVal)。灰度变化大于maxVal的,设置为强边缘像素,低于minVal的,剔除。在minVal和maxVal之间的设置为弱边缘。进一步判断,如果其领域内有强边缘像素,保留,如果没有,剔除。

在这里插入图片描述

  • A 高于阈值 maxVal 所以是真正的边界点
  • B 虽然低于 maxVal 但高于minVal 并且与 A 相连,所以也被认为是真正的边界点
  • C 就会被抛弃,因为他不仅低于 maxVal 而且不与真正的边界点相连
  • D 也会被抛弃,因为低于minVal

所以选择合适的 maxVal和 minVal 对于能否得到好的结果非常重要。在这一步一些小的噪声点也会被除去,因为我们假设边界都是一些长的线段。

	image = image_read('coin.jpg')
    image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
    image = cv2.GaussianBlur(image, (3, 3), 0)
    Value = [(10, 150), (100, 200), (180, 230)]
    plt.figure(figsize=(20, 5))
    for i, (minVal, maxVal) in enumerate(Value):
        plt.subplot(1, 3, i + 1)
        edges = cv2.Canny(image, minVal, maxVal)
        edges = cv2.GaussianBlur(edges, (3, 3), 0)  # 卷积核 标准差
        plt.imshow(edges, 'gray')
        plt.title('maxVal={}\nminVal={}'.format(maxVal, minVal))
        plt.axis('off')
    plt.show()

在这里插入图片描述

二十、读取摄像头数据
  • cap.read() 返回一个布尔值(True/False)。如果帧读取的是正确的,就是 True。所以最后你可以通过检查他的返回值来查看视频文件是否已经到了结尾。有时 cap 可能不能成功的初始化摄像头设备。这种情况下上面的代码会报错
  • cap.isOpened(),来检查是否成功初始化了。如果返回值是True,那就没有问题
  • cap.get(propId) 来获得视频的一些参数信息,这里propId 可以是 0 到 18 之间的任何整数。每一个数代表视频的一个属性

在这里插入图片描述
其中的一些值可以使用 cap.set(propId,value) 来修改, value 就是你想要设置成的新值

例如,我可以使用 cap.get(3) 和 cap.get(4) 来查看每一帧的宽和高。默认情况下得到的值是 640X480。但是我们可以使用 ret=cap.set(3,320)和 ret=cap.set(4,240) 来把宽和高改成 320X240

	# 从摄像头获取图像数据
    cap = cv2.VideoCapture(0)
    # 查看是否成功获取摄像头
    if not cap.isOpened():
        exit('there is no camera exists')
    while (True):
        # ret 读取成功True或失败False
        # frame读取到的图像的内容
        # 读取一帧数据
        ret, frame = cap.read()
        # 将读取的该帧转为灰度图
        # gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
        cv2.imshow('frame', frame)
        # waitKey功能是不断刷新图像,单位ms,返回值是当前键盘按键值。即按下q退出
        # ord返回对应的ASCII数值
        if cv2.waitKey(1) == ord('q'):
            break
    cap.release()
    cv2.destroyAllWindows()
二十一、读取视频文件
	# 从文件读取视频内容
    cap = cv2.VideoCapture('cats.mp4')
    # 视频每秒传输帧数
    fps = cap.get(cv2.CAP_PROP_FPS)
    # 视频图像的宽度,get返回float类型
    frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    # 视频图像的长度
    frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    while (True):
        # ret 读取成功True或失败False
        # frame读取到的图像的内容
        # 读取一帧数据
        ret, frame = cap.read()
        if ret != True:
            break
        cv2.imshow('frame', frame)
        # waitKey功能是不断刷新图像,单位ms,返回值是当前键盘按键值
        # 如果waitkey的用于掩饰的参数太小,会导致视频播放的很快,因为程序读取一帧图像很快
        # ord返回对应的ASCII数值
        if cv2.waitKey(25) == ord('q'):
            break
    cap.release()
    cv2.destroyAllWindows()
二十二、视频写入

我们要创建一个 VideoWriter 的对象,应该确定一个输出文件的名字。接下来指定 FourCC 编码、播放频率、帧的大小

FourCC 就是一个 4 字节码,用来确定视频的编码格式。可用的编码一般为:DIVX, XVID, MJPG, X264, WMV1, WMV2

主要操作:读取一帧,翻转一帧,写入一帧

	# 从文件读取视频内容
    cap = cv2.VideoCapture('cats.mp4')
    # 视频每秒传输帧数
    fps = cap.get(cv2.CAP_PROP_FPS)
    # 视频图像的宽度
    frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    # 视频图像的长度
    frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    # 写入视频的编码方式
    fourcc = cv2.VideoWriter_fourcc(*'XVID')
    # 设置写入视频的编码、每秒帧数、每一帧的长宽,返回写入对象
    out = cv2.VideoWriter('output.avi', fourcc, fps, (frame_width, frame_height))
    while True:
        ret, frame = cap.read()
        if ret is True:
            # 0:竖直翻转,1:水平翻转,-1:表示水平 + 垂直翻转
            frame = cv2.flip(frame, 0)
            out.write(frame)
            cv2.imshow('frame', frame)
            if cv2.waitKey(1) == ord('q'):
                break
        else:
            break
    out.release()
    cap.release()
    cv2.destroyAllWindows()

这样我们就完成了一个视频的竖直翻转

  • 4
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bugcoder-9905

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值