图像处理库OpenCV安装与使用

2019-05-09  本文已影响0人  Byte猫

OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉库,可以运行在Linux、Windows、Android和Mac OS操作系统上。它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。
官方文档

安装

pip install opencv-python 
pip install opencv-contrib-python  # 安装opencv-contrib,包含一些其它库,比如xfeature2d

在安装后通过在python控制台中输入"import cv2"命令可以验证是否成功安装

使用OpenCV

1、图像的存取

import cv2 as cv
# 读取彩色图像
img = cv.imread('test.jpg')  # 读取后直接就是numpy数组的形式
# 直接读取单通道灰度图
gray_img = cv.imread('test.jpg', cv.IMREAD_GRAYSCALE)
# 彩色图变为灰度图
# gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# 灰度图像二值化
# threshold = 155
# _, binary_image = cv.threshold(gray_img, threshold, 255, cv.THRESH_BINARY)  # 超过阈值的像素值修改成设定值,其他值为0

# 输出图片信息
print('彩色图片尺寸:', img.shape)
print('彩色图片数据:', type(img), img)
print('灰度图片尺寸:', gray_img.shape)
print('灰度图片数据:', type(gray_img), gray_img)

把单通道图片保存后,再读取,仍然是3通道,相当于把单通道值复制到3个通道保存

cv.imwrite('test_gray.jpg', gray_img)
reload_grayimg = cv.imread('test_gray.jpg')
print(reload_grayimg.shape)

保存图像时还可以根据需要控制文件大小

# IMWRITE_JPEG_QUALITY指定jpg质量,范围0到100,默认95,越高画质越好,文件越大
cv.imwrite('test_imwrite.jpg', color_img, (cv.IMWRITE_JPEG_QUALITY, 80))
# IMWRITE_PNG_COMPRESSION指定png质量,范围0到9,默认3,越高文件越小,画质越差
cv.imwrite('test_imwrite.png', color_img, (cv.IMWRITE_PNG_COMPRESSION, 5))

2、图像显示

cv.imshow('picture show', img)
cv.waitKey(0)
if k == 27:          # wait for ESC key to exit
    cv.destroyAllWindows()
elif k == ord('s'):   # wait for 's' key to save and exit
    cv.imwrite('mypic.png', img)
    cv.destroyAllWindows()

需要注意的是opencv加载的图像色彩通道是BGR不是RGB,如果想要用matplotlib进行显示,需要进行转换

import matplotlib.pyplot as plt

# 改变颜色 (from BGR to RGB)
img = cv.cvtColor(img, cv.COLOR_BGR2RGB)
plt.imshow(img)
plt.xticks([]), plt.yticks([])  # to hide tick values on X and Y axis
plt.show()

3、色度、饱和度、明度

调整色度

# 通过cvtColor把图像从BGR转换到HSV
img_hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)

# H空间中,绿色比黄色的值高一点,所以给每个像素+15,黄色的树叶就会变绿
turn_green_hsv = img_hsv.copy()
turn_green_hsv[:, :, 0] = (turn_green_hsv[:, :, 0]+15) % 180
turn_green_img = cv.cvtColor(turn_green_hsv, cv.COLOR_HSV2BGR)

调整饱和度

# 减小饱和度会让图像损失鲜艳,变得更灰
colorless_hsv = img_hsv.copy()
colorless_hsv[:, :, 1] = 0.5 * colorless_hsv[:, :, 1]
colorless_img = cv.cvtColor(colorless_hsv, cv.COLOR_HSV2BGR)

调整明度

# 减小明度为原来一半
darker_hsv = img_hsv.copy()
darker_hsv[:, :, 2] = 0.5 * darker_hsv[:, :, 2]
darker_img = cv.cvtColor(darker_hsv, cv.COLOR_HSV2BGR)

4、图像变换

图像缩放

# 指定大小,缩放成 (width, height)的图像
img_resize = cv.resize(img, (200, 200))

# 按照50%比例缩放, interpolation表示使用何种差值方式对图像进行缩放
# INTER_NEAREST为采用最近邻插值
# INTER_LINEAR为双线性插值,默认情况使用
# INTER_NEAREST为最邻近插值
# INTER_AREA使用像素区域关系重新采样,和INTER_NEAREST相似
# INTER_CUBIC采用4x4像素邻域内的双立方插值
img_resize = cv.resize(img, (0, 0), fx=0.5, fy=0.5, interpolation=cv.INTER_NEAREST)

图像旋转

