Python OpenCV #2 - OpenCV中的GUI功能

本文pdf下载链接:https://download.csdn.net/download/2301_81176265/89134597

一、开始使用图像

原作者:Ana Huamán
兼容性:OpenCV >= 3.4.4

警告:

本教程可能包含过时的信息。

1.1 目标

在本教程中,您将学习如何:

  • 从文件中读取图像(使用cv::imread
  • 在OpenCV窗口中显示图像(使用cv::imshow
  • 将图像写入文件(使用cv::imwrite

1.2 源代码

下载代码:点击这里

代码一览:

import cv2 as cv
import sys

img = cv.imread("starry_night.jpg")

if img is None:
    sys.exit("Could not read the image.")

cv.imshow("Display window", img)
k = cv.waitKey(0)
 
if k == ord("s"):
    cv.imwrite("starry_night.png", img)

1.3 讲解

第一步,导入OpenCV python库。正确的方法是给它另外分配一个名称cv,下面将使用这个名称来引用这个库。

import cv2 as cv
import sys

现在,让我们分析主要代码。作为第一步,我们用OpenCV读取图像“starry_night.jpg”。为此,调用cv::imread函数使用第一个参数指定的文件路径加载图像。第二个参数是可选的,它指定了我们想要的图像格式。这可能是:

  • IMREAD_COLOR :以BGR 8位格式加载图像。这是这里使用的 默认
  • IMREAD_UNCHANGED :按原样加载图像,包括Alpha通道(如果存在)
  • IMREAD_GRAYSCALE :将图像作为强度图像加载

读取后,图像数据将存储在cv::Mat对象中。

img = cv.imread("starry_night.jpg")

注意:

OpenCV提供对图像格式Windows位图(bmp)、便携式图像格式(pbm、pgm、ppm)和Sun光栅(sr、ras)的支持。

在插件的帮助下(如果您自己构建库,您需要指定使用它们,但是在我们默认提供的软件包中),您还可以加载JPEG(jpeg,jpg,jpe),JPEG 2000(jp 2-在CMake中代号为Jasper),TIFF文件(tiff,tif)和便携式网络图形(png)等图像格式。

此外,OpenEXR也是一种可能性。

然后,如果图像被正确加载,则执行检查。

if img is None:
    sys.exit("Could not read the image.")    

然后,通过调用cv::imshow函数显示图像。第一个参数是窗口的标题,第二个参数是将要显示的cv::Mat对象。

因为我们希望我们的窗口一直显示到用户按下一个键(否则程序会很快结束),所以我们使用cv::waitKey函数,它唯一的参数是它应该等待用户输入多长时间(以毫秒为单位)。零意味着永远等待。返回值是按下的键。

cv.imshow("Display window", img)
k = cv.waitKey(0)

最后,如果按下的键是“s”键,则图像被写入.png文件。为此,调用cv::imwrite函数,该函数将文件路径和cv::Mat对象作为参数。

if k == ord("s"):
    cv.imwrite("starry_night.png", img)

二、开始使用视频

2.1 目标

  • 了解如何读取视频、显示视频和保存视频。
  • 学习从摄像头捕获视频并显示它。
  • 您将学习这些函数:cv.VideoCapture()cv.VideoWriter()

2.2 从摄像头捕获视频

下载代码:点击这里

通常,我们必须用相机捕捉实时流。OpenCV提供了一个非常简单的接口来实现这一点。让我们从摄像头捕捉视频(我使用笔记本电脑上的内置网络摄像头),将其转换为灰度视频并显示。这只是一个简单的任务。

要捕获视频,您需要创建一个 VideoCapture 对象。它的参数可以是设备索引或视频文件的名称。设备索引只是指定哪个相机的数字。通常会连接一台相机(就像我的情况一样)。所以我只传递0(或-1)。您可以通过传递1等来选择第二个相机。

之后,您可以逐帧捕获。但在最后,不要忘记释放捕获。

import numpy as np
import cv2 as cv
 
cap = cv.VideoCapture(0)
if not cap.isOpened():
    print("无法打开摄像头")
    exit()
while True:
    # 逐帧捕获
    ret, frame = cap.read()
 
    # 如果正确捕获,ret为True
    if not ret:
        print("Can't receive frame (stream end?). Exiting ...")
        break
    # 操作来到这里
    gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
    # 显示捕获结果
    cv.imshow('frame', gray)
    if cv.waitKey(1) == ord('q'):
        break
 
# 当所有事情做完时,释放捕获
cap.release()
cv.destroyAllWindows()

cap.read() 返回一个bool(True/False)。如果帧读取正确,则为True。因此,您可以通过检查此返回值来检查视频的结尾。

有时,cap可能没有初始化捕获。在这种情况下,此代码显示错误。您可以通过方法 cap.isOpened() 检查它是否已初始化。如果是True,那就可以。否则改为使用 cap.open() 打开它。

您还可以使用 cap.get(propId) 方法访问此视频的一些功能,其中propId是从0到18的数字。每个数字表示视频的属性(如果它适用于该视频)。完整的细节可以在这里看到:cv::VideoCapture::get()。其中一些值可以使用 cap.set(propId,value) 修改。值是您想要的新值。

例如,我可以通过cap.get(cv.CAP_PROP_FRAME_WIDTH)cap.get(cv.CAP_PROP_FRAME_HEIGHT)检查框架的宽度和高度。它默认为640x480。但我想把它修改成320x240。使用ret = cap.set(cv.CAP_PROP_FRAME_WIDTH, 320)ret = cap.set(cv.CAP_PROP_FRAME_HEIGHT, 240)

注意:

如果你得到错误,确保你的相机在使用任何其他相机应用程序(如Linux的Cheese)时是正常工作。

2.3 从文件播放视频

下载代码(视频也在其中):点击这里

从文件中播放视频与从相机中捕获视频相同,只需将相机索引更改为视频文件名。此外,在显示帧时,为cv.waitKey()使用适当的时间。如果它太小,视频将非常快,如果它太高,视频将很慢(好吧,这就是如何以慢动作显示视频的方法)。正常情况下25毫秒就可以了。

import numpy as np
import cv2 as cv
 
cap = cv.VideoCapture('vtest.avi')

while cap.isOpened():
    ret, frame = cap.read()

    # 如果正确捕获,ret为True
    if not ret:
        print("无法捕获帧(播放结束?)正在退出...")
        break
    gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)

    cv.imshow('frame', gray)
    if cv.waitKey(1) == ord('q'):
        break

cap.release()
cv.destroyAllWindows()

注意:

确保安装了正确版本的ffmpeg或gstreamer。有时使用视频捕获是一件令人头痛的事情,主要是由于错误安装ffmpeg/gstreamer。

2.4 保存视频

下载代码:点击这里

我们捕获一个视频,并逐帧处理它,想保存这个视频。对于图像,它非常简单:只需使用cv.imwrite()。在这里,需要多做一点工作。

这一次我们创建一个 VideoWriter 对象。我们应该指定输出文件名(例如:output.avi)。然后我们应该指定 FourCC 代码(细节在下一段中)。然后应该传递每秒帧数(fps)和帧大小。最后一个是isColor标志。如果它是 True ,编码器期望彩色帧,否则它与灰度帧一起工作。

FourCC是用于指定视频编解码器的4字节代码。可用代码的列表可以在fourcc.org中找到。它依赖于平台。下面的解码器对我来说很好用。

  • 在Fedora中:DIVX,XVID,MJPG,X264,WMV1,WMV2. (XVID更优选。MJPG会产生大尺寸视频。X264提供非常小尺寸的视频)
  • 在Windows中:DIVX(更多内容有待测试和添加)
  • 在OSX中:MJPG(.mp4),DIVX(.avi),X264(.mpeg)。

对于MJPG,FourCC代码作为cv.VideoWriter_fourcc('M', 'J', 'P', 'G')orcv.VideoWriter_fourcc('MJPG')传递。

下面的代码从摄像头捕获,在垂直方向上翻转每一帧,并保存视频。

import numpy as np
import cv2 as cv
 
cap = cv.VideoCapture(0)
 
# 定义编解码器并创建VideoWriter对象
fourcc = cv.VideoWriter_fourcc(*'XVID')
out = cv.VideoWriter('output.avi', fourcc, 20.0, (640, 480))
 
while cap.isOpened():
    ret, frame = cap.read()
    if not ret:
        print("无法捕获帧(播放结束?)正在退出...")
        break
    frame = cv.flip(frame, 0)

    # 写入翻转的帧
    out.write(frame)
    
    cv.imshow('frame', frame)
    if cv.waitKey(1) == ord('q'):
        break
 
# 如果工作完成,释放所有内容内容
cap.release()
out.release()
cv.destroyAllWindows()

三、OpenCV中的绘图函数

3.1 目标

  • 学习使用OpenCV绘制不同的几何形状。
  • 您将学习这些函数:cv.line()、cv.circle()、cv.rectangle()、cv.ellipse()、cv.putText()等。

3.2 代码

在所有上述函数中,您将看到下面给出的一些常见参数:

  • img:您要绘制形状的图像。
  • color:形状的颜色。对于BGR,将其作为元组传递,例如:(255,0,0)表示蓝色。对于灰度,只需传递标量值。
  • thickness:线或圆等的厚度。如果为闭合图形(如圆)传递-1,它将填充形状。默认厚度 = 1。
  • lineType:线的类型,是否为8连、抗锯齿线等,默认为8连。cv.LINE_AA提供了抗锯齿的线条,看起来非常适合曲线。

3.3 画线

要绘制一条直线,您需要传递直线的起始和结束坐标。我们将创建一个黑色图像,并在其上从左上角到右下角绘制一条蓝线。

import numpy as np
import cv2 as cv
 
# 创建一个黑色背景
img = np.zeros((512, 512, 3), np.uint8)
 
# 画一条5像素粗的蓝色斜线
cv.line(img, (0, 0), (511, 511), (255, 0, 0), 5)

3.4 绘制矩形

要绘制矩形,需要矩形的左上角和右下角。这次我们将在图像的右上角绘制一个绿色矩形。

# 画一条3像素粗的绿色空心矩形
cv.rectangle(img, (384, 0), (510, 128), (0, 255, 0), 3)

3.5 画圆

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

# 画一个红色的实心圆
cv.circle(img, (447, 63), 63, (0, 0, 255), -1)

3.6 绘制椭圆

要绘制椭圆,我们需要传递几个参数。一个参数是中心位置(x,y)。下一个参数是轴的长度(长轴, 短轴)。角度是椭圆逆时针方向旋转的角度。

startAngle和endAngle表示从长轴顺时针方向测量的椭圆弧的起点和终点。即,给出值0和360给出完整的椭圆。有关详细信息,请查看cv.ellipse()文档。下面的例子在图像的中心绘制了一个半椭圆。

#  画一个蓝色椭圆
cv.ellipse(img, (256, 256), (100, 50), 0, 0, 180, 255, -1)

3.7 绘制多边形

要绘制多边形,首先需要顶点的坐标。将这些点放入一个ROWSx1x2的数组中,其中ROWS是顶点数,类型应为int32。在这里,我们画一个小多边形的四个黄色顶点。

# 绘制一个黄色四边形
pts = np.array([[10, 5], [20, 30], [70, 20], [50, 10]], np.int32)
pts = pts.reshape((-1, 1, 2))
cv.polylines(img, [pts], True, (0, 255, 255))

注意:

如果第三个参数为False,你将得到一条连接所有点的折线,而不是一个封闭的形状。

cv.polylines()可用于绘制多条线。只需创建一个包含所有要绘制的线条的列表,并将其传递给函数。所有线条将单独绘制。这是一种比为每一行调用cv.line()更好更快的绘制一组直线的方法。

3.8 将文本添加到图像

要在图像中放置文本,您需要指定以下内容。

  • 要写入的文本数据
  • 您想要放置它的位置坐标(即数据开始的左下角)。
  • 字体类型(查看cv.putText()文档以获得支持的字体)
  • 字体比例(指定字体大小)
  • 常规的东西,如颜色,厚度,线型等。为了更好的外观,建议使用lineType = cv.LINE_AA

我们将在图像上以白色颜色写入 OpenCV

# 写入白色文字OpenCV
font = cv.FONT_HERSHEY_SIMPLEX
cv.putText(img, 'OpenCV', (10, 500), font, 4, (255, 255, 255), 2, cv.LINE_AA)

3.9 结果

现在是时候看看我们的最终结果了。正如您在前几篇文章中学习的那样,显示图像以查看它。

完整代码下载:点击这里

alt text

四、鼠标当画笔

4.1 目标

  • 学习在OpenCV中处理鼠标事件
  • 您将学习这些函数:cv.setMouseCallback()

4.2 简单演示

下载代码:点击这里

在这里,我们创建了一个简单的应用程序,它可以在双击图像的任何地方画一个圆。

首先,我们创建一个鼠标回调函数,当鼠标事件发生时执行。鼠标事件可以是任何与鼠标相关的事件,如左键按下,左键向上,左键双击等,它为我们提供了每个鼠标事件的坐标(x, y)。

有了事件和位置,我们可以做任何事情。要列出所有可用的事件,请在Python终端中运行以下代码:

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

创建鼠标回调函数有一个特定的格式,在任何地方都是一样的。不同的只是函数的功能。因此,我们的鼠标回调函数只做一件事,就是在我们双击的地方画一个圆。请看下面的代码,在注释中不言自明:

import numpy as np
import cv2 as cv
 
# 鼠标回调函数
def draw_circle(event,x,y,flags,param):
    if event == cv.EVENT_LBUTTONDBLCLK:
        cv.circle(img,(x,y),100,(255,0,0),-1)
 
# 创建黑色背景和窗口,将函数绑定到窗口
img = np.zeros((512,512,3), np.uint8)
cv.namedWindow('image')
cv.setMouseCallback('image',draw_circle)
 
while(1):
    cv.imshow('image',img)
    if cv.waitKey(20) & 0xFF == 27:
        break
cv.destroyAllWindows()

4.3 更高级的演示

下载代码:点击这里

现在,我们将使用一个更好的应用程序。在这个程序中,我们通过拖动鼠标来绘制矩形或圆形(取决于我们选择的模式),就像在画图程序中一样。因此,我们的鼠标回调函数分为两部分,一部分用于绘制矩形,另一部分用于绘制圆形。

这个具体示例将有助于创建和理解一些交互式应用程序,如对象跟踪、图像分割等。

import numpy as np
import cv2 as cv
 
drawing = False # 如果按下鼠标则为True
mode = True # 如果为True,绘制矩形。按‘m’切换到曲线
ix, iy = -1, -1
 
# 鼠标回调函数
def draw_circle(event, x, y, flags, param):
    global ix, iy, drawing, mode
 
    if event == cv.EVENT_LBUTTONDOWN:
        drawing = True
        ix, iy = x, y
 
    elif event == cv.EVENT_MOUSEMOVE:
        if drawing == True:
            if mode == True:
                cv.rectangle(img, (ix, iy), (x, y), (0, 255, 0), -1)
            else:
                cv.circle(img, (x, y), 5, (0, 0, 255), -1)
 
    elif event == cv.EVENT_LBUTTONUP:
        drawing = False
        if mode == True:
            cv.rectangle(img, (ix, iy), (x, y), (0, 255, 0), -1)
        else:
            cv.circle(img, (x, y), 5, (0, 0, 255), -1)

接下来,我们必须将这个鼠标回调函数绑定到OpenCV窗口。在主循环中,我们应该为键’m’设置一个键盘绑定,以在矩形和圆形之间切换。

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

4.4 额外资源

4.4.1 练习

  1. 在上一个例子中,我们画了一个填充矩形。修改代码以绘制一个未填充的矩形。

五、使用Trackbar颜色栏

5.1 目标

  • 学习将Trackbar绑定到OpenCV窗口
  • 您将学习这些函数:cv.getTrackbarPos(),cv. getTrackbar()等。

5.2 代码示例

下载代码:点击这里

在这里,我们将创建一个简单的应用程序,显示您指定的颜色。你有一个显示颜色的窗口和三个轨迹条来指定B,G,R颜色。你滑动轨迹条,窗口的颜色也会相应地改变。

默认情况下,初始颜色将设置为黑色。

对于cv.createTrackbar()函数,第一个参数是轨迹条名称,第二个参数是它所附加的窗口名称,第三个参数是默认值,第四个参数是最大值,第五个参数是每次轨迹条值更改时执行的回调函数。

回调函数总是有一个默认参数,即轨迹条位置。在我们的例子中,函数什么也不做,所以我们简单地传递。

Trackbar的另一个重要应用是将其用作按钮或开关。默认情况下,OpenCV没有按钮功能。所以你可以使用Trackbar来获得这样的功能。

在我们的应用程序中,我们创建了一个开关,只有当开关打开时,应用程序才能工作,否则屏幕总是黑色的。

import numpy as np
import cv2 as cv

def nothing(x):
    pass

# 创建黑色背景和窗口
img = np.zeros((300, 512, 3), np.uint8)
cv.namedWindow('image')

# 为变换颜色创建Trackbar
cv.createTrackbar('R', 'image', 0, 255, nothing)
cv.createTrackbar('G', 'image', 0, 255, nothing)
cv.createTrackbar('B', 'image', 0, 255, nothing)
 
# 为开关功能创建一个开关
switch = '0 : OFF \n1 : ON'
cv.createTrackbar(switch, 'image', 0, 1, nothing)
 
while (1):
    cv.imshow('image', img)
    k = cv.waitKey(1) & 0xFF
    if k == 27:
        break
    
    # 获取4个Trackbar的位置
    r = cv.getTrackbarPos('R','image')
    g = cv.getTrackbarPos('G','image')
    b = cv.getTrackbarPos('B','image')
    s = cv.getTrackbarPos(switch,'image')
    
    if s == 0:
        img[:] = 0
    else:
        img[:] = [b, g, r]
 
cv.destroyAllWindows()

应用程序的屏幕截图如下所示:

alt text

5.3 额外资源

5.3.1 练习

  1. 使用轨迹条创建具有可调颜色和画笔半径的Paint应用程序。对于绘图,请参考以前的教程。
  • 21
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值