OpenCV的GUI特性

OpenCV的GUI特性 源网页

  • 开始学习图片
  • 开始学习视频
  • OpenCV的绘图方法
  • 鼠标作为画笔
  • 滚动栏作为调色板

文章目录
  • OpenCV的GUI特性
    • [开始学习图片]()
      • 目标
      • 使用OpenCV
        • 读取一个图像
        • 总结
      • 使用Matplotlib
      • 拓展资源
    • 学习视频
    • OpenCV的绘图方法
      • 目标
      • 代码
      • 画一条线
      • 画一个长方形
      • 画圆
      • 画一个椭圆形
      • 绘制多边形
      • 添加文字
    • 鼠标作为画笔
      • 目标
      • 简单案例
      • 更多高级案例
      • 额外资源
      • 练习题
    • 轨迹栏作为调色盘
      • 目标
      • 代码案例
      • 练习题

开始学习图片 目标
  • 这里,你会学习如何读取一张图片,如何展示以及如何保存它
  • 你会学习到这些方法: cv.imread(),cv.imshow(),cv.imwrite()
  • 另外,你会学习到如何在matplotlib中展示图片
使用OpenCV
读取一个图像 使用 cv.imread() 来读取一张图片。这个图片给予的路径应该是在工作目录中或者使用完整路径
第二个参数是一个flasg来指定图片的读取方式
  • cv.IMREAD_COLOR:导入一个彩色图片。图片的所有透明度将会被忽略。这是默认的flag
  • cv.IMREAD_GRAYSCALE:导入一个灰度图片
  • cv.IMREAD_UNCHANGED:导入图片,包括alpha通道
注意: 你可以用简单的证书1,0,-1来代替这些flag

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

warning
即使图片路径是错误的,它也不会引发异常,但是 print img 会返回 None
展示一个图片
使用方法 cv.imshow()会在一个窗口里面显示一张图片。窗口会自动适应图片的大小。
第一个参数:字符串,是窗口的名字。
第二个参数是我们的图片。你可以创建多个不同名字的窗口展示同一个图片
cv.imshow('image',img) cv.waitKey() cv.destoryAllWindows()

图片的截图看起来将会是这个样子

cv.waitKey()是一个键盘绑定函数。他的参数是时间单位是毫秒。这个函数等待指定的时间来等待任何键盘事件。如果你在这段时间内,输入了任何键,这个程序会继续。如果参数是0,他将会无限制的等待按键。他也可以设置成检测指定的按键,如按下按键a等,我们将会在下面讨论
注意 除了绑定案件事件,这个函数韩处理很多其他GUI事件,所以你必须将它用于实际的显示图片上

cv.destoryAllWindows()简单的摧毁所有我们建立的窗口。如果你想关闭指定的窗口,使用方法cv.destoryWindow() ,并传入参数:窗口的名称
注意 这里有一个特殊的案例,你可以在一个一创建的窗口中载入图像。在这种情况下,你可以指定窗口是否可以重新变更大小,它使用 cv.namedWindow().默认,他的flag是 cv.WINDOW_AUTOSIZE.但是如果你指定flag为 cv.WINDOW_NORMAL,你可以重新变更窗口。当图片太大的时候,这将会非常有帮助

代码如下:
cv.namedWindow('image', cv.WINDOW_NORMAL) cv.imshow('image',img) cv.waitKey(0) cv.destroyAllWindows()

写一个图片
使用方法 cv.imwrite()来保存一张图片。
第一个参数是文件名
第二个参数是你想要保存的image实例
cv.imwrite('messigravy.png',img)

这会将图片已png的格式保存在工作目录中
总结 在下面的程序中,导入了一张灰度图并且展现,保存了他。如果你按下了 s 会退出,或者按下esc 取消保存并退出
import numpy as np import cv2 as cv img=cv.imread('messi5.jpg',0) cv.imshow('image',img) k=cv.waitKey(0) if k==27: cv.destoryAlWindows() elfi k==ord('s'): cv.imwrite('messigray.png',img) cv.destoryAllWindows()