def rotate_bound(image, angle):
    '''
    图像旋转
    INPUT -> 图像数组, 旋转角度(顺时针)
    '''
    (h, w) = image.shape[:2]

    # 旋转中心点
    (cX, cY) = (w // 2, h // 2)

    # 获得旋转矩阵
    M = cv.getRotationMatrix2D((cX, cY), -angle, 1.0)
    #theta = angle * np.pi / 180
    #M = np.array([
    #    [np.cos(theta), -np.sin(theta), 0],
    #    [np.sin(theta), np.cos(theta), 0]
    #], dtype=np.float32)

    cos = np.abs(M[0, 0])
    sin = np.abs(M[0, 1])

    # 计算图像新外接框
    nW = int((h * sin) + (w * cos))
    nH = int((h * cos) + (w * sin))

    M[0, 2] += (nW / 2) - cX
    M[1, 2] += (nH / 2) - cY

    return cv.warpAffine(image, M, (nW, nH))

img2 = rotate_bound(img, 45)

图像截取

# 直接截取
dst = img[10:600, 10:400]

# 沿着横纵轴放大1.6倍,然后平移(-150,-240),最后按原图大小截取,等效于裁剪并放大
M = np.array([
    [1.6, 0, -150],
    [0, 1.6, -240]
], dtype=np.float32)
dst = cv.warpAffine(img, M, (img.shape[1], img.shape[0]))

图像移位

M = np.array([
    [1, 0, -150],
    [0, 1, -240]
], dtype=np.float32)
dst = cv2.warpAffine(img, M, (height,width))

5、摄像头、视频的读取以及保存

打开摄像头并保存视频

# coding = utf-8
import numpy as np
import cv2 as cv
import time

def video_save(num_frames, filepath, out_fps):
    '''
    打开摄像头并保存视频
    INPUT -> 捕获总帧数, 视频保存路径, 输出帧率
    '''
    
    cap = cv.VideoCapture(0)  # VideoCapture(0)表示打开默认的相机
    if cap.isOpened() is False:   # 确认摄像头是否成功打开
        print('Error')
        exit(1)

    # 获取捕获的分辨率
    size = (int(cap.get(cv.CAP_PROP_FRAME_WIDTH)),
            int(cap.get(cv.CAP_PROP_FRAME_HEIGHT)))
    # 设置要保存视频的编码,分辨率和帧率
    video = cv.VideoWriter(
        filepath,
        cv.VideoWriter_fourcc('M', 'P', '4', '2'),   # 视频编码格式参考:http://www.fourcc.org/codecs.php
        out_fps,   # 输出文件的帧率
        size
    )

    for i in range(num_frames):
        ret, frame = cap.read()
        video.write(frame)
        # time.sleep(interval)  捕获图像的间隔(秒)

    # 释放资源并写入视频文件
    video.release()
    cap.release()


video_save(100, '100000.avi', 24)
def video_save2(key, window_name, path, out_fps):
    '''
    打开摄像头并保存视频(不限定总帧数,直到按下某键)
    INPUT -> 按键, 窗口名, 视频保存路径, 输出帧率
    '''
    cv.namedWindow(window_name) # 创建一个窗口

    cap = cv.VideoCapture(0)  # VideoCapture(0)表示打开默认的相机
    if cap.isOpened() is False:   # 确认摄像头是否成功打开
        print('Error')
        exit(1)

    # 获取捕获的分辨率
    size = (int(cap.get(cv.CAP_PROP_FRAME_WIDTH)),
            int(cap.get(cv.CAP_PROP_FRAME_HEIGHT)))
    # 设置要保存视频的编码,分辨率和帧率
    video = cv.VideoWriter(
        path,
        cv.VideoWriter_fourcc('M', 'P', '4', '2'),   # 视频编码格式参考:http://www.fourcc.org/codecs.php
        out_fps,   # 输出文件的帧率
        size
    )

    while True:
        ret, frame = cap.read()
        video.write(frame)

        cv.imshow(window_name, frame) # 将图像矩阵显示在一个窗口中
        if cv.waitKey(20) & 0xFF == ord(key): # 每隔20ms采集一帧,按某键退出采集
            break

    # 释放资源并写入视频文件
    video.release()
    cap.release()
    cv.destroyWindow(window_name)

video_save2('k', 'test window', '100001.avi', 24)

间隔读取视频文件中的每帧的图片

def video_extraction(filepath, interval):
    '''
    视频帧提取
    INPUT -> 视频地址, 帧间隔
    '''
    if not os.path.exists(os.path.abspath(filepath) +"_extraction"):
        os.mkdir(os.path.abspath(filepath) +"_extraction")
    cap = cv.VideoCapture()

    cap.open(filepath)
    # 获取视频帧数
    num_frames = int(cap.get(cv.CAP_PROP_FRAME_COUNT))

    for i in range(num_frames):
        ret, frame = cap.read()
        if i % interval == 0:  # 每隔interval帧进行一次截屏操作
            imagepath = os.path.abspath(filepath) +"_extraction\ " + str(i)+".jpg"
            print('导出 {}!'.format(imagepath))
            cv.imwrite(imagepath, frame)

    # 执行结束释放资源
    cap.release()

video_extraction('100001.avi', 10)
上一篇下一篇

猜你喜欢

热点阅读