OpenCV的GUI特性
读入和显示图像
import numpy as np
import cv2
img = cv2.imread('miss.jpg',0) # OpenCV3中使用imread()读入图像
cv2.imshow('image',img) # 使用imshow()显示图片
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.waitKey()是一个键盘绑定函数,它表示在特定的几毫秒之内,如果按下任意键,这个函数会返回按键的ASCII码值,程序将会继续运行。如果没有键盘输入,返回值为-1,如果我们设置这个函数的参数为0,那它将会无限期的等待键盘输入。它也可以被用来检测特定键是否被按下,例如按键a是否被按下。
cv2.destroyAllWindows()可以轻易删除任何我们建立的窗口。如果
你想删除特定的窗口可以使用cv2.destroyWindow(),在括号内输入你想删除的窗口名即可。
另外,还有一种方法也可以显示图像,就是先创建一个窗口, 之后
再加载图像。这种情况下,你可以决定窗口是否可以调整大小。要使用到的函数是cv2.namedWindow()。
cv2.namedWindow()的窗口可调节参数默认是cv2.WINDOW_AUTOSIZE。但是如果你把标签改成cv2.WINDOW_NORMAL,就可以调整窗口大小了。当图像维度太大,或者要添加轨迹条控制参数时,调整窗口大小将会很有用。
import numpy as np
import cv2
img = cv2.imread('miss.jpg', 0)
cv2.namedWindow('image', cv2.WINDOW_NORMAL)
cv2.imshow('image',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
保存图像
将图像写入某个文件中,要使用imwrite()函数
<!–hexoPostRenderEscape:
import numpy as np
import cv2
img = cv2.imread('miss.jpg', 0)
cv2.namedWindow('image', cv2.WINDOW_NORMAL)
cv2.imshow('image',img)
cv2.waitKey(0)
cv2.imwrite('new.jpg',img) # 写入图像
cv2.destroyAllWindows()
:hexoPostRenderEscape–>
使用waitKey()获取键盘输入
前面提到过,可以使用waitKey()得到键盘输入,从而进行一些操作。
<!–hexoPostRenderEscape:
import numpy as np
import cv2
img = cv2.imread('miss.jpg', 0)
cv2.imshow('image',img)
k = cv2.waitKey(0) # 从屏幕读入键盘输入,返回该键对应的ASCII码
if k == 27: # 'ESC'键的ASCII码为27
cv2.destroyAllWindows()
elif k == ord('s'): # 如果输入的是's'键
cv2.imwrite('messigray.png',img)
cv2.destroyAllWindows()
:hexoPostRenderEscape–>
使用matplotlib
opencv-python还可以同matplotlib一起协同使用:
<!–hexoPostRenderEscape:
import numpy as np
import cv2
from matplotlib import pyplot as plt
img = cv2.imread('miss.jpg', 0)
plt.imshow(img, cmap = 'gray', interpolation = 'bicubic') # 设置颜色映射为灰度图,插值方式为双三次插值
plt.xticks([]), plt.yticks([]) # 不给x和Y轴指定刻度值(不显示刻度)
plt.show()
:hexoPostRenderEscape–>
彩色图像使用OpenCV 加载时是BGR 模式。但是Matplotib 是RGB模式。所以彩色图像如果已经被OpenCV 读取,那它将不会被Matplotib 正确显示。
视频
用摄像头捕获视频
为了获取视频,需要创建一个VideoCapture 对象。它的参数可以是设备的索引号,或者是一个视频文件。
设备索引号就是指定要使用的摄像头。一般的笔记本电脑都有内置摄像头,所以参数就是0。你可以通过设置成1 或者其他的来选择别的摄像头。之后,你就可以一帧一帧的捕获视频了。但是最
后,别忘了停止捕获视频。
<!–hexoPostRenderEscape:
import numpy as np
import cv2
cap = cv2.VideoCapture(0) # 使用电脑默认的摄像头生成VideoCapture对象
while(True):
# 一帧一帧的捕获图像
ret, frame = cap.read() # 调用cv2.VideoCapture对象的read()方法来逐帧读取图像
<span class="hljs-comment"># 对每一帧图像都施加[GRB => GRAY]也就是彩色图转换为灰度图</span>
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
<span class="hljs-comment"># 显示每一帧图像</span>
cv2.imshow(<span class="hljs-string">'frame'</span>,gray)
<span class="hljs-keyword">if</span> cv2.waitKey(<span class="hljs-number">1</span>) & <span class="hljs-number">0xFF</span> == <span class="hljs-built_in">ord</span>(<span class="hljs-string">'q'</span>):
<span class="hljs-keyword">break</span>
# 捕获完毕后,释放摄像头
cap.release()
cv2.destroyAllWindows()
:hexoPostRenderEscape–>
cap.read() 返回一个布尔值(True/False)。如果要读取的帧存在,
就是True。因此最后你可以通过检查他的返回值来查看视频文件是否已经到
了结尾。
有时候cap可能不能成功的初始化摄像头设备,这种情况下上述代码会报错。这时可以使用cap.isOpened()来检查是否初始化成功,如果返回值是True,就表明没有问题。否则就要使用函数cap.open()。
另外,也可以使用函数cap.get(propId) 来获得视频的一些参数信息。这里的propId可以是0到18 之间的任何整数。每一个数代表视频的一个属性,数字所代表的摄像头属性见
下表:
其中一些值可以通过cap.set(propId,value) 来修改。例如,我可以使用cap.get(3) 和cap.get(4) 来查看每一帧的宽和高。
默认情况下得到的值是640X480。但是我可以使用ret=cap.set(3,320)
和ret=cap.set(4,240) 来把宽和高改成320X240。
保存视频
从文件中播放视频与从摄像头中捕获一样,你只需要把设备索引号改成视频文件的名字即可。在播放每一帧时,使用cv2.waiKey()设置适当的持续时间。如果设置的太低视频就会播放的非常快,如果设置的太高就会播放的很慢(可以使用这种方法控制视频的播放速度)。通常情况下25 毫秒就可以了。
import numpy as np
import cv2
cap = cv2.VideoCapture(0) # 从文件中播放视频也要初始化VideoCapture对象
# 设置编/解码器
fourcc = cv2.VideoWriter_fourcc(*'XVID') # 在windows平台下使用DIVX编码模式
# 创建VideoWriter对象将图像信息写入视频文件
out = cv2.VideoWriter('output.avi',fourcc, 20.0, (640,480)) # 播放频率为20.0,每一帧大小应为640*480
# Video(filename, codec_format, play_frequency, frame_size, isColor),isColor标签如果是True则每一帧是彩色图,否则是灰度图
while(cap.isOpened()): # 如果设备初始化成功
ret, frame = cap.read()
if ret==True:
frame = cv2.flip(frame, 0) # 图像翻转
# 将帧写入文件中
out.write(frame)
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
else:
break
# 释放VideoCapture和VideoWriter对象
cap.release()
out.release()
cv2.destroyAllWindows()
FourCC 就是一个4 字节码,用来确定视频的编码格式。可用的编码列表
可以从 fourcc.org 查到。
OpenCV中的绘图函数
OpenCV中的绘图函数,常用的有:cv2.line(),cv2.circle(),cv2.rectangle(),
cv2.ellipse(),cv2.putText()等。这些函数都需要设置下面这些参数:
- img:你想要绘制图形的那幅图像的文件句柄。
- color:形状的颜色。以RGB为例,需要传入一个元组,例如:(255,0,0)代表蓝色。对于灰度图则只需要传入灰度值。
- thickness:线条的粗细。如果给一个闭合图形设置为-1,那么这个图形就会被填充。默认值是1。
- linetype:线条的样式,端点连接方式,是否抗锯齿等。默认情况是连接方式。cv2.LINE_AA为抗锯齿,这样看起来会非常平滑。
线条
import numpy as np
import cv2
# 通过指定像素点创建一张黑色的图作为背景
img=np.zeros((512,512,3), np.uint8)
# 画5px粗的蓝色斜线line(img, start, end, color, thickness)
cv2.line(img,(0,0),(511,511),(255,0,0),5)
cv2.imwrite('paint.jpg',img) # 写入图像
矩形
import numpy as np
import cv2
# 通过指定像素点创建一张黑色的图作为背景
img=np.zeros((512,512,3), np.uint8)
# (img, lefttop_coord,rightbittom_coord,color, thickness)
cv2.rectangle(img,(384,0),(510,128),(0,255,0),3)
cv2.imwrite('paint.jpg',img) # 写入图像
画圆
import numpy as np
import cv2
# 通过指定像素点创建一张黑色的图作为背景
img=np.zeros((512,512,3), np.uint8)
# (img, center,r,color,thickness)
cv2.circle(img,(447,63), 63, (0,0,255), -1) # 闭合图形的粗细为-1表示填充
cv2.imwrite('paint.jpg',img)
椭圆
import numpy as np
import cv2
# 通过指定像素点创建一张黑色的图作为背景
img=np.zeros((512,512,3), np.uint8)
# (img, (cx, cy), (rx, ry), rotate, (startAngle, endAnge), color[BGR], thickness)
cv2.ellipse(img,(256,256),(100,50),180,0,180,(255,0,22),-1)
cv2.imwrite('paint.jpg',img)
多边形
import numpy as np
import cv2
# 通过指定像素点创建一张黑色的图作为背景
img=np.zeros((512,512,3), np.uint8)
# 指定画多边形所需要的关键点
points=np.array([[10,5],[20,30],[70,20],[50,10]], np.int32)
points=pts.reshape((-1,1,2))
# (img, [point_lst], isClosepath, color, thickness)
cv2.polylines(img,[points],True,(0,255,255),33)
cv2.imwrite('paint.jpg',img)
在图片上添加文字
import numpy as np
import cv2
# 通过指定像素点创建一张黑色的图作为背景
img=np.zeros((512,512,3), np.uint8)
# (img, text, position, fontFamily, fontsize color, thickness)
font=cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img, 'studyOpenCV', (20,250), font, 2, (0,255,255), 2)
cv2.imwrite('paint.jpg',img)
鼠标事件
查看OpenCV中支持的鼠标事件:
import cv2
events=[i for i in dir(cv2) if 'EVENT'in i]
print(events)
import cv2
import numpy as np
# 用鼠标做画笔(这个有点类似processing中的鼠标画笔)
# 与鼠标事件绑定后,特定鼠标事件被激发后,相应的信息如event对象,鼠标坐标x,y等都会作为参数传给这个鼠标事件的回调函数
def draw_circle(event,x,y,flags=0,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(1):
cv2.imshow('image',img)
if cv2.waitKey(20) == 27: # 按下'ESC'时关闭
break
cv2.destroyAllWindows()
使用滑动条
import cv2
import numpy as np
def nothing(x):
pass
# 创建一副黑色图像作为背景
img=np.zeros((200,512,3),np.uint8)
cv2.namedWindow('image')
cv2.createTrackbar('R','image',0,255,nothing) # 创建滑动条,滑动条标识符'R',值的变化区间在[0-255],滑动条的值每次改变都会调用函数nothing()
cv2.createTrackbar('G','image',0,255,nothing)
cv2.createTrackbar('B','image',0,255,nothing)
switch='0:OFF\n1:ON'
cv2.createTrackbar(switch,'image',0,1,nothing) # 创建图像开关滑动条,只有0,1两个选项
while(1): # 时刻检查滑动条的值来更新图像的RGB值
cv2.imshow('image',img) # 显示图像
k=cv2.waitKey(1)
if k == 27:
break
r=cv2.getTrackbarPos('R','image') # 从标识符为'R'的滑动条中取得值
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] # 图像的RGB像素更新为各滑动条中的值
cv2.destroyAllWindows()
使用滑动条和鼠标事件来实现一个更复杂的效果:
<!–hexoPostRenderEscape:
import cv2
import numpy as np
def nothing(x):
pass
# 当鼠标按下时变为True
drawing=False
# 如果mode 为true 就绘制矩形。按下'm'则变成绘制曲线。
mode=True
ix,iy=-1,-1 # 要绘制的矩形左上角的坐标
# 创建回调函数
def draw_circle(event,x,y,flags,param):
r=cv2.getTrackbarPos('R','image') # 获取滑动条的值
g=cv2.getTrackbarPos('G','image')
b=cv2.getTrackbarPos('B','image')
color=(b,g,r)
<span class="hljs-keyword">global</span> ix,iy,drawing,mode <span class="hljs-comment"># 在该函数内允许使用全局变量ix,iy,drawing,mode(这种语法有点类似PHP中的全局变量语法)</span>
<span class="hljs-keyword">if</span> event==cv2.EVENT_LBUTTONDOWN: <span class="hljs-comment"># 当按下左键时返回起始位置坐标</span>
drawing=<span class="hljs-literal">True</span>
ix,iy=x,y
<span class="hljs-comment"># 当鼠标左键按下并移动时绘制图形。由event参数可得是否移动,由flag可得鼠标是否按下</span>
<span class="hljs-keyword">elif</span> event==cv2.EVENT_MOUSEMOVE <span class="hljs-keyword">and</span> flags==cv2.EVENT_FLAG_LBUTTON:
<span class="hljs-keyword">if</span> drawing==<span class="hljs-literal">True</span>:
<span class="hljs-keyword">if</span> mode==<span class="hljs-literal">True</span>:
cv2.rectangle(img,(ix,iy),(x,y),color,<span class="hljs-number">-1</span>)
<span class="hljs-keyword">else</span>:
<span class="hljs-comment"># 绘制圆圈,小圆点连在一起成了线,3 代表了笔画的粗细</span>
cv2.circle(img,(x,y),<span class="hljs-number">3</span>,color,<span class="hljs-number">-1</span>) <span class="hljs-comment"># 当鼠标松开停止绘画</span>
<span class="hljs-keyword">elif</span> event==cv2.EVENT_LBUTTONUP:
drawing==<span class="hljs-literal">False</span>
<span class="hljs-keyword">if</span> mode==<span class="hljs-literal">True</span>:
cv2.rectangle(img,(ix,iy),(x,y),(<span class="hljs-number">0</span>,<span class="hljs-number">255</span>,<span class="hljs-number">0</span>),<span class="hljs-number">-1</span>)
<span class="hljs-keyword">else</span>:
cv2.circle(img,(x,y),<span class="hljs-number">5</span>,(<span class="hljs-number">0</span>,<span class="hljs-number">0</span>,<span class="hljs-number">255</span>),<span class="hljs-number">-1</span>)
# img是一个由全[0,0,0]组成的三维数组,在这里表示每一像素点的颜色值
img=np.zeros((200,512,3), np.uint8)
cv2.namedWindow('image')
cv2.createTrackbar('R','image',0,255,nothing)
cv2.createTrackbar('G','image',0,255,nothing)
cv2.createTrackbar('B','image',0,255,nothing)
cv2.setMouseCallback('image',draw_circle) # 绑定鼠标回调事件
while(1):
cv2.imshow('image',img)
k=cv2.waitKey(1)
if k==ord('m'):
mode=not mode # 取反
elif k==27:
break
:hexoPostRenderEscape–>
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!