知识要点
1. 通过PIL的Image读取图片: img = Image.open(img_path) # img_path 为文件地址.
2. 将pillow图片转换为ndarray: np.asarray(img) # np.asarray 可以把一个pillow对象转换为ndarray.
3.数组转置, 维度调整: plt.imshow(np.transpose(img, (1, 2, 0))) # img.numpy(), bgr转换为rgb显示.
一 深度学习总体分类
-
对深度学习的研究与应用主要集中在图像、语言、文字三大领域,结合人工智能和机器学习等相关算法,提出了计算机视觉、自然语言处理等主要热点研究领域。
-
深度学习框架: TensorFlow(Google), pytorch(Facebook), Paddle(百度).
-
自然语言处理(NLP): 是计算机科学,人工智能,语言学关注计算机和人类自然语言之间的相互作用的领域。它研究能实现人与计算机之间用自然语言进行有效通信的各种理论和方法。
二 计算机视觉 (OpenCV)
机器视觉用摄影机和电脑代替人眼对目标进行识别、跟踪和测量等机器视觉,并进一步做图形处理,使电脑处理成为更适合人眼观察或传送给仪器检测的图像。
2.1 图像/视频的加载和显示
2.1.1 图片文件
- 创建窗口: cv2.namedWindow('window',cv2.WINDOW_NORMAL) # import cv2
- 更改窗口大小: cv2.resizeWindow('window', 800,600)
- 展示名字为window的窗口: cv2.imshow('window', 0)
- waitKey方法表示等待按键: key = cv2.waitKey(0): # 0表示任何按键, 其他整数表示等待按键的时间, 单位是毫秒, 超过时间没有发生按键操作窗口会自动关闭.
- 另一种关闭方式: 视频常使用, 因为图片一直在刷新.
- key是int型: if key&0xFF == ord('q'): # ord() 将字母转换为int类型
- 关闭窗口: cv2.destroyAllWindows()
- 读取图片: img = cv2.imread('./cat.jpeg') # OpenCV读取的图片按照BGR(蓝绿红)排列
- 显示图片: plt.imshow(img) # 按RGB显示
- 同时显示图片: np.hstack((new_cat, dog, new_img)) # 图片大小一致, 通道数一致
- 保存图片: cv2.imwrite('./123.png', img)
2.1.2 视频文件
- 读取视频文件: vc = cv2.VideoCapture('./1.mp4')
- 打开摄像头: vc = cv2.VideoCapture(0) # 0表示选择第一个摄像头
- 检测是否正常打开: if vc.isOpened()
- 文件读取: open, frame = vc.read() # 两个返回值: open是状态值,True/False, frame是图片.
- 视频显示: cv2.imshow('result', frame)
- 循环显示视频: key = cv2.waitKey(1) # if key & 0xFF == ord('q'):
- 释放资源: vc.release()
- 关闭窗口: cv2.destroyAllWindows()
2.1.3 视频录制
- 打开摄像头: cap = cv2.VideoCapture(0)
- 保存文件: vw = cv2.VideoWriter('output.mp4', fourcc, 20, (640, 480)) # fourcc = cv2.VideoWriter_fourcc( *'mp4v') # 参数一为输出文件, 参数二为格式, 参数三为帧率, 参数四为分辨率.
-
vw.write(frame) # cv2.imshow('frame', frame) # if cv2.waitKey(1) == ord('q'):
- 资源释放: cap.release() # vw.release() # cv2.destroyAllWindows()
2.1.4 控制鼠标
OpenCV允许我们对窗口上的鼠标动作做出响应:
- setMouseCallback(winname, callback, userdata) # winname是窗口的名字, callback是回调函数, userdata是给回调函数的参数. # 结合callback使用
- callback(event, x, y, flags, userdata)回调函数必须包含这5个参数. # event是事件(鼠标移动, 左键, 右键等), x, y是点鼠标的坐标点, flags主要用于组合键, userdata就是上面的setMouseCallback 的 userdata
- 设置鼠标回调函数: cv2.setMouseCallback('mouse', mouse_callback, '123')
TrackBar控件(追踪条):
- createTrackbar(trackbarname, winname, value, count, onChange) 创建TrackBar控件, value为trackbar的默认值, count为bar的最大值, 最小为0
- getTrackbarPos(trackbarname, winname) 获取TrackBar当前值
- 创建trackbar: cv2.createTrackbar('R', 'trackbar', 0, 255, callback)
-
获取当前trackbar 的值: r = cv2.getTrackbarPos('R', 'trackbar')
-
-
用获取的三个值修改背景: img[:] = [b, g, r]
2.2 绘制图形及图像算术变换
2.2.1 颜色空间转换
- 追踪条: cv2.createTrackbar('curcolor', 'color', 0, 4, callback)
- index = cv2.getTrackbarPos('curcolor', 'color')
- 颜色空间转换API: cvt_img = cv2.cvtColor(img, colorspaces[index]) # cv2.imshow('color', cvt_img)
2.2.2 图片拷贝
- 读取图片: img = cv2.imread('./cat.jpeg')
- 浅拷贝: img2 = img.view() # 该数据调整时, 会直接改变原图
- 深拷贝: img3 = img.copy()
- 改变数据: img[10:100, 10:100] = [0, 0, 255]
- split(mat) 分割图像的通道: b, g, r = cv2.split(img) # b, g, r 都是数组
- merge((ch1, ch2, ch3)) 融合多个通道: img2 = cv2.merge((b, g, r))
2.2.3 绘制图形
- 画直线: cv2.line(img, pt1, pt2, color, thickness, lineType, shift)
- 画矩形: cv2.rectangle(img, (10,10), (100, 100), (0, 0, 255), -1)
- 画圆: cv2.circle(img, center, radius, color[, thickness[, lineType[, shift]]])
- 画椭圆: cv2.ellipse(img, 中心点, 长宽的一半, 角度, 开始, 结束,...)
- 画多边形: cv2.polylines(img, pts, isClosed, color[, thickness[, lineType[, shift]]])
- 填充多边形: cv2.fillPoly(img, [pts], (255, 255, 0))
- cv2.putText(img, "Hello OpenCV!", (10, 400), cv2.FONT_HERSHEY_TRIPLEX, 3, (255,0,0)) # 绘制文字
- opencv 绘制中文 opencv本身不支持, 因为没有中文字体.我们可以借助pillow来实现绘制中文 .
- font_path = 'msyhbd.ttc' # 字体文件
- font = ImageFont.truetype(font_path, 15)
- img_pil = Image.fromarray(img) # 叠加原图
- draw = ImageDraw.Draw(img_pil)
- draw.text((10, 150), '绘制中文', font=font, fill=(0, 255, 0, 0))
2.2.4 算术运算
- 图像的加法运算: cv2.add() # 矩阵的加法, 要求加法运算的两张图shape必须是相同的.
- 图片和单个数字相加进行运算: dog += 10 # cv2.imshow('dog', dog) # 每个和10 进行加法运算, 超出255 的数字, 会被截断, 相当于 n% 256(取余).
- 减法运算: cv2.subtract() # 图像对应位置的元素相减, 如果减完小于0, 统一变成0.
- 乘法: new_img = cv2.multiply(new_cat,dog)
- 除法: new_img = cv2.divide(new_cat,dog)
- 图像的融合: new_img = cv2.addWeighted(new_cat, 0.3, dog, 0.8, 0) # 图片的融合操作相当于对图片进行线性运算 w1* x1 + w2 * x2 + b. 其中alpha是第一个权重参数, beta是第二个权重参数, gamma是偏差.
- 非操作: cv2.bitwise_not(img) # 非操作的效果就相当于是用 255 - img
- 与运算: bitwise_and(img1, img2) # 图片对应位置元素进行与操作. 表现出来的效果就是黑和黑与还是黑, 白和白与还是白. # 先转换为二进制,再进行或运算, 值变小(都为1 为1,同时满足) # 添加水印可用
- 或运算: cv2.bitwise_or() # 对应元素做或运算
- 异或运算: cv2.bitwise_xor() # 对应元素做异或运算
2.3 图像的基本变换
2.3.1 图像的变换
- 图像尺寸变换: new_dog = cv2.resize(dog,dsize=(800, 800), interpolation=cv2.INTER_NEAREST)
- 图像的翻转: cv2.flip(src, flipCode) # flipCode =0 表示上下翻转 # flipCode >0 表示左右翻转 # flipCode <0 上下 + 左右
- 图像的旋转: cv2.rotate(img, rotateCode) # ROTATE_90_CLOCKWISE 90度顺时针 # ROTATE_180 180度 # ROTATE_90_COUNTERCLOCKWISE 90度逆时针
- 仿射变换之图像平移: cv2.warpAffine(src, M, dsize, flags, mode, value) # M:变换矩阵 # dsize: 输出图片大小 # flag: 与resize中的插值算法一致 # mode: 边界外推法标志 # value: 填充边界值
- 计算变换矩阵的API: M = cv2.getRotationMatrix2D(center, angle, scale) # center 中心点 , 以图片的哪个点作为旋转时的中心点. # angle 角度: 旋转的角度, 按照逆时针旋转. # scale 缩放比例: 想把图片进行什么样的缩放.
- 通过三点可以确定变换后的位置: M = cv2.getAffineTransform(src[], dst[]) # src 原目标的三个点 # dst 对应变换后的三个点 # 相当于解方程, 3个点对应三个方程, 能解出偏移的参数和旋转的角度.
- 透视变换:cv2.warpPerspective(img, M, dsize,....) # 透视变换就是将一种坐标系变换成另一种坐标系. 简单来说可以把一张"斜"的图变"正". # 对于透视变换来说, M是一个3 * 3 的矩阵.
- M = cv2.getPerspectiveTransform(src, dst) # 获取透视变换的变换矩阵, 需要4个点, 即图片的4个角, 提供变换前的4个点和变换后的4个点.
2.4 图片卷积
2.4.1 模糊操作
- 方盒滤波: dst = cv2.boxFilter(img, -1, (5, 5), normalize = True)
- 均值滤波: dst = cv2.blur(img, (5, 5))
- 高斯滤波: dst = cv2.GaussianBlur(img, (25, 25), sigmaX = 0) # sigma越大, 平滑效果越明显, 当sigma 为0时, 自动模糊 . 高斯滤波适用于处理有噪声的文件, 减少噪点 .
- 中值滤波: dst = cv2.medianBlur(img, 9) # 中值滤波对胡椒噪音(也叫椒盐噪音)效果明显.
- 双边滤波: dst = cv2.bilateralFilter(img, 7, sigmaColor = 50, sigmaSpace = 20) # 有美颜效果
2.4.2 边缘检测
- 索贝尔算子: # sobel算子对图像求一阶导数。一阶导数越大,说明像素在该方向的变化越大,边缘信号越强 .
- 计算X轴方向的梯度: dx = cv2.Sobel(img, -1, dx = 1, dy = 0, ksize = 1)
- 计算Y轴方向的梯度: dy = cv2.Sobel(img, -1, dx = 0, dy = 1, ksize = 5)
- 合并xy的梯度: dst = cv2.addWeighted(dx, 2, dy, 2, gamma = 1) # 等同于cv2.add()
-
沙尔算子: # Scharr算子和Sobel很类似, 使用不同的kernel值, 擅长寻找细小的边缘, 使用较少.
- 计算X轴方向的梯度: dx = cv2.Scharr(img, cv2.CV_64F, dx = 1, dy = 0)
- 计算Y轴方向的梯度: dy = cv2.Scharr(img, cv2.CV_64F, dx = 0, dy = 1)
- 合并xy的梯度: dst = cv2.addWeighted(dx, 2, dy, 2, gamma = 1) # dst = cv2.add(dx, dy)
- 拉普拉斯算子: dst = cv2.Laplacian(img, -1, ksize = 3) # 可以同时求两个方向的边缘, 对噪音敏感, 需要先进行去噪再调用拉普拉斯。可以先使用中值滤波: dst = cv2.medianBlur(img, 9)
- Canny算法: lena1 = cv2.Canny(img, 100, 200) # 被很多人认为是边缘检测的最优算法, 阈值越小, 细节越丰富。
2.5 形态学及图像的开闭运算
-
形态学常用基本操作有:膨胀和腐蚀, 开运算, 闭运算, 顶帽, 黑帽
2.5.1 图像全局二值化
- 灰度化处理: gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 图像二值化之前需先灰度化
- 二值化操作: thresh, dst = cv2.threshold(gray, 90, 255, cv2.THRESH_BINARY) # 返回两个值,一个是阈值,一个是二值化处理后的图片
- 自适应阈值二值化: dst = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 9, 7) # 此时的阈值是根据图像上的每一个小区域计算与其对应的阈值.
2.5.2 图像形态学操作
- 腐蚀操作: dst = cv2.erode(img, kernel, iterations = 2) # 腐蚀操作也是用卷积核扫描图像, 去除图片中的噪点, # 定义核: kernel = np.ones((3, 3), np.uint8).
- 膨胀操作: dst = cv2.dilate(img, kernel, iterations = 1) # opencv提供了获取卷积核的api: kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (5,5)) # 扩展原轮廓
- 开运算: dst = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel) # 开运算 = 腐蚀 + 膨胀 # 去除图像外部的噪点 . # opencv提供了获取卷积核的api
- 闭运算: dst = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel) # 闭运算 = 膨胀 + 腐蚀 填充图像内部的噪点 .
- 形态学梯度: dst = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel) # 梯度 = 原图 - 腐蚀, 腐蚀之后原图边缘变小了, 原图 - 腐蚀 就可以得到腐蚀掉的部分, 即边缘.
- 顶帽运算: dst = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel, iterations = 2) # 顶帽 = 原图 - 开运算, 开运算的效果是去除图像外的噪点, 原图 - 开运算就得到了去掉的噪点.
- 黑帽操作: dst = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel,iterations = 2) # 黑帽 = 原图 - 闭运算 闭运算可以将图形内部的噪点去掉, 那么原图 - 闭运算的结果是得到图形内部的噪点.
2.6 查找图像轮廓
2.6.1 查找轮廓
- 查找轮廓: contours, hierarchy = cv2.findContours(binary,cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # 新版本返回两个结果,分别是轮廓和层级.
- 先变成单通道的黑白图片: gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
- 二值化: thresh, binary = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY) # 返回两个东西, 一个阈值, 一个是二值化的图.
- 绘制轮廓: cv2.drawContours(img_copy, contours, -1, (0, 0, 255), 2) # 索引取-1时描绘所有轮廓.
- 轮廓面积计算: area = cv2.contourArea(contours[1]) # print('area: ', area)
- 轮廓周长计算: perimeter = cv2.arcLength(contours[1], closed = False) # perimeter 周长
2.6.2 轮廓描绘
- 使用多边形逼近: approx = cv2.approxPolyDP(contours[0], 6, closed = True) # 近似模拟多边形的轮廓 # approx 本质是一个类型的轮廓
- 画出多边形逼近的轮廓: cv2.drawContours(img_copy, [approx], 0, (0, 255, 0), 2)
- 凸包计算: hull = cv2.convexHull(contours[0]) # 凸包指的是完全包含原有轮廓,并且仅由轮廓上的点所构成的多边形。
- 画出凸包: cv2.drawContours(img, [hull], 0, (255, 0, 0), 2)
- 最小外接矩形: rect = cv2.minAreaRect(contours[1])
- box = cv2.boxPoints(rect)
- box = np.round(box).astype('int64') # 注意坐标必须是整数的, 所以需要转化一下
- cv2.drawContours(img, [box], 0, (255, 0, 0), 2)
- 最大外接矩形: x, y, w, h = cv2.boundingRect(contours[1]) # 最大外接矩形参数, (x,y), (w, h)
- cv2.rectangle(img, (x, y), (x + w, y + h), (0, 0, 255), 2)
- 外接圆: (a, b), radius = cv2.minEnclosingCircle(contours[1]) # 返回圆的中心点和半径
- cv2.circle(img, (int(a), int(b)), int(radius), (0, 255, 0), 2)
2.7 图像上下采样及图像直方图显示
2.7.1 图像上下采样
- 高斯金字塔pyrDown向下采样: dst = cv2.pyrDown(img) # 每次处理后, 结果图像是原来的1/4.
- pyrUp 向上采样: dst = cv2.pyrUp(img) # 放大图片
- 拉普拉斯金字塔: lap = img- PyrUp(PyrDown(img)) # 保留的就是残差
2.7.2 图像直方图
- 统计直方图: hist = cv2.calcHist([img], [0], None, [256], [0, 255]) # 其中[0]是channels 通道
- plt.plot(hist_mask, color = 'r', label = 'mask')
- 通过掩码截取部分图像: cv2.imshow('mask_gray', cv2.bitwise_and(img, img, mask = mask))
- 生成掩膜图像: mask = np.zeros(gray.shape, np.uint8) # 生成一个原始图片大小一样大的全黑图片, 全为0.
- 设置想要显示的部分: mask[200:400, 200:400] = 255 # 将想要的区域通过索引方式设置为255.
- 均衡化处理: dark_equ = cv2.equalizeHist(gray_dark)
2.6 图像的特征检测
2.6.1 角点检测
- Harris角点检测: dst = cv2.cornerHarris(gray, blockSize = 2, ksize = 3, k = 0.04) # 返回角点响应, 每个像素算出一个角点响应.
- 填充检测点颜色: img[dst >= (0.01 * dst.max())] = [0, 0, 255] # 红色
- 显示图片: cv2.imshow('img,', img)
- 推荐Shi-Tomasi角点检测: corners = cv2.goodFeaturesToTrack(gray, 1000, 0.01, 10) # (Harris角点检测计算的稳定性和K有关, 不稳定, shi-tomasi是优化版) # corners是特征点集合
2.6.2 特征点检测
- SIFT关键点检测: sift = cv2.xfeatures2d.SIFT_create() # 创建SIFT对象 # SIFT最慢, 准确率最高
- 进行检测: kp = sift.detect(gray)
- 绘制关键点: cv2.drawKeypoints(gray, kp, img)
- SURF特征检测: surf = cv2.xfeatures2d.SURF_create() # 创建SURF对象 # SURF 速度比SIFT快些, 准确率差些
- 同时把关键点和描述子一起检测出来: kp, des = surf.detectAndCompute(img, None)
- 绘制关键点: cv2.drawKeypoints(gray, kp, img)
- ORB特征检测: orb = cv2.ORB_create() # ORB速度最快, 可以实时检测, 准确率最差.
- 关键点和描述子: kp, des = orb.detectAndCompute(img, None)
- 绘制关键点: cv2.drawKeypoints(gray, kp, img)
2.6.3 特征匹配
- 暴力特征匹配: bf = cv2.BFMatcher(cv2.NORM_L1, False)
- 创建特征检测对象: sift = cv2.SIFT_create()
- 分别计算描述子: kp1, des1 = sift.detectAndCompute(img2, None)
- 分别计算描述子: kp2, des2 = sift.detectAndCompute(img1, None)
- 除了match, 还有knnMatch匹配: match = bf.knnMatch(des1, des2, k=2) # 一般k=2
- 通过设定阈值提高关联度: for m, n in match:
- if m.distance < 0.7 * n.distance: # item.append(m)
- match进行匹配: match = bf.match(des1, des2)
- 绘制特征匹配: result = cv2.drawMatches(img2, kp1, img1, kp2, match, None)
- 绘制图片: cv2.imshow('result',result)
- FLANN特征匹配: flann = cv2.FlannBasedMatcher(index_params , search_params)
- sift = cv2.SIFT_create() # 创建特征检测对象
- 分别计算描述子: kp1, des1 = sift.detectAndCompute(img1, None)
- 分别计算描述子: kp2, des2 = sift.detectAndCompute(img2, None)
- index_params = dict(algorithm = 1, tree = 3)
- search_params = dict(check = 9)
- 创建FLANN: flann = cv2.FlannBasedMatcher(index_params , search_params)
- 特征匹配: matches = flann.match(des1, des2)
- result = cv2.drawMatches(img1, kp1, img2, kp2, matches, None)
- 显示结果: cv2.imshow('result',result)
2.6.4 图像查找
-
计算单应性矩阵: H, _ = cv2.findHomography(src_points, dst_points, cv2.RANSAC, 5) # 单应性矩阵的应用, 查找对应图形 # 通过特征匹配和单应性矩阵我们可以实现图像查找.
2.7 模板匹配
2.7.1 模板匹配
- 模板匹配: res = cv2.matchTemplate(img, template, cv2.TM_SQDIFF) # 模板匹配和卷积原理很像,模板在原图像上从原点开始滑动,计算模板与的差别程度,这个差别程度的计算方法在opencv里有6种.
- 找出最大值和最小值及其位置: min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
- 画出匹配轮廓: cv2.rectangle(img, min_loc, (min_loc[0] + 85, min_loc[1] + 110), (0, 0, 255), 2)
- 同时匹配多个对象: res = cv2.matchTemplate(mario_gray, template, cv2.TM_CCOEFF_NORMED) # 匹配
- 设定阈值,相关性大于0.8可匹配: threshold = 0.8
- loc = np.where(res >= threshold) # 分别返回Y, X轴的索引
2.7.2 二值化处理 (otsu算法)
Otsu算法之所以称为最大类间方差法是因为,该方法主要是通过阈值进行前后背景分割, 二值化常见阈值类型有6种.
- 二值化处理: ret, dst = cv2.threshold(naza_gray, 50, 255, cv2.THRESH_BINARY) # 前景
- 使用otsu算法: ret, dst = cv2.threshold(naza_gray, 0, 255, cv2.THRESH_BINARY| cv2.THRESH_OTSU) # 背景 # otsu算法是一种自适应阈值算法.
2.8 图像的分割与修复
传统图像分割方法有: 分水岭法, GrabCut法, MeanShift法, 背景扣除.
2.8.1 分水岭算法
分水岭算法涉及API:(前景物体从背景中分离):
-
dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5) # 计算img中非零值到距离它最近的0值之间的距离
-
二值化处理: _, fg = cv2.threshold(dist_transform, 0.5 * dist_transform.max(), 255, cv2.THRESH_BINARY) # 核心步骤
- 求连通域: _, markers = cv2.connectedComponents(fg) # 用0标记图像的背景,用大于0的整数标记其他对象 # connectedcomponents 要求输入的图片是8位单通道的图片及0,255的图片.
- 执行分水岭法: markers = cv2.watershed(img, markers) # watershed返回的markers已经做了修改, 边界区域标记为-1了.
- 改变边界颜色: img[markers == -1] = [0, 0, 255]
2.8.2 GrabCut (交互式区分前景背景)
通过交互的方式获得前景物体: 用户指定前景的大体区域, 剩下的为背景区域.
- 取出矩形框(x, y, w, h): rect = (200, 180, 180, 200)
- mask = np.zeros(img.shape[:2], dtype = np.uint8) # mask 是grabcut 保存分割结果的矩阵, 分割前全为0,黑色,分割完成后有四种值 # 0:背景, 1:前景, 2:可能的背景, 3:可能的前景
- cv2.grabCut(img, mask, rect, None, None, 5, mode = cv2.GC_INIT_WITH_RECT) # 结果在mask中,展示前景,不要背景.
- 筛选前景部分: mask1 = np.where((mask == 1)|(mask == 3), 255, 0).astype(np.uint8)
- 使用与运算: output1 = cv2.bitwise_and(img, img, mask = mask1)
- 显示结果: cv2.imshow('output1', np.hstack((img, output1)))
2.8.3 MeanShift图像分割
- 均值迁移滤波: img_mean = cv2.pyrMeanShiftFiltering(img, 20, 30) # MeanShift严格来说并不是用来对图像进行分割的, 而是在色彩层面进行平滑滤波的.它会中和色彩分布相近的颜色, 平滑色彩细节, 侵蚀掉面积较小的颜色区域.
2.8.4 视频前后景分离
- MOG: mog = cv2.bgsegm.createBackgroundSubtractorMOG() # 混合高斯模型为基础的前景/背景分割算法
- fgmask = mog.apply(frame) # 去背景
- cv2.imshow('img', fgmask)
- MOG2: mog = cv2.createBackgroundSubtractorMOG2() # 同MOG类似, 不过对亮度产生的阴影有更好的识别, 缺点是会产生很多细小的噪点.
- GMG去背景: mog = cv2.bgsegm.createBackgroundSubtractorGMG() # 静态背景图像估计和每个像素的贝叶斯分割, 抗噪性更强.
2.8.5 图像修复
- dst = cv2.inpaint(img, mask, 5, flags = cv2.INPAINT_TELEA) # 用相邻像素替换这些坏标记,使其看起来像邻居.
- cv2.INPAINT_NS(Fluid Dynamics Method 流体力学算法)
- cv2.INPAINT_TELEA(Fast Marching Method 快速行进算法)
2.9 目标追踪和光流估计
2.9.1 目标追踪
OpenCV目标跟踪算法的使用大概可以分为以下几个步骤:
- 创建MultiTracker对象: trackers = cv2.legacy.MultiTracker_create()
- 读取视频或摄像头数据: cap = cv2.VideoCapture('./videos/soccer_02.mp4')
- 框选ROI区域: roi = cv2.selectROI('frame', frame, showCrosshair = True)
- 添加实际的追踪算法. tracker = OPENCV_OBJECT_TRACKERS['boosting'](), trackers.add(tracker, frame, roi)
- 对每一帧进行进行目标追踪: success, boxes = trackers.update(frame)
- 显示视频: cv2.imshow('frame', frame)
2.9.2 结合深度学习进行目标追踪
opencv 和深度学习结合:
- 分类文件导入: config = './bvlc_googlenet.prototxt'
- 模型导入: model = './bvlc_googlenet.caffemodel'
- 模型创建: net = cv2.dnn.readNetFromCaffe(config, model)
- 把图片变成tensor: blob = cv2.dnn.blobFromImage(img, 1.0, (224, 224), (104, 117, 223))
- 把图片给到网络预测: net.setInput(blob)
- 预测类型: r = net.forward()
- 对得到的结果排序: order = sorted(r[0], reverse = True) # 1000类
2.9.3 光流估计
稀疏光流估计算法为Lucas-Kanade算法, 比较经典.
- p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, gray, p0, None,winSize=(15,15),maxLevel=2) # p1为更新的点, st是状态
- cv2.calcOpticalFlowPyrLK() # 稀疏光流
- cv2.calcOpticalFlowFarneback() # 稠密光流