zoukankan      html  css  js  c++  java
  • Gui Features in OpenCV

    1 Getting Started with Images

    1.1 目标

    • 学习如何读取图像、展示图像、保存图像
    • 学习函数:cv2.imread(), cv2.imshow(), cv2.imwrite()
    • 学习用 matplotlib 展示图像

    1.2 使用OpenCV

    1.2.1 读取图像

    函数 cv2.imread() 有两个参数:

    • 图像路径
    • 读取图像的方式:
      • cv2.IMREAD_COLOR: 加载色彩图像,默认flag;
      • cv2.IMREAD_GRAYSCALE: 以灰度模式(grayscale mode)加载图像;
      • cv2.IMREAD_UNCHANGED: 加载包含alpha通道(alpha channel)的图像.

    注意:以上三种状态可分别用整数 1,0 和 -1表示。

    import numpy as np
    import cv2
    
    # Load an color image in grayscale
    img = cv2.imread('messi5.jpg', 0)
    print(img)
    

    警告: 即使图像路径是错误的,它也不会报错,但是 print(img) 会给出 None.

    1.2.2 展示图像

    用 cv2.imshow() 在窗口中展示图像,窗口将自动适应图像大小。
    参数:

    • 一个字符串,表示窗口名称;
    • 读取的图像名,可以创建多个有着不同窗口名称的窗口。
    cv2.imshow('image', img)
    cv2.waitKey(0)  # 将鼠标放在图像上,然后按任意键才会停止
    cv2.destroyAllWindows()
    

    cv2.waitKey()是一个键盘绑定函数,它的参数是以毫秒(milliseconds)记的时间。这个函数对于任意键盘事件等待特定的毫秒数。如果你在那个时间按下任意键,程序继续。如果参数为0,它将无限期的等待键盘输入。它也可以设置为检测专门的键盘输入,例如键a是否被按下,这个下面将会讨论。

    cv2.destroyAllWindows()销毁我们创建的所有窗口。如果你想销毁任意指定的窗口,传递给函数cv2.destroyWindow()精确的窗口名作为参数。

    注意:有一种特定的情况,在这种情况下你已经创建了窗口,并且加载了图像。你可以指定窗口尺寸是否可以调整,这时候可以用cv2.namedWindow()函数。默认flag是cv2.WINDOW_AUTOSIZE,但是如果你指定flag是cv2.WINDOW_NORMAL,你可以调整窗口尺寸。当图像维度太大和向窗口增加轨迹条时非常有用。

    cv2.namedWindow('image', cv2.WINDOW_NORMAL)
    cv2.imshow('image', img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    

    1.2.3 保存图像

    cv2.imwrite() 第一个参数:文件名,第二个参数:保存的图像。

    cv2.imwrite('messigray.png', img)
    

    1.2.4 总结

    下面的程序演示:加载灰色图像,展示,当按下 's' 键时保存图像并退出,或者按 ESC 键不保存且退出。

    import numpy as np
    import cv2
    
    img = cv2.imread('messi5.jpg', 0)
    cv2.imshow('image', img)
    k = cv2.waitKey(0)
    if k == 27:      # wait for ESC key to exit
        cv2.destroyAllWindows()
    elif k == ord('s'):   # wait for 's' key to save and exit
        cv2.imwrite('messigray2.png', img)
        cv2.destroyAllWindows()
    

    ord()以一个字符作为参数,返回对应的ASCII数值,或者Unicode数值,如果所给的Unicode字符超出了你的Python定义范围,则会引发一个TypeError的异常。
    如果使用的是64位机器,需要修改 k = cv2.waitKey(0) 为 k = cv2.waitKey(0) & 0xFF

    1.3 使用Matplotlib

    import numpy as np
    import cv2
    from matplotlib import pyplot as plt
    
    img = cv2.imread('messi5.jpg', 0)
    plt.imshow(img, cmap='gray', interpolation = 'bicubic')
    plt.xticks([])
    plt.yticks([])     # to hide tick values on X and Y axis
    plt.show() 
    

    警告:OpenCV中加载颜色图像是 BGR 模式,而 Matplotlib 中展示图像是 RGB 模式。所以颜色图像用OpenCV读取,在Matplotlib中不会被正确展示。

    下面的例子来对比OpenCV和Matplotlib中的图像显示。

    import cv2
    import numpy as np
    import matplotlib.pyplot as plt
    
    img = cv2.imread('messi5.jpg')
    b,g,r = cv2.split(img)
    img2 = cv2.merge([r,g,b])
    
    plt.rcParams['figure.figsize'] = (12, 9)
    plt.subplot(121)
    plt.imshow(img) # expects distorted color
    plt.subplot(122)
    plt.imshow(img2) # expect true color
    plt.show()
    

    cv2.imshow('bgr image',img) # expects true color
    cv2.imshow('rgb image',img2) # expects distorted color
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    

    # 可以这样转换
    img = cv2.imread('messi5.jpg')
    img2 = img[:,:,::-1]
    
    plt.rcParams['figure.figsize'] = (12, 9)
    plt.subplot(121)
    plt.imshow(img) # expects distorted color
    plt.subplot(122)
    plt.imshow(img2) # expect true color
    plt.show()
    

    2 Getting Started with Videos

    2.1 目标

    • 学习读取视频,展示视频,保存视频
    • 学习从摄像头中抓取视频,并且展示
    • 学习函数 cv2.VideoCapture(), cv2.VideoWriter()

    2.2 用摄像头抓取视频

    我们经常要用摄像头抓取实时视频(live stream),OpenCV 对此提供了一个简单接口。让我们从摄像头中抓取一个视频,转化为灰度(grayscale)视频并展示。从一个简单的任务开始。

    抓取视频,首先要创建一个 VideoCapture 对象。它的参数可以是设备索引或者视频文件的名称。设备索引是一个确定摄像头的编号。正常情况下摄像头会被连接,所以我简单的传递0(或者-1)。你也可以通过传递1来选择第二个摄像头。之后,你可以一帧帧( frame-by-frame) 抓取。但是,最后不要忘记释放抓取。

    import numpy as np
    import cv2
    
    cap = cv2.VideoCapture(0)  # 启动电脑自带的摄像头
    
    while(True):
        # Capture frame-by-frame
        ret, frame = cap.read()
        
        # Our operations on the frame come here
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        
        # Display the resulting frame
        cv2.imshow('frame', gray)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
            
    # When everything done, release the capture
    cap.release()
    cv2.destroyAllWindows()
    

    上面的程序是一帧一帧抓取图像,然后用cv2.cvtColor()将其转化成灰色,然后展示出来。

    cap.read()返回bool类型。如果读取frame正确,返回True。所以你可以通过检查返回值来检查视频的结尾。

    有时,cap没有初始化,这种情况下代码会显示错误。你可以通过方法cap.isOpened()来检查cap是否被初始化。如果初始化了,那没问题,否则,用cap.open()打开它。

    你也可以用cap.get(propld)方法来访问视频的某些特征,propld是0到18的数字。每个数字表示视频的一个属性(如果对视频有意义),并且可以在Property Identifier看到整个细节。其中有一些数值可以用cap.set(propld, value)修改。

    例如,我可以通过cap.get(3)和cap.get(4)来检查帧(frame)的宽度(width)和高度(height),默认640x480。但是如果我想修改为320x240,只要用 ret = cap.set(3, 320) 和 ret = cap.set(4, 240)即可。

    2.3 从文件中播放视频

    可以不启用摄像头而从文件中播放视频,恰当利用 cv2.waitKey()的时间,如果太小,视频将播放的非常快,如果太大,视频会播放的非常慢(慢动作展示视频)。在正常的情况下 25 milliseconds 比较合适。

    import numpy as np
    import cv2
    
    cap = cv2.VideoCapture('vtest.mp4')
    
    while(cap.isOpened()):
        ret, frame = cap.read()
        # 这里保证获取到图像,而且必须加上,可以作为读取结束的判断,否则播放到最后一帧会出错
        if ret == True:  
            gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
            cv2.imshow('frame', gray)
            
            if cv2.waitKey(25) & 0xFF == ord('q'):
                break
        else:
            break
    
    cap.release()
    cv2.destroyAllWindows()
    

    上面的程序在windows系统下运行正常,但在Mac OSX 10.10.3中会出错,猜测是没有安装ffmpeg or gstreamer的原因(没有适合系统版本的),暂未找到解决方法。

    2.4 保存视频

    如果我们要保存图像,用函数 cv2.imwrite()即可,但在保存视频的时候,稍微麻烦一点。

    首先要创建一个 VideoWriter 对象。我们应该指定输出文件的名字(例如:output.avi),然后指定 FourCC 编码,然后是应该传递的每秒帧数和帧的尺寸,最后是 isColor 标识。如果 isColor == True, 编码器会编码成color frame,否则是是grayscale frame。

    FourCC是一个用于指定视频编码器(codec)的4字节代码,有效代码列表在fourcc.org中,它是平台依赖的,下面是编码器:

    • In Fedora: DIVX, XVID, MJPG, X264, WMV1, WMV2. (XVID is more preferable. MJPG results in high size video. X264 gives very small size video)
    • In Windows: DIVX (More to be tested and added)
    • In OSX : (I don’t have access to OSX. Can some one fill this

    FourCC 代码被传递为 cv2.VideoWriter_fourcc('M','J','P','G') 或者 cv2.VideoWriter_fourcc(*'MJPG) for MJPG.

    下面的代码从摄像头中抓取,在垂直方向flip每一帧并且保存。

    import numpy as np
    import cv2
    
    cap = cv2.VideoCapture(0)
    
    # 获取视频播放界面长宽
    width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH) + 0.5)
    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT) + 0.5)
    
    # Define the codec and create VideoWriter object
    fourcc = cv2.VideoWriter_fourcc(*'mp4v')
    out = cv2.VideoWriter('output2.mp4',fourcc, 20.0, (width, height))
    # out = cv2.VideoWriter('output3.mp4',fourcc, 20.0, (640, 480))
    
    while(cap.isOpened()):
        ret, frame = cap.read()
        if ret==True:
            frame = cv2.flip(frame,0) 
    
            # write the flipped frame
            out.write(frame)
    
            cv2.imshow('frame',frame)
            if cv2.waitKey(1) & 0xFF == ord('q'):
                break
        else:
            break
    
    # Release everything if job is finished
    cap.release()
    out.release()
    cv2.destroyAllWindows()
    

    cv2.flip() 1:水平翻转,0:垂直翻转,-1:水平垂直翻转。

    保存视频不成功,应该是fourcc = cv2.VideoWriter_fourcc(*'mp4v')编码方式的问题,对Mac OSX不友好。
    在利用了width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH) + 0.5) height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT) + 0.5),并且把编码方式修改为'mp4v',输出视频格式修改为.mp4之后就正常了,其他方式不起作用。

    3 Drawing Functions in OpenCV

    3.1 目标

    • 学习利用OpenCV绘制不同的几何形状
    • 学习函数 cv2.line(), cv2.circle(), cv2.rectangle(), cv2.ellipse(), cv2.putText()等

    3.2 代码

    上面所有的函数中,有一些通用参数,如下所示:

    • img: 你想要在其上画出形状的图像
    • color: 形状的颜色。对BGR而言,作为元组传递,例如(255,0,0)是蓝色。对于grayscale而言,仅仅传递标量值
    • thickness: 线和圆圈等的粗细。如果-1被传递给像圆圈一样的封闭图形,将会填充形状。默认thickness = 1
    • lineType: 线的类型,8连接,抗锯齿线等。默认8连接。cv2.LINE_AA给出的抗锯齿线看起来非常平滑。

    3.2.1 绘制直线

    画一条线,需要给出线的开始和结束坐标。我们将创建一个黑色图像,并且在其上从左上角到右下角画一条蓝色的线。

    import numpy as np
    import cv2
    
    # Create a black image
    img = np.zeros((512, 512, 3), np.uint8)
    
    # Drawing a diagonal blue line with thickness of 5 px
    img = cv2.line(img, (0,0), (511,511), (255,0,0), 5)
    
    cv2.imshow('image', img)
    cv2.waitKey(0)  # 将鼠标放在图像上,然后按任意键才会停止
    cv2.destroyAllWindows()
    

    3.2.2 绘制矩形

    画矩形,需要矩形的左上角和右下角坐标,我们将要在图像的右上角画一个绿色的矩形。

    img = cv2.rectangle(img, (384,0), (510,128), (0,255,0), 3)
    
    cv2.imshow('image', img)
    cv2.waitKey(0)  # 将鼠标放在图像上,然后按任意键才会停止
    cv2.destroyAllWindows()
    

    3.2.3 绘制圆

    画圆,需要中心坐标和半径。我们将要在上面的矩形中画一个圆。

    img = cv2.circle(img, (447,63), 63, (0,0,225), -1)
    
    cv2.imshow('image', img)
    cv2.waitKey(0)  # 将鼠标放在图像上,然后按任意键才会停止
    cv2.destroyAllWindows()
    

    3.2.4 绘制椭圆

    画椭圆,需要传递几个参数。1.中心位置,2.轴长度(主轴长,次轴长),3.angle:逆时针方向的椭圆旋转角度,4.startAngle和endAngle:从主轴顺时针方向开始测量的椭圆弧度的开始和结束角度,例如,0和360代表整个椭圆。对于更多的细节可以查询cv2.ellipse()的文件。下面的例子在图像的中心位置绘制了半个椭圆。

    img = cv2.ellipse(img, (256,256), (100,50), 0, 0, 180, 255, -1)
    
    cv2.imshow('image', img)
    cv2.waitKey(0)  # 将鼠标放在图像上,然后按任意键才会停止
    cv2.destroyAllWindows()
    

    3.2.5 绘制多边形

    绘制多边形,首先需要定点坐标。使这些点组成一个形如ROWS×1×2的数组,其中ROWS是顶点的数量,并且必须是int32。这里用黄色绘制四个顶点的小多边形。

    pts = np.array([[10,5], [20,30], [70,20], [50,10]], np.int32)
    pts = pts.reshape((-1, 1, 2))
    img = cv2.polylines(img, [pts], True, (0,255,255))
    
    cv2.imshow('image', img)
    cv2.waitKey(0)  # 将鼠标放在图像上,然后按任意键才会停止
    cv2.destroyAllWindows()
    

    如果第三个参数是False,将会得到一个连接所有点的多边线,而不是闭合的形状。

    cv2.polylines()可以来绘制多条线。创建一个想要绘制的所有线的列表,然后将其传递给函数。用这种方法绘制一组线相比调用cv2.line()更好更快。

    3.2.6 在图像上添加文本

    在图像中放置文本,需要指定下面的事情:

    • 文本数据
    • 放置文本的位置坐标(左上角是数据开始的位置)
    • 字体类型(通过查询cv2.putText()文档来查看支持的字体)
    • 字体刻度(指定字体的大小)
    • 通常的事情如颜色、粗细、线型等。为了更好的显示,推荐lineType=cv2.LINE_AA.

    我们将在图像中用白色写上“OpenCV”:

    font = cv2.FONT_HERSHEY_SIMPLEX
    cv2.putText(img, 'OpenCV', (10,500), font, 4, (255,255,255), 2, cv2.LINE_AA)
    
    cv2.imshow('image', img)
    cv2.waitKey(0)  # 将鼠标放在图像上,然后按任意键才会停止
    cv2.destroyAllWindows()
    

    3.3 更多资源

    在椭圆函数中用的角度不是我们的环形角度,更多细节访问这个讨论

    3.4 练习

    试着利用OpenCV中的绘图函数创建一个OpenCV logo.

    4 Mouse as a Paint-Brush

    4.1 目标

    • 学习在OpenCV中处理鼠标事件
    • 学习函数cv2.setMouseCallback()

    4.2 简单演示

    我们创建一个简单的应用,可以在图像上双击过的地方绘制圆圈。

    首先我们创建一个当鼠标事件发生时被执行的鼠标回调函数。鼠标事件可以是和鼠标相关的任何事情,比如左键按下,左键松开,左键双击。对于每个鼠标事件,会给我们一个坐标(x,y)。有了这个事件和位置,我们可以做任何喜欢的事。列出所有有效地事件,可以在Python终端运行下面的代码:

    import cv2
    
    events = [i for i in dir(cv2) if 'EVENT' in i]
    print(events)
    

    创建鼠标回调函数有一个专门的格式,不同的地方仅仅是函数的功能。所以我们的鼠标回调函数做一件事情,它就在我们双击的地方绘制一个圆圈。

    import cv2
    import numpy as np
    
    # mouse callback function
    def draw_circle(event, x, y, flags, param):
        if event == cv2.EVENT_LBUTTONDOWN:
            cv2.circle(img, (x,y), 100, (255,0,0), -1)
            
    # Create a black image, a window and bind the function to window
    img = np.zeros((512,512,3), np.uint8)
    cv2.namedWindow('image')
    cv2.setMouseCallback('image', draw_circle)
    
    while(1):
        cv2.imshow('image', img)
        if cv2.waitKey(20) & 0xFF == 27:
            break
    cv2.destroyAllWindows()
    

    将 event 为 cv2.EVENT_LBUTTONDBLCLK 修改为 cv2.EVENT_LBUTTONDOWN,才有反应。为什么?而在windows环境下不需要修改就可以成功。

    4.3 更多高级演示

    我们将要做更好的应用。在这个应用当中,我们通过像绘图应用中拖拽鼠标那样绘制矩形或者圆形(依赖于我们选择的模式)。所以我们的鼠标回调函数有两部分,一部分绘制矩形,一部分绘制圆形。这个例子将会在创建和理解许多交互式应用——如对象跟踪、图像分割——中等很有帮助。

    import cv2
    import numpy as np
    
    drawing = False  # true if mouse is pressed
    mode = True  # if True, draw rectangle. Press 'm' to toggle to curve
    ix, iy = -1, -1
    
    # mouse callback function
    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 == True:
                if mode == 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 == True:
                cv2.rectangle(img, (ix,iy), (x,y), (0,255,0), -1)
            else:
                cv2.circle(img, (x,y), 5, (0,0,255), -1)
    

    下面我们必须将这个鼠标回调函数和OpenCV窗口绑定。在主循环中,我们应该对‘m’键设置键盘绑定用于在矩形和圆形之间转换。

    img = np.zeros((512, 512, 3), np.uint8)
    cv2.namedWindow('image')
    cv2.setMouseCallback('image', draw_circle)
    
    while(1):
        cv2.imshow('image', img)
        k = cv2.waitKey(1) & 0xFF
        if k == ord('m'):
            mode = not mode
        elif k == 27:
            break
            
    cv2.destroyAllWindows()
    

    回调函数是如何执行的?循环中没有这个函数呀。

    5 Trackbar as the Color Ralette

    5.1 目标

    学习将滑动条绑定到OpenCV窗口
    学习函数cv2.getTrackbarPos(), cv2.createTrackbar()等

    5.2 代码演示

    我们将在这里创建一个简单的应用,可以展示你指定的颜色。你有一个展示颜色和指定B,G,R颜色的三个滑动条的窗口。滑动相应的滑动条,相应的,窗口颜色改变。默认,初始颜色被设为黑色。

    cv2.createTrackbar(trackbarName, windowName, value, count, onChange)
    参数:

    • trackbar name
    • window name to which it is attached
    • default value
    • maximum value
    • callback function which is executed everytime trackbar value changes

    回调函数有一个叫trackbar position的默认参数。在我们的例子中,这个函数不做任何事情,我们简单的pass掉就可以了。

    trackbar的另一个重要应用是将它作为一个button或者switch。默认,OpenCV没有button功能。所以我们可以用trackbar来实现这个功能。在我们的应用中,我们已经创建了一个switch,只有当switch是开启的时候应用才会工作,否则屏幕是黑色的。

    import cv2
    import numpy as np
    
    def nothing(x):
        pass
    
    # Create a black image, a window
    img = np.zeros((300, 512, 3), np.uint8)
    cv2.namedWindow('image')
    
    # create trackbars for color change
    cv2.createTrackbar('R', 'image', 0, 255, nothing)
    cv2.createTrackbar('G', 'image', 0, 255, nothing)
    cv2.createTrackbar('B', 'image', 0, 255, nothing)
    
    # create switch for ON/OFF functionality
    switch = '0: OFF...1: ON'
    cv2.createTrackbar(switch, 'image', 0, 1, nothing)
    
    while(1):
        cv2.imshow('image', img)
        k = cv2.waitKey(1) & 0xFF
        if k == 27:
            break
            
        # get current position of four trackbars
        r = cv2.getTrackbarPos('R', 'image')
        g = cv2.getTrackbarPos('G', 'image')
        b = cv2.getTrackbarPos('B', 'image')
        s = cv2.getTrackbarPos(switch, 'image')
        
        if s == 0:
            img[:] = 0
        else:
            img[:] = [b,g,r]
            
    cv2.destroyAllWindows()
    

    注意: Mac OSX 中运行失败,在windows下运行成功。

  • 相关阅读:
    基于 Docker 安装 RocketMQ
    167. 两数之和 II
    阿里云的使用
    自动关机程序
    C语言学习关于数据类型的一些知识点(初学者)
    关于C语言学习的一些感想(初学者)
    c# 第14节 字符方法、转义字符、字符串的方法
    c# 第13节 迭代语句、while、do...while、for、foreach、goto
    c# 第12节 分支语句if、switch、三位运算符
    c# 第11节 运算符大全
  • 原文地址:https://www.cnblogs.com/shaocf/p/9248459.html
Copyright © 2011-2022 走看看