警告
如果你使用一个64位的机器,你需要改变
k=cv.waitKey(0)


k=cv.waitKey(0) &0xFF

使用Matplotlib
Matplotlib是一个python的绘图程序库,它提供了大量的绘图方法。你会再即将到来的文章中见到他们,你会学习到如何在matplotlib中展现image。你可以用matplotlib来进行缩放图片,保存等操作
import numpy as np import cv2 as cv from matplotlib import pyplot as plt img = cv.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()

窗口的截图如下:

同看到
大量的绘图选项可以在Matplotlib中使用,请参考Matplotlib文档获得更多的细节。有时候,我们会在路上看到她。
注意
由OpenCV导入的彩色图片是BGR模式的,但是Matplotlib是用RGB模式占线的,所以由opencv读取的彩色图片在matplotlib中不会正确的显示
拓展资源
  1. Matplotlib Plotting Styles and Features
学习视频 ###目标
  • 学习读取视频,展示和保存
  • 学习抓取摄像机和展示
  • 你会用到以下方法:cv.VideoCapture(),cv.VideoWriter()
###从摄像投抓取片段
经常,我们从摄像头中获取视频流。OpenCV提供了一个非常简单的接口来完成。让我们从摄像头抓取一段视频(我使用了笔记本内置的网络摄像头),转换成灰度视频,然后展示他。这只是一个简单的任务,让我们开始吧
为了抓取一段录像,我们需要创建一个VideoCapture对象。他的参数可以是设备,也可以是录像的名称。设备目录仅仅只是一个数字来指定哪个摄像头。通常一个摄像头是可用的(在我的例子中)。所以我简单的输入了0(或者-1)。你输入1来选择第二个摄像头或者其他的。之后,你可以逐帧来抓去。但是最后,不要忘记释放这次抓取。
import numpy as np import cv2 as cv cap = cv.VideoCapture(0) while(True): # Capture frame-by-frame ret, frame = cap.read() # Our operations on the frame come here gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY) # Display the resulting frame cv.imshow('frame',gray) if cv.waitKey(1) & 0xFF == ord('q'): break # When everything done, release the capture 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.getCAP_PROP_FRAME_HEIGHT),它默认会返回640*480。但是如果我想要更改成320*240,只需要 ret=cap.set(cv.CAP_PROP_FRAME_WIDTH,320),ret=cap.set(cv.CAP_PROP_FRAME_HEIGHT)
注意 如果你发现了异常,确保摄像机通过其他软件也能正常运行

### 从文件中播放视频
和从摄像头中抓取一样,只是更改了摄像头目录 为 视频文件的文件名。同样的当播放帧的时候,使用cv.waitKey()来占用。如果他太少了,视频会播放的非常快。如果太高了,视频会非常慢(好的,这就是如何以慢动作展现视频)。正常情况下,25毫秒会运作正常。
import numpy as np import cv2 as cv cap = cv.VideoCapture('vtest.avi') while(cap.isOpened()): ret, frame = cap.read() gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY) cv.imshow('frame',gray) if cv.waitKey(1) & 0xFF == ord('q'): break cap.release() cv.destroyAllWindows()

注意 确保安装了正确版本的ffmpeg或gstreamer。有时,由于ffmpeg/gstreamer的错误安装,使用视频捕获是一个令人头痛的问题。

