- 前言
- Day1.OpenCV操作基础
- 读取/保存图片
- 读取/保存视频
- 画点、线、圆、矩形、文字等
- 鼠标键盘事件以及滑动条设置
- 鼠标事件
- 键盘事件
- 滑动条设置
- 结语
硕士期间做了近两年的图像处理与深度学习相关的内容,但在实际应用中仍然能遇到新问题,学习新知识,因此在这开一个坑,总结一下图像处理开源库OpenCV(Python)中常见的函数、原理和算法,也会同时记录新碰到的问题与解决方法,巩固一下图像基础。
按照OpenCV官方doc顺序来进行学习回忆和总结~
Day1.OpenCV操作基础 读取/保存图片图片读取主要采用imread(),读取img的通道顺序为BGR,
img = cv2.imread(path, flags=cv2.IMREAD_COLOR)
其中path表示读取图片路径,flags表示读图方式 cv2.IMREAD_COLOR 读取彩图 cv2.IMREAD_UNCHANGED 读取原图 cv2.IMREAD_GRAYSCALE 读取灰度图
图片保存主要采用imwrite(),
cv2.imwrite(path, img)
其中path表示图片保存路径,img表示需要保存的Mat格式图片
如果本地图片名或保存图片名带有中文,则会出现读取/保存图片不成功的现象,此时需要通过imdecode和imencode进行读写,
# 读图
img = cv2.imdecode(np.fromfile(path, dtype=np.uint8), flags)
# 写图
cv2.imencode('.jpg', img)[1].tofile(path)
读取/保存视频
视频读取主要采用VideoCapture(),其中path=0时开启摄像头,
cap = cv2.VideoCapture(path)
常用的读取流程是:捕获视频流VideoCapture()->读取视频帧cap.read()->图像处理->结束后cap.release(),如下所示,
cap = cv2.VideoCapture(0)
if not cap.isOpened():
print("Cannot open camera")
exit(0)
while True:
ret, frame = cap.read()
if not ret:
print("Last frame.")
break
cv2.imshow('frame', gray)
if cv2.waitKey(1) == ord('q'):
break
cap.release()
视频保存主要采用VideoWriter(),其中fourcc表示视频编码方式,*'MJPG’可用来保存.mp4格式
fourcc = cv2.VideoWriter_fourcc(*'XVID')
outvid = cv2.VideoWriter(path, fourcc, fps, (W, H))
注意,如果(W, H)与后面outvid.write(img)中img的Size不符合,就无法正常保存视频,这是常见的保存无效视频文件的原因
以下是打开视频->水平翻转->保存视频的一个例程,
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('output.avi', fourcc, 20.0, (640, 480))
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
frame = cv2.flip(frame, 0)
out.write(frame)
cv2.imshow('frame', frame)
if cv2.waitKey(1) == ord('q'):
break
cap.release()
out.release()
画点、线、圆、矩形、文字等
图像处理时经常需要画图,例如特征匹配时要画点画线、目标检测画目标框等
画形状的常见函数包括,
# 线
cv2.line(img, pt1, pt2, color, thickness, lineType)
# 矩形
cv2.rectangle(img, pt1, pt2, color, thickness, lineType)
# 圆
cv2.circle(img, center, radius, color, thickness, lineType)
# 椭圆
cv2.ellipse(img, center, (ra, rb), angle, startAngle, endAngle, color, thickness, lineType)
# 多边形或折线
cv2.polylines(img, pts, isClosed, color, thickness, lineType)
# 文字
cv2.putText(img, text, pt1, fontFace, fontScale, color, thickness, lineType)
通用参数包括img,color,thickness,lineType,分别表示输入图像,颜色,线厚度,线形等 当thickness=-1时画的形状是内部填充的,可用于图像掩膜的生成 lineType有三种形式, cv2.LINE_AA 反锯齿线 ,画曲线更平滑 cv2.LINE_8 8-连通线 cv2.LINE-4 4-连通线
以下是一个画图实例,
import cv2
import numpy as np
img = np.zeros([480, 640, 3], np.uint8)
cv2.line(img, (100, 100), (300, 300), (0, 255, 255), 3, cv2.LINE_AA)
cv2.rectangle(img, (384, 0), (510, 128), (0, 255, 0), 3)
cv2.circle(img, (447, 63), 63, (0, 0, 255), -1)
cv2.ellipse(img, (256, 256), (100, 50), -30, 0, 180, (255, 180, 0), -1)
pts = np.array([[10, 5], [20, 30], [70, 20], [50, 10]], np.int32)
cv2.polylines(img, [pts], True, (0, 255, 255))
cv2.putText(img, 'OpenCV', (10, 400), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2, cv2.LINE_AA)
cv2.imshow('img', img)
cv2.waitKey(0)
输出结果:
OpenCV鼠标键盘事件包括左右键双击、移动、拖拽、Ctrl/Alt/Shift等,
cv2.CV_EVENT_MOUSEMOVE :鼠标移动
cv2.CV_EVENT_LBUTTONDOWN : 鼠标左键按下
cv2.CV_EVENT_RBUTTONDOWN : 鼠标右键按下
cv2.CV_EVENT_MBUTTONDOWN : 鼠标中键按下
cv2.CV_EVENT_LBUTTONUP : 鼠标左键放开
cv2.CV_EVENT_RBUTTONUP : 右键放开
cv2.CV_EVENT_MBUTTONUP : 中键放开
cv2.CV_EVENT_LBUTTONDBLCLK : 左键双击
cv2.CV_EVENT_RBUTTONDBLCLK : 右键双击
cv2.CV_EVENT_MBUTTONDBLCLK : 中键双击
cv2.CV_EVENT_MOUSEWHEEL : 鼠标向前后滑动
cv2.CV_EVENT_MOUSEHWHEEL : 鼠标向左右滑动
cv2.CV_EVENT_FLAG_LBUTTON :左键拖拽
cv2.CV_EVENT_FLAG_RBUTTON : 右键拖拽
cv2.CV_EVENT_FLAG_MBUTTON : 中键拖拽
cv2.CV_EVENT_FLAG_CTRLKEY : Ctrl按下不放
cv2.CV_EVENT_FLAG_SHIFTKEY : shift按下不放
cv2.CV_EVENT_FLAG_ALTKEY : alt按下不放
有时需要通过鼠标画图,这时就要通过鼠标回调函数setMouseCallback与鼠标响应函数onMouse共同完成
cv2.setMouseCallback(WindowName, onMouse, param=None)
onMouse(event, x, y, flags, param)
其中,setMouseCallback()负责将窗口与鼠标事件绑定,WindowName表示要绑定的窗口,onMouse表示要具体事件响应的方式,param是需要传给onMouse的参数(可缺省), onMouse()中的event表示发生的鼠标事件,x、y表示鼠标位置,param是回调函数传进来的参数
以下给出了一个鼠标点击画圆的程序,
import cv2
import numpy as np
# mouse callback function
def draw_circle(event, x, y, flags, param):
if event == cv2.EVENT_LBUTTONDOWN:
print('event!', cv2.EVENT_LBUTTONDOWN)
cv2.circle(img, (x, y), 100, (255, 0, 0), -1)
if event == cv2.EVENT_LBUTTONUP:
print('event!', cv2.EVENT_LBUTTONUP)
if event == cv2.EVENT_MOUSEMOVE:
print('event!', cv2.EVENT_MOUSEMOVE)
if event == cv2.EVENT_FLAG_ALTKEY:
print('event!', cv2.EVENT_FLAG_ALTKEY)
counter = 0
# Create a black image, a window and bind the function to window
img = np.ones((512, 512, 3), np.uint8)*255
cv2.namedWindow('image')
cv2.setMouseCallback('image', draw_circle)
while 1:
cv2.imshow('image', img)
if cv2.waitKey(20) & 0xFF == 27:
break
cv2.destroyAllWindows()
键盘事件
OpenCV似乎没有具体的键盘相应事件,不过有一个waitKey函数,
cv2.waitKey(time)
在imshow图像后必须至少有一个waitKey()函数,不然无法显示图像
此外,waitKey可以用作键盘响应函数,例如
# 500ms内键盘输入q
cv2.waitKey(500) & 0xFF == ord('q')
# 如果1000ms内键盘输入Esc就退出循环
if cv2.waitKey(1000) & 0xFF == 27:
break
# &0xFF的作用是防止奇奇怪怪的BUG,不加也行
滑动条设置
如果要在图像窗口创建滑动条,则通过createTrackbar()、cv2.getTrackbarPos(), cv2.setTrackbarPos(),其中createTrackBar用于创建滑动条、绑定窗口并设置响应函数,getTrackbarPos用于获取滑动条数值,setTrackbarPose用于设定滑动条初始数值
以下是一个通过滑动条来改变图像通道的例程
import numpy as np
import cv2
from copy import deepcopy
img = cv2.imread('starry_night.png')
myimg = np.zeros_like(img, np.uint8)
cv2.namedWindow('image')
def updateGray(x):
global myimg, img, H, W
size = cv2.getTrackbarPos('gray', 'image')
if size == 1:
myimg = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
if size == 0:
myimg = deepcopy(img)
cv2.createTrackbar('gray', 'image', 0, 1, updateGray)
while True:
cv2.imshow('image', myimg)
if cv2.waitKey(50) == 27:
break
cv2.destroyWindow('image')
本文回顾了基本的OpenCV基础读写操作,以后就将正式进入图像处理的核心操作啦