笔记来源于官方文档
安装
. 在控制台运行pip install opencv-python,等待下载安装完成就可以直接引用了
图片的读取显示和保存
. 使用cv2.imread()来读取图片,cv2.imshow()来显示图片,cv2.imwrite()来保存图片,例如:
import cv2
img = cv2.imread('kkxj.jpg')
#cv2.namedWindow('first',cv2.WINDOW_NORMAL)
cv2.imshow('first',img)
key = cv2.waitKey(0)
if key == 27: #ESC
cv2.destroyAllWindows()
elif key == ord('s'):
cv2.imwrite('new.jpg',img)
cv2.destroyAllWindows()
. cv2.imread()有两个参数,第一个参数是文件名,第二个参数是读取标识默认位(cv2.IMREAD_COLOR),标识有三种值:
cv2.IMREAD_COLOR :加载彩色图像,会忽略掉透明度信息;.
cv2.IMREAD_GRAYSCALE :以灰度模式加载图像;
cv2.IMREAD_UNCHANGED : 加载图像,包含alpha通道(透明度信息)。
. 值得注意的是,如果文件不存在是不会在读取这一步抛出异常,img的值将会是none,也会在之后的显示这一步出错。
. 代码中cv2.namedWindow() 函数用在显示前,用来决定窗口的大小能否通过拖拉鼠标改变,其默认值是cv2.WINDOW_AUTOSIZE 也就是窗口大小和图片大小相同,且不能拖拉窗口边缘改变其大小,如果要实现这点,可以在显示前调用该函数,给第二个参数赋值cv2.WINDOW_NORMAL 。
. cv2.waitKey() 是键盘绑定函数,参数的单位是毫秒,表示在指定时间内等待键盘事件,如果参数位0表示无限期等待键盘事件,也可以用来检测某个按键是否按下,类似之后的判断是按下的是ESC还是‘s’,如果是按下的是ESC将会直接摧毁所有的窗口,如果按下的是‘s’将调用cv2.imwrite保存img为新文件。
视频的读取显示和保存
. opencv提供了简单的接口方便对视频进行抓取,首先需要创建一个VideoCapture 对象,传入的参数可以是设备索引(比如笔记本电脑的摄像头),也可以是某个视频文件的名字。创建玩对象后就能实现对视频进行逐帧抓取了:
#cap = cv2.VideoCapture('jackychen.m4s')
cap = cv2.VideoCapture(0)
while(True):
ret,frame = cap.read()
#将图片转化为灰度模式
gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
#cv2.resizeWindow('frame',640,360)
cv2.imshow('frame',gray )
#加上&0xff是因为是64位机,但加不加在测试环境没看出区别
if cv2.waitKey(1) & 0xff == ord('q'): #对视频文件来说1毫秒太快了,一般25毫秒比较合适
break;
cap.release() #用完切记要释放
cv2.destroyAllWindows()
. cap.read()的返回值是bool值,即如果正确读取了一帧将会返回True,所以上面应该是ret是返回的bool值,frame是抓取的那帧画面;
VideoCapture 对象有时不能知道是否初始化,可以调用isOpened() 函数检查,如果没有可以调用open() 来打开。
. 关于对视频文件的操作可以通过get(propId) 和 set(propId, value) 函数来做到,propId 值是特殊定义的整型变量,对应值的意义如下:
参数值(对应从0开始) | 描述 |
---|---|
CV_CAP_PROP_POS_MSEC | 视频文件的当前位置(以毫秒为单位) |
CV_CAP_PROP_POS_FRAMES | 接下来要解码/捕获的帧的基于0的索引 |
CV_CAP_PROP_POS_AVI_RATIO | 视频文件的相对位置:0-电影开始,1-电影结束 |
CV_CAP_PROP_FRAME_WIDTH | 视频流中帧的宽度(这个和下面的高度好像只能用在摄像头抓取的画面上,要改视频文件的窗口还是用resize函数) |
CV_CAP_PROP_FRAME_HEIGHT | 视频流中帧的高度 |
CV_CAP_PROP_FPS | 帧率 |
CV_CAP_PROP_FOURCC | 编解码器的4个字符的代码 |
CV_CAP_PROP_FRAME_COUNT | 视频文件中的帧数 |
CV_CAP_PROP_FORMAT | 由retrieve()返回的Mat对象的格式 |
CV_CAP_PROP_MODE | 特定于后端的值,指示当前的捕获模式 |
CV_CAP_PROP_BRIGHTNESS | 图像亮度(仅适用于相机) |
CV_CAP_PROP_CONTRAST | 图像的对比度(仅适用于相机) |
CV_CAP_PROP_SATURATION | 图像饱和度(仅适用于相机) |
CV_CAP_PROP_HUE | 图像的色相(仅适用于相机) |
CV_CAP_PROP_GAIN | 图像增益(仅适用于相机) |
CV_CAP_PROP_EXPOSURE | 曝光(仅适用于相机) |
CV_CAP_PROP_CONVERT_RGB | 布尔标志,指示是否应将图像转换为RGB |
CV_CAP_PROP_WHITE_BALANCE_U | 白平衡(摄像机对白色物体的还原)设置的U值(注意:当前仅由DC1394 v 2.x后端支持) |
CV_CAP_PROP_WHITE_BALANCE_V | 白平衡设置的V值(注意:当前仅由DC1394 v 2.x后端支持) |
CV_CAP_PROP_RECTIFICATION | 立体摄像机的整流标志()(注意:当前仅受DC1394 v 2.x后端支持) |
CV_CAP_PROP_ISO_SPEED | 摄像机的ISO速度(快门速度)(注意:当前仅受DC1394 v 2.x后端支持) |
CV_CAP_PROP_BUFFERSIZE | 内部缓冲存储器中存储的帧数(注:当前仅由DC1394 v 2.x后端支持) |
. 保存抓取的视频比起图片稍微复杂一点。首先需要创建一个VideoWriter 对象,然后需要传递给他四个参数,第一个是需要输出的文件名,第二个是FourCC代码,第三个是帧率,第四个是画面显示大小,最后一个是isColor标志,如果为True,则编码器需要彩色框,否则将与灰度框一起使用。
. 关于FourCC代码,它是是一个4字节代码,用于指定视频编解码器,种类非常多,试了几个都没出现问题,可以在这里查看。
cap = cv2.VideoCapture(0)
fourcc = cv2.VideoWriter_fourcc(*'DIVX')
out = cv2.VideoWriter('output.avi',fourcc,20.0,(640,480))
while(True):
ret,frame = cap.read()
if ret == True:
out.write(frame)
cv2.imshow('frame',frame)
if cv2.waitKey(1) == ord('q'):
break
else:
break
cap.release()
out.release()
cv2.destroyAllWindows()
画些图形
画线
. 画线使用的函数是cv2.line(),需要传递原图像,开始坐标,结束坐标,线的颜色和粗细:
import cv2
import numpy as np
# 创建一块黑色背景
img = np.zeros((512,512,3), np.uint8)
# 画对角线
img = cv2.line(img,(0,0),(511,511),(255,0,0),5)
cv2.imshow('test',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
. numpy是一个用来处理复杂矩阵的库,也包含了一些数学函数,zeros()函数相当于初始化一个数组,每个元素的类型由第二个参数指定,这里是一个三位数组,可以前第一个参数中的将两个值认为是图像的长宽,第三个值是每个像素点的RGB值。
画矩形
. 画矩形使用的函数是cv2.rectangle(),与画线的函数类似,只是坐标表示的是左上角坐标和右下角坐标了:
img = cv2.rectangle(img,(384,0),(510,128),(0,255,0),3)
画圆
. 画圆的函数是cv2.circle(),其中的坐标参数换成了圆心坐标和半径:
#最后一个参数为-1表示内部填充(实心)
img = cv2.circle(img,(447,63), 63, (0,0,255), -1)
画椭圆
. 画椭圆的函数是cv2.ellipse(),函数的参数变得更多了,第二个参数也是圆心坐标,接下来是长轴和短轴的长度,然后是图形的旋转角度,然后是开始绘制的角度位置,然后是结束绘制的角度位置,最后也是绘制的线条粗细。
img = cv2.ellipse(img,(256,256),(100,50),0,120,360,(0,255,0),-1)
画多边形
. 画多边形的函数是cv2.polylines(),其参数主要是传递的各个顶点的坐标:
#创建数组
pts = np.array([[10,5],[20,30],[70,20],[50,10]], np.int32)
img = cv2.polylines(img,[pts],True,(0,255,255),3)
. 如果第三个参数传递的是False,将不会成为一个封闭的图形。第二个参数可以看出是一个三位数组,也就是说如果直接给一个三维数组,应该可以画出多个图形来,比如:
pts = np.array([
[[10,5],[20,30],[70,20],[50,10]],
[[100,50],[200,300],[170,200],[250,210]] ], np.int32)
img = cv2.polylines(img,pts,True,(0,255,255),5)
画一些文字
. 在图像上写字可以使用函数cv2.putText(),需要的参数有:
1.原始图像;
2.文字内容;
3.开始坐标;
4.字体(文字样式);
5.文字大小;
6.字体颜色;
7.笔迹粗细;
8.线形(线的样式)。
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img,'OpenCV',(10,500), font, 4,(255,255,255),3,cv2.LINE_AA)
鼠标作画
鼠标事件
绑定回调函数
. 使用cv2.setMouseCallback() 来绑定鼠标事件发生时调用的函数,需要给调用的函数传入事件类型变量:
#实现鼠标双击后自动生成一个圆
def draw_circle(event,x,y,falg,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
#鼠标事件
drawing = False
eraer = True
mode = True
ix,iy = -1,-1
bx,by = -1,-1 #上一次的坐标
def draw(event,x,y,falgs,param):
global ix,iy,drawing,mode,eraer,bx,by
if event == cv2.EVENT_LBUTTONDOWN:
drawing = True
eraer = True
ix,iy = x,y
bx, by = x, y
elif event == cv2.EVENT_MOUSEMOVE:
if drawing == True:
if mode == True:
if eraer == True:
cv2.rectangle(img, (ix, iy), (bx,by), (0, 0, 0), -1)
cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),-1)
bx,by = x,y
else:
cv2.circle(img,(x,y),5,(0,0,255),1)
elif event == cv2.EVENT_LBUTTONUP:
drawing = False
eraer = 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)
img = np.zeros((512,512,3), np.uint8)
cv2.namedWindow('image')
cv2.setMouseCallback('image',draw)
while(1):
cv2.imshow('image',img)
if cv2.waitKey(1) == ord('m'):
mode = not mode
elif cv2.waitKey(1) == 27:
break
cv2.destroyAllWindows()
. 鼠标左键按下的时候定义原点坐标,通过拖动来画出矩形,左键释放的时候确定最终图形,通过按键‘m’来改变画的图形
使用TrackBar
. TrackBar的想滚动套一样可以通过滑动来改变值,也可以设置滚动条的值来实现像按钮开关一样的功能。
. 主要使用的函数是cv2.getTrackbarPos(), cv2.createTrackbar(),前者是获取当前trackbar的值,后者是创建一个trackbar,cv2.createTrackbar()的第一个参数是控件(trackbar)的名字,第二个参数是窗口名,第三个是trackbar的默认值,第四个参数是trackbar的最大值,第五个参数是当trackbar的值发生改变时调用的回掉函数。
. 以下是一个控制三基色的值改变屏幕背景色的例子:
def nothing(x):
pass
img = np.zeros((300,400,3),np.uint8)
cv2.namedWindow('image')
#创建trackbars
cv2.createTrackbar('R','image',0,255,nothing)
cv2.createTrackbar('G','image',0,255,nothing)
cv2.createTrackbar('B','image',0,255,nothing)
#使用trackbar充当按钮开关一样的功能
switch = '0: OFF \n 1: ON'
cv2.createTrackbar(switch,'image',0,1,nothing)
while(1):
cv2.imshow('img',img)
k = cv2.waitKey(1) & 0xFF
if k == 27:
break
#获取各个trackbar当前的值
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()