###保存视频
所以我们抓取了一段视频,逐帧处理他然后我们想要保存它。对于图片,非常简单,只需要使用cv.imwrite()。这里 需要一段稍多的工作
这次,我们创建了一个VidowWriter实例,我们需要指定输出文件名。然后我们指定FourCC代码(细节在下一章)。然后指定FPS和每帧需要压缩的大小。最后是isColoreflag,如果她是True,压缩成指定颜色的帧,否则以灰度帧压缩。
FourCC是一个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: MJPG (.mp4), DIVX (.avi), X264 (.mkv).
Fourcc代码对于MJPG格式,可以如下输入 cv.VideoWriter_fourcc('M'.'J','P','G') 或者cv.VideoWriter_fourcc("MJPG")
下面是从摄像机中抓取,将每帧朝垂直方向翻转然后保存的代码
import numpy as np import cv2 as cv cap = cv.VideoCapture(0) # Define the codec and create VideoWriter object fourcc = cv.VideoWriter_fourcc(*'XVID') out = cv.VideoWriter('output.avi',fourcc, 20.0, (640,480)) while(cap.isOpened()): ret, frame = cap.read() if ret==True: frame = cv.flip(frame,0) # write the flipped frame out.write(frame) cv.imshow('frame',frame) if cv.waitKey(1) & 0xFF == ord('q'): break else: break # Release everything if job is finished cap.release() out.release() cv.destroyAllWindows()

OpenCV的绘图方法 目标
  • 学习用Opencv 绘制不同的几何图形
  • 你会学到以下方法:cv.line(),cv.cricle(),cv.rectangle(),cv.ellipse(),cv.putText()etc
代码
在上方所有的方法,你可以看到一些通用的参数:
  • img: 画图所在的图像
  • colore: 图形的颜色。对于BGR,需要给予一个元祖,如蓝色(255,0,0),对于灰度,只需要给予标量值
  • thickness:行或者圆等的厚度,如果 给予了 -1 参数给了闭环图像像是圆形,他会被填充。默认是1
  • lineType:线条的类型,是否八连,抗锯齿线等等。默认,他是八连的。cv.LINE_AA提供了反锯齿线,看起来很适合曲线
画一条线
为了画一条线,你需要给予起点和重点。我们会创建一个黑色的图片然后画一条蓝色的线在上面,线从左上到右下。
import numpy as np import cv2 as cv # Create a black image img = np.zeros((512,512,3), np.uint8) # Draw a diagonal blue line with thickness of 5 px cv.line(img,(0,0),(511,511),(255,0,0),5)

画一个长方形
来画一个矩形,你需要提供矩形的左上角和右下角。这次我们来画一个绿色的矩形在画面的最左边
cv.rectangle(img,(384,0),(510,128),(0,0,255),-1))

画圆
想要画圆,你需要提供中心点和半径。我们会在矩形的中间画一个园
cv.circle(img,(447,63), 63, (0,0,255), -1)

画一个椭圆形
画一个椭圆,需要输入一些参数。一个参数是中心点(x,y),另一个参数是轴线的长度(主要是轴线长度,次轴长度)。角度是椭圆逆时针旋转的角度。startAngle和endAngle表示从主轴顺时针方向测量的椭圆圆弧的起始和结束。也就是说,给出的值是0,而360给出的是完整的椭圆。要了解更多细节,请参阅cv.ellipse()的文档。下面的例子在图像中心绘制了半个椭圆。
cv.ellipse(img,(256,256),(100,50),0,0,180,255,-1)

绘制多边形
要画一个多边形,首先你需要顶点的坐标。将这些点设置为形状行x1x2数组,其中行是顶点数,类型为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))

请注意 如果第三个参数为假,您将得到连接所有点的折线,而不是一个封闭的形状。 polylines()可以绘制多条线。只需要创建一个您想要绘制的所有行列表,并将其传递给函数。所有的线将单独画。与为每一行调用cv.line()相比,它是一种更好更快的绘制一组线的方法。

添加文字
为了添加文字,你需要指定以下参数
  • Text data:你想要添加的文字
  • position:你想放置的位置的坐标(左下角 是0点)
  • font type:格式(参考 cv.putText()文档来支持更多)
  • font scale:文字大小(指定文字的大小)
  • 规则的东西,如颜色、厚度、线条类型等。为了更好看,推荐线条类型= cv。LINE_A。
我们会用白色的 opencv来写在图片
font = cv.FONT_HERSHEY_SIMPLEX cv.putText(img,'OpenCV',(10,500),font,4,(255,255,255),2,cv.LINE_AA)

###结果
是时候查看画出来的结果,使用你在上一节学习到的来展示他们。
OpenCV的GUI特性
文章图片

