Mango的OpenCV学习笔记【一】

本文主要参考自 OpenCV官方文档

一、图像入门操作

  1. 使用cv2.imread() 函数读取图像。
    cv2.IMREAD_COLOR: 加载彩色图像。任何图像的透明度都会被忽视。它是默认标志。
    cv2.IMREAD_GRAYSCALE:以灰度模式加载图像
    cv2.IMREAD_UNCHANGED:加载图像,包括alpha通道

    注意:除了这三个标志,你可以分别简单地传递整数1、0或-1。

    代码使用如下所示:

    import cv2
    
    # 加载彩色灰度图像
    img = cv2.imread('../../Resources/cat.jpg', 0)
    
  2. cv2.imshow() 在窗口中显示图像。窗口自动适合图像尺寸。
    第一个参数是窗口名称,它是一个字符串。

    cv2.waitKey() 是一个键盘绑定函数。其参数是以毫秒为单位的时间。

    cv2.destroyAllWindows() 只会破坏我们创建的所有窗口。

    如果要销毁任何特定的窗口,请使用函数 cv2.destroyWindow() 在其中传递确切的窗口名称作为参数。

    cv2.namedWindow('image',cv2.WINDOW_NORMAL)
    cv2.imshow('image',img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
  3. 使用 cv2.imwrite() 写入图像

    cv2.imwrite('../../Resources/cat_gray.jpg', img)
    
  4. 使用 Matplotlib 进行绘图

    import cv2
    from matplotlib import pyplot as plt
    
    img = cv2.imread('../../Resources/cat.jpg', 0)
    plt.imshow(img, cmap='gray', interpolation='bicubic')
    plt.xticks([]), plt.yticks([])  # 隐藏 x 轴和 y 轴上的刻度值
    plt.show()
    

    窗口显示图形如下Mango的OpenCV学习笔记【一】_第1张图片

二、视频入门操作

  1. 使用 cv2.VideoCapture() 捕获视频对象
    正常情况下,一个摄像头被连接,我们只需要传递0,便可逐帧捕获,当然当你有多个摄像头时,你可以传递1,2…来选择不同摄像头…

    import cv2
    
    cap = cv2.VideoCapture(0)
    while True:
        # 逐帧捕获
        ret, frame = cap.read()
        # 如果正确读取帧,ret为True
        if not ret:
            break
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        # 显示结果帧e
        cv2.imshow('frame', gray)
        if cv2.waitKey(1) == ord('q'):
            break
    # 完成所有操作后,释放捕获器
    cap.release()
    cv2.destroyAllWindows()
    
  2. 使用 cap.get(propId) 获取视频的一些功能

    param define
    cv2.VideoCapture.get(0) 视频文件的当前位置(播放)以毫秒为单位
    cv2.VideoCapture.get(1) 基于以0开始的被捕获或解码的帧索引
    cv2.VideoCapture.get(2) 视频文件的相对位置(播放):0=电影开始,1=影片的结尾。
    cv2.VideoCapture.get(3) 在视频流的帧的宽度
    cv2.VideoCapture.get(4) 在视频流的帧的高度
    cv2.VideoCapture.get(5) 帧速率
    cv2.VideoCapture.get(6) 编解码的4字-字符代码
    cv2.VideoCapture.get(7) 视频文件中的帧数
    cv2.VideoCapture.get(8) 返回对象的格式
    cv2.VideoCapture.get(9)
    cv2.VideoCapture.get(10) 图像的亮度(仅适用于照相机)
    cv2.VideoCapture.get(11) 图像的对比度(仅适用于照相机)
    cv2.VideoCapture.get(12) 图像的饱和度(仅适用于照相机)
    cv2.VideoCapture.get(13) 色调图像(仅适用于照相机)
    cv2.VideoCapture.get(14) 图像增益(仅适用于照相机)(Gain在摄影中表示白平衡提升)
    cv2.VideoCapture.get(15) 曝光(仅适用于照相机)
    cv2.VideoCapture.get(16) 指示是否应将图像转换为RGB布尔标志
    cv2.VideoCapture.get(17) × 暂时不支持
    cv2.VideoCapture.get(18) 立体摄像机的矫正标注(目前只有DC1394 v.2.x后端支持这个功能)
  3. 从文件中读取视频

    import cv2
    
    cap = cv2.VideoCapture('../../Resources/cat.mp4')
    while True:
        ret, frame = cap.read()
        # 如果正确读取帧,ret为True
        if not ret:
            break
        cv2.imshow('frame', frame)
        if cv2.waitKey(1) == ord('q'):
            break
    cap.release()
    cv2.destroyAllWindows()
    
  4. 使用 cv2.imwrite() 保存视频

    import cv2
    
    cap = cv2.VideoCapture('../../Resources/cat.mp4')
    # 获取视频帧数
    fps = cap.get(cv2.CAP_PROP_FPS)
    width = cap.get(3)
    height = cap.get(4)
    # print(width, height)
    
    # 定义编解码器并创建VideoWriter对象
    fourcc = cv2.VideoWriter_fourcc(*'mp4v')
    
    out = cv2.VideoWriter('output.mp4', fourcc, fps, (int(width), int(height)))
    while True:
        ret, frame = cap.read()
        if not ret:
            break
        frame = cv2.flip(frame, 0)
        # 写翻转的框架
        out.write(frame)
        cv2.imshow('frame', frame)
        if cv2.waitKey(1) == ord('q'):
            break
    # 完成工作后释放所有内容
    cap.release()
    out.release()
    cv2.destroyAllWindows()
    

三、对图像绘图

  1. 使用 cv2.line() 画线
  2. 使用 cv2.rectangle() 画矩形
  3. 使用 cv2.circle() 画圆
  4. 使用 cv2.ellipse() 画椭圆
  5. 使用 cv2.polylines() 画多边形
  6. 使用 cv2.putText() 添加文字
    import cv2
    import numpy as np
    
    # 直线、矩形、圆、椭圆、多边形、写文字
    img = cv2.imread(r"../../Resources/cat.jpg")
    cv2.line(img, (0, 0), (50, 50), (0, 0, 255), thickness=3)
    cv2.rectangle(img, (100, 30), (210, 180), (0, 255, 0), thickness=1)
    cv2.circle(img, (100, 100), 100, (255, 0, 0), thickness=3)
    cv2.ellipse(img, (200, 200), (100, 100), 0, 180, 300, (0, 255, 255), thickness=-1)
    
    # 多边形
    # 定义n个顶点坐标
    pts = np.array([[100, 100], [200, 150], [180, 150], [210, 450], [100, 150]])
    # img – 要画的图片
    # pts – 多边形的顶点
    # isClosed – 是否闭合线段
    # color – 颜色
    cv2.polylines(img, [pts], 1, (255, 0, 255), thickness=3)
    
    font = cv2.FONT_HERSHEY_SIMPLEX
    cv2.putText(img, 'OpenCV', (10, 300), font, 1, (255, 255, 255), 2, cv2.LINE_AA)
    
    cv2.imshow("pic show", img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    

四、PIL与OpenCV的相互转换操作

  1. 通道切割与合并
    import cv2
    import numpy as np
    import PIL.Image as Image
    
    img_arr = cv2.imread("../../Resources/beautiful_girl.jpg")
    print(img_arr.shape)
    
    # 通道切割
    b = img_arr[:, :, 0:1]
    g = img_arr[:, :, 1:2]
    r = img_arr[:, :, 2:]
    print(b.shape, g.shape, r.shape)
    
    # 通道合并
    arr = np.concatenate((r, g, b), axis=2)
    print(arr.shape)
    
    # 用OpenCV显示图像,此时通道为 RGB,而非OpenCV默认通道 BGR
    cv2.imshow("arr_img", arr)
    cv2.waitKey(0)
    
    # 使用PIL显示图像,此时通道为RGB
    img = Image.fromarray(arr)
    img.show()
    
    # 通道切割
    b, g, r = cv2.split(img_arr)
    # 通道合并
    new_img = cv2.merge([b, g, r])
    
    zeros = np.zeros([img_arr.shape[0], img_arr.shape[1]], dtype=np.uint8)
    # print(zeros)
    
    # 通道合并
    img_b = cv2.merge([b, zeros, zeros])
    img_g = cv2.merge([zeros, g, zeros])
    img_r = cv2.merge([zeros, zeros, r])
    
    new_img[..., 0] = 255
    new_img[..., 1] = 0
    new_img[..., 2] = 255
    
    cv2.imshow("new_img", new_img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
  2. PIL与OpenCV的转换
    from PIL import Image
    import cv2
    import numpy as np
    
    '从PIL转到opencv'
    # PIL打开的图像是RGB通道
    img = Image.open("../../Resources/beautiful_girl.jpg")
    # img = cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)
    
    img_arr = np.array(img)
    img_arr = img_arr[..., ::-1]
    
    # opencv显示的图像是BGR通道
    cv2.imshow("PIL->OpenCv", img_arr)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    '从opencv转到PIL'
    # opencv打开的图像是BGR通道
    img_arr = cv2.imread("../../Resources/beautiful_girl.jpg")
    # img = Image.fromarray(cv2.cvtColor(img_arr,cv2.COLOR_BGR2RGB))
    # print(img_arr)
    
    img_arr = img_arr[..., ::-1]
    
    # PIL显示的图像是RGB通道
    img = Image.fromarray(img_arr)
    
    img.show()
    
    cv2.imshow("opencv_img", np.array(img))
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
  3. 生成验证码(练习题)
    from PIL import Image, ImageDraw, ImageFont
    import random
    
    
    # import codecs
    
    # 汉字生成 1
    def unicode_():
        val = random.randint(0x4E00, 0x9FBF)
        return chr(val)
    
    
    # 汉字生成 2
    def gbk2312_():
        head = random.randint(0xb0, 0xf7)
        body = random.randint(0xa1, 0xfe)
        val = f'{head:x} {body:x}'
        str_ = bytes.fromhex(val).decode('gb2312')
        return str_
    
    
    # 随机字符
    def rand_char():
        digital = chr(random.randint(48, 57))
        upper = chr(random.randint(65, 90))
        lower = chr(random.randint(97, 122))
    
        # return random.choice([digital, upper, lower])
        return random.choice([digital, upper, lower, gbk2312_(), unicode_()])
    
    
    # 随机背景颜色
    def rand_bg_color():
        bg_r = random.randint(128, 255)
        bg_g = random.randint(128, 255)
        bg_b = random.randint(128, 255)
        return bg_r, bg_g, bg_b
    
    
    # 随机字体颜色
    def rand_font_color():
        font_r = random.randint(0, 127)
        font_g = random.randint(0, 127)
        font_b = random.randint(0, 127)
        return font_r, font_g, font_b
    
    
    # 空白画布生成
    def draw_canvas(width, height):
        image = Image.new("RGB", (width, height), (255, 255, 255, 0))
        return image
    
    
    # 字体设置、绘图
    def canvas(width, height):
        font = ImageFont.truetype('msyh.ttc', 40)
        img = draw_canvas(width, height)
        draw = ImageDraw.Draw(img)
        return font, img, draw
    
    
    # 背景图片生成
    def bg_generate(width, height):
        font, img, draw = canvas(width, height)
        for i in range(width):
            for j in range(height):
                draw.point((i, j), fill=rand_bg_color())
        img.save('../Image/bg.png')
    
    
    def noise(pic_width, pic_height):
        font, img, draw = canvas(pic_width, pic_height)
        for i in range(10):
            draw.line(
                (random.randint(0, pic_width), random.randint(0, pic_height),
                 random.randint(0, pic_width), random.randint(0, pic_height)),
                fill="black", width=1
            )
        return img
    
    
    # 单个验证码图片生成
    def single_code(code_width, code_height, pic_index):
        font, img, draw = canvas(code_width, code_height)
        for i in range(code_width):
            for j in range(code_height):
                draw.point((i, j), fill=rand_bg_color())
        draw.text((random.randint(0, 1), random.randint(-10, -5)),
                  rand_char(), fill=rand_font_color(), font=font)
        img.save('../Image/Single_Code/single_code_{}.png'.format(pic_index + 1))
    
    
    # 单验证码图片去除背景
    def del_single_bg(img):
        img = img.convert('RGBA')
        sp = img.size
        width = sp[0]
        height = sp[1]
        # print(sp)
        for yh in range(height):
            for xw in range(width):
                dot = (xw, yh)
                color_d = img.getpixel(dot)
                # print(color_d)
                # print('*' * 100)
                if color_d[0] >= 128 and color_d[1] >= 128 and color_d[2] >= 128:
                    color_d = (255, 255, 255, 0)
                    img.putpixel(dot, color_d)
                    # print(color_d)
        # img.show()
        img = img.rotate(random.randint(-60, 60), expand=True)
        return img
    
    
    # 验证码图片合成
    def verify_code_com(bg_pic, code_pic, k):
        bg_pic.paste(code_pic, (60 * k + random.randint(0, 5), random.randint(0, 5)), mask=code_pic)
        return bg_pic
    
    
    def verification_code(pic_width, pic_height, code_width, code_height):
        bg_generate(pic_width, pic_height)
        # bg = Image.open('bg.png')
        new_pic = ''
        for i in range(4):
            if i == 0:
                new_pic = Image.open('../Image/bg.png')
            else:
                new_pic = Image.open('../Image/Code_Image/code_{}.png'.format(i))
            single_code(code_width, code_height, i)
            image = Image.open('../Image/Single_Code/single_code_{}.png'.format(i + 1))
            pic = del_single_bg(image)
            pic.save('../Image/Del_Single_Code/del_single_pic_{}.png'.format(i + 1))
            c_pic = Image.open('../Image/Del_Single_Code/del_single_pic_{}.png'.format(i + 1))
            new_pic = verify_code_com(new_pic, c_pic, i)
            new_pic.save('../Image/Code_Image/code_{}.png'.format(i + 1))
        return new_pic
    
    
    if __name__ == '__main__':
        p_width = 240
        p_height = 80
        c_width = 60
        c_height = 60
        for x in range(5):
            image_ = verification_code(p_width, p_height, c_width, c_height)
            draw_ = ImageDraw.Draw(image_)
            for a in range(10):
                draw_.line(
                    (random.randint(0, p_width), random.randint(0, p_height),
                     random.randint(0, p_width), random.randint(0, p_height)),
                    fill="black", width=1
                )
            image_.save('../Image/Verification_Code/Verification_code_{}.png'.format(x))
        # image.show()
    
    效果图如下(可自行修改,这里生成的图片包含汉字、数字、字母):在这里插入图片描述

五、将鼠标作为画笔(选学)

  1. 列出鼠标所有的可用事件
    import cv2
    
    events = [i for i in dir(cv2) if 'EVENT' in i]
    print(events)
    
  2. 创建一个鼠标回调函数,在双击的地方画圆
    import cv2
    import numpy as np
    
    events = [i for i in dir(cv2) if 'EVENT' in i]
    print(events)
    
    
    def draw_circle(event, x, y, flags, param):
        if event == cv2.EVENT_LBUTTONDBLCLK:
            cv2.circle(img, (x, y), 100, (255, 0, 0), -1)
    
    
    # 创建一个黑色的图像,一个窗口,并绑定到窗口的功能
    img = np.zeros((512, 512, 3), np.uint8)
    cv2.namedWindow('image')
    cv2.setMouseCallback('image', draw_circle)
    while True:
        cv2.imshow('image', img)
        if cv2.waitKey(20) & 0xFF == 27:
            break
    cv2.destroyAllWindows()
    
  3. 高级演示
    鼠标回调函数有两部分,一部分用于绘制矩形,另一部分用于绘制圆形。
    import cv2
    import numpy as np
    
    drawing = False  # 如果按下鼠标,则为真
    mode = True  # 如果为真,绘制矩形。按 m 键可以切换到曲线
    ix, iy = -1, -1
    
    
    # 鼠标回调函数
    def draw_circle(event, x, y, flags, param):
        global ix, iy, drawing, mode
        if event == cv2.EVENT_LBUTTONDOWN:
            drawing = True
            ix, iy = x, y
        elif event == cv2.EVENT_MOUSEMOVE:
            if drawing is True:
                if mode is True:
                    cv2.rectangle(img, (ix, iy), (x, y), (0, 255, 0), -1)
                else:
                    cv2.circle(img, (x, y), 5, (0, 0, 255), -1)
        elif event == cv2.EVENT_LBUTTONUP:
            drawing = False
            if mode is True:
                cv2.rectangle(img, (ix, iy), (x, y), (0, 255, 0), -1)
            else:
                cv2.circle(img, (x, y), 5, (0, 0, 255), -1)
    
    
    # 创建一个黑色的图像,一个窗口,并绑定到窗口的功能
    img = np.zeros((512, 512, 3), np.uint8)
    cv2.namedWindow('image')
    cv2.setMouseCallback('image', draw_circle)
    while True:
        cv2.imshow('image', img)
        if cv2.waitKey(20) & 0xFF == 27:
            break
    cv2.destroyAllWindows()
    

六、 将轨迹栏作为调色器(选学)

  1. 对于 cv2.getTrackbarPos() 函数:
    ① 第一个参数是轨迹栏名称
    ② 第二个参数是它附加到的窗口名称
    ③ 第三个参数是默认值
    ④ 第四个参数是最大值
    ⑤ 第五个是执行的回调函数每次跟踪栏值更改。
    回调函数始终具有默认参数,即轨迹栏位置。在我们的例子中,函数什么都不做,所以我们简单地通过。

    图像堆叠函数:

    """图像堆叠"""
    import cv2
    import numpy as np
    
    
    def stack_images(scale, img_array):
        rows = len(img_array)
        cols = len(img_array[0])
        rows_available = isinstance(img_array[0], list)
        width = img_array[0][0].shape[1]
        height = img_array[0][0].shape[0]
        if rows_available:
            for x in range(0, rows):
                for y in range(0, cols):
                    if img_array[x][y].shape[:2] == img_array[0][0].shape[:2]:
                        img_array[x][y] = cv2.resize(img_array[x][y], (0, 0), None, scale, scale)
                    else:
                        img_array[x][y] = cv2.resize(img_array[x][y], (img_array[0][0].shape[1], img_array[0][0].shape[0]),
                                                     None, scale, scale)
                    if len(img_array[x][y].shape) == 2:
                        img_array[x][y] = cv2.cvtColor(img_array[x][y], cv2.COLOR_GRAY2BGR)
            image_blank = np.zeros((height, width, 3), np.uint8)
            hor = [image_blank] * rows
            for x in range(0, rows):
                hor[x] = np.hstack(img_array[x])
            ver = np.vstack(hor)
        else:
            for x in range(0, rows):
                if img_array[x].shape[:2] == img_array[0].shape[:2]:
                    img_array[x] = cv2.resize(img_array[x], (0, 0), None, scale, scale)
                else:
                    img_array[x] = cv2.resize(img_array[x], (img_array[0].shape[1], img_array[0].shape[0]), None, scale,
                                              scale)
                if len(img_array[x].shape) == 2:
                    img_array[x] = cv2.cvtColor(img_array[x], cv2.COLOR_GRAY2BGR)
            hor = np.hstack(img_array)
            ver = hor
        return ver
    
    

    调色板:

    """图片颜色轨迹检测、调参"""
    import cv2
    import numpy as np
    from OpenCv_Review.Part_1.Chapter6_Trackbar_Operation.section1_stack import stack_images
    
    
    def empty(a):
        pass
    
    
    path = '../../Resources/Maserati.jpg'
    cv2.namedWindow("TrackBars")
    cv2.resizeWindow("TrackBars", 640, 240)
    cv2.createTrackbar("Hue Min", "TrackBars", 0, 179, empty)
    cv2.createTrackbar("Hue Max", "TrackBars", 19, 179, empty)
    cv2.createTrackbar("Sat Min", "TrackBars", 110, 255, empty)
    cv2.createTrackbar("Sat Max", "TrackBars", 240, 255, empty)
    cv2.createTrackbar("Val Min", "TrackBars", 153, 255, empty)
    cv2.createTrackbar("Val Max", "TrackBars", 255, 255, empty)
    
    while True:
        img = cv2.imread(path)
        imgHSV = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
        h_min = cv2.getTrackbarPos("Hue Min", "TrackBars")
        h_max = cv2.getTrackbarPos("Hue Max", "TrackBars")
        s_min = cv2.getTrackbarPos("Sat Min", "TrackBars")
        s_max = cv2.getTrackbarPos("Sat Max", "TrackBars")
        v_min = cv2.getTrackbarPos("Val Min", "TrackBars")
        v_max = cv2.getTrackbarPos("Val Max", "TrackBars")
        # print(h_min, h_max, s_min, s_max, v_min, v_max)
        lower = np.array([h_min, s_min, v_min])
        upper = np.array([h_max, s_max, v_max])
        mask = cv2.inRange(imgHSV, lower, upper)
        imgResult = cv2.bitwise_and(img, img, mask=mask)
    
        # cv2.imshow("Original",img)
        # cv2.imshow("HSV",imgHSV)
        # cv2.imshow("Mask", mask)
        # cv2.imshow("Result", imgResult)
    
        imgStack = stack_images(0.6, ([img, imgHSV], [mask, imgResult]))
        cv2.imshow("Stacked Images", imgStack)
        if cv2.waitKey(20) & 0xFF == 27:
            break
    cv2.destroyAllWindows()
    

    效果图如下:Mango的OpenCV学习笔记【一】_第2张图片

你可能感兴趣的:(OpenCV,opencv,python,计算机视觉)