鼠标作为画笔 目标
  • 学习抓取鼠标事件
  • 你会学到这些方法: cv.setMouseCallback()
简单案例
在这里,我们创建了一个简单的应用程序,它在双击图像的任何地方绘制一个圆。
首先,我们创建一个鼠标回调方法 用来在鼠标事件发生的时候执行。鼠标事件可以是任何和鼠标有关系的时间,例如按下左键,抬起左键,双击左键等等。每一个鼠标事件都返回一个坐标(X,Y),使用鼠标事件和定位,我们可以做任何我们喜欢的事情。为了列出所有可用的鼠标事件,在python终端运行一下代码
import cv2 as cv events = [i for i in dir(cv) if 'EVENT' in i] print( events )

创建鼠标回调方法有一个在任何地方都相同的特殊格式。。它只在函数的作用上有所不同。我们的鼠标回调函数只做一件事,他在双击的地方画出一个圆形。查看以下的代码。代码的内容中有注释:
git checkout v1.0 file code/mouse_paint_brush.py

import numpy as np import cv2 as cv # mouse callback function def draw_circle(event,x,y,flags,param): if event == cv.EVENT_LBUTTONDBLCLK: cv.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) cv.namedWindow('image') cv.setMouseCallback('image',draw_circle) while(1): cv.imshow('image',img) if cv.waitKey(20) & 0xFF == 27: break cv.destroyAllWindows()

更多高级案例
现在来完成一个更好的应用。这次,我们通过拖拽鼠标画一个矩形或者圆形(根据鼠标的选择)像是我们在画图应用里面做的一样。所以我们的鼠标回调函数有两个部分,一是画矩形另一个是画圆形。这个特殊的案例对于创造和理解一些交互式应用相当的有用,例如 物体追踪,图片分割等等
git checkout v1.1 code/mouse_paint_brush.py

import numpy as np import cv2 as cv 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 == 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()

额外资源
练习题
  1. 在我们上一个案例中,我们画了一个填充的矩形。请更待代码来画一个非填充的矩形
git checkout v1.2 code/mouse_patin_brush.py

轨迹栏作为调色盘 目标
  • 学习绑定轨迹栏到opencv的窗口
  • 你会学习到一下方法: cv.getTrackbarPos(),cv.createTrackbar()etc
代码案例
这里我们会创建一个简单的应用,用来展示你指定的颜色。你需要有一个窗口来展现颜色,和三个滚动条来指定 B,G,R的颜色。滑动滚动条并且相应的窗口的颜色改变。默认的初始颜色是黑色。
对于 cv.getTrackbarPost()函数,第一个参数是滚动条的名字,第二个是窗口的名字,第三个是默认的值,第四个是最大值,第五个是回调参数在每次滚动条的值改变的时候执行。回调函数总是有一个默认的参数是滚动条的位置。在我们的案例中,方法总是不做任何事情,所以我们直接跳过就行。
另一个重要的滚动条应用是像按钮或者开关一样来使用。Opencv,默认的,没有任何按钮的功能。所以你可以用滚动条来实现类似的功能。在我们的应用中,我们已经创建了一个开关,应用程序只有在开关打开时才工作,否则屏幕总是黑色的。
git checkout v1.0 code/trackbar_test.py

import numpy as np import cv2 as cv def nothing(x): pass # Create a black image, a window img = np.zeros((300,512,3), np.uint8) cv.namedWindow('image') # create trackbars for color change cv.createTrackbar('R','image',0,255,nothing) cv.createTrackbar('G','image',0,255,nothing) cv.createTrackbar('B','image',0,255,nothing) # create switch for ON/OFF functionality 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 # get current positions of four trackbars 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()

应用的截图看起来如下:
OpenCV的GUI特性
文章图片

练习题
  1. 【OpenCV的GUI特性】创建一个画图程序可以调整颜色和刷子大小通过滚动条。为了画图,参考上一节教程关于鼠标的句柄
    v1.3 code/trackbar_test.py

    推荐阅读