3)绘制圆形包围圈
函数 cv2.minEnclosingCircle()通过迭代算法构造一个对象的面积最小包围圆形。该函数的语法格式为:
center,radius=cv2.minEnclosingCircle(points)
"""
参数:
points: 轮廓数组
返回值:
center: 最小包围圆形的中心
radius: 最小包围圆形的半径
"""
代码:
# 绘制最小圆形
import cv2
import numpy as np
im = cv2.imread("../data/cloud.png", 0)
cv2.imshow("orig", im)
# 提取图像轮廓
ret, binary = cv2.threshold(im, 127, 255, cv2.THRESH_BINARY)
img, contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
(x, y), radius = cv2.minEnclosingCircle(contours[0])
center = (int(x), int(y))
radius = int(radius)
cv2.circle(im, center, radius, (255, 255, 255), 2) # 绘制圆
cv2.imshow("result", im) # 显示绘制后的图像
cv2.waitKey()
cv2.destroyAllWindows()
执行结果:
4)绘制最佳拟合椭圆
函数cv2.fitEllipse()可以用来构造最优拟合椭圆。该函数的语法格式是:
retval=cv2.fitEllipse(points)
"""
参数:
points: 轮廓
返回值:
retval: 为RotatedRect类型的值,包含外接矩形的中心、长半轴、短半轴、旋转角度参数信息,这些信息正好与椭圆的中心点、轴长度、旋转角度等信息吻合
"""
代码:
# 绘制最优拟合椭圆
import cv2
import numpy as np
im = cv2.imread("../data/cloud.png")
gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
cv2.imshow("orig", gray)
# 提取图像轮廓
ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
img, contours, hierarchy = cv2.findContours(binary,
cv2.RETR_LIST,
cv2.CHAIN_APPROX_NONE)
ellipse = cv2.fitEllipse(contours[0]) # 拟合最优椭圆
print("ellipse:", ellipse)
cv2.ellipse(im, ellipse, (0, 0, 255), 2) # 绘制椭圆
cv2.imshow("result", im) # 显示绘制后的图像
cv2.waitKey()
cv2.destroyAllWindows()
执行结果:
5)逼近多边形
函数cv2.approxPolyDP()用来构造指定精度的逼近多边形曲线。该函数的语法格式为:
approxCurve = cv2.approxPolyDP(curve,epsilon,closed)
"""
参数:
curve: 轮廓
epsilon: 精度,原始轮廓的边界点与逼近多边形边界之间的最大距离
closed: 布尔类型,该值为True时,逼近多边形是封闭的;否则,逼近多边形是不封闭的
返回值:
approxCurve: 逼近多边形的点集
"""
代码:
# 构建多边形,逼近轮廓
# 刚开始读取图像是单通道图像,后面就画不出来彩色轮廓
# 原图本身灰度图像,读取按照彩色图像读取,那么这个图像仍然是三通道
# 通常我们另外转化为灰度图像,二值化黑底白片查找轮廓坐标,然后在原图像标注轮廓
import cv2
import numpy as np
im = cv2.imread("../data/cloud.png")
cv2.imshow("im", im)
gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 提取图像轮廓
img, contours, hierarchy = cv2.findContours(binary,# 在二值化处理后的图像上查找轮廓
cv2.RETR_LIST,# 所有轮廓
cv2.CHAIN_APPROX_NONE)# 存储轮廓所有点的信息
# contour列表中每个元素代表一个轮廓,每个轮廓是三维的,第1维度是多少个点
# 精度
adp =im.copy() # 复制图像
epsilon = 0.005 * cv2.arcLength(contours[0], True) # # 根据轮周长计算精度(精度就有大小参照)
approx = cv2.approxPolyDP(contours[0], #轮廓
epsilon, #精度
True) # 构造多边形
# 绘制多边形
adp = cv2.drawContours(adp, # 在该图上绘制
[approx],#轮廓数据(要求列表)
0, # 要绘制的轮廓的索引
(0, 0, 255), 2)#颜色、粗细
cv2.imshow("result_0.005", adp)
# 精度二
adp2 = im.copy()
epsilon = 0.01 * cv2.arcLength(contours[0], True) # 精度,根据周长计算
approx = cv2.approxPolyDP(contours[0], epsilon, True) # 构造多边形
adp = cv2.drawContours(adp2, [approx], 0, (0, 0, 255), 2) # 绘制多边形
cv2.imshow("result_0.01", adp2)
cv2.waitKey()
cv2.destroyAllWindows()
执行结果:
1. 视频基本处理1)读取摄像头
import numpy as np
import cv2
cap = cv2.VideoCapture(0) # 实例化VideoCapture对象, 0表示第一个摄像头
while cap.isOpened():
ret, frame = cap.read() # 捕获帧
cv2.imshow("frame", frame)
c = cv2.waitKey(1) # 等待1毫秒,等待用户输入
if c == 27: # ESC键
break
cap.release() # 释放摄像头
cv2.destroyAllWindows()
2)播放视频文件
import numpy as np
import cv2
cap = cv2.VideoCapture("D:\tmp\min_nong.mp4") # 打开视频文件
while cap.isOpened():
ret, frame = cap.read() # 读取帧
cv2.imshow("frame", frame) # 显示
c = cv2.waitKey(25)
if c == 27: # ESC键
break
cap.release() # 释放视频设备
cv2.destroyAllWindows()
3)捕获并保存视频
import numpy as np
import cv2
""" 编解码4字标记值说明
cv2.VideoWriter_fourcc('I','4','2','0')表示未压缩的YUV颜色编码格式,色度子采样为4:2:0。
该编码格式具有较好的兼容性,但产生的文件较大,文件扩展名为.avi。
cv2.VideoWriter_fourcc('P','I','M','I')表示 MPEG-1编码类型,生成的文件的扩展名为.avi。
cv2.VideoWriter_fourcc('X','V','I','D')表示MPEG-4编码类型。如果希望得到的视频大小为平均值,可以选用这个参数组合。
该组合生成的文件的扩展名为.avi。
cv2.VideoWriter_fourcc('T','H','E','O')表示Ogg Vorbis编码类型,文件的扩展名为.ogv。
cv2.VideoWriter_fourcc('F','L','V','I')表示Flash视频,生成的文件的扩展名为.flv。
"""
cap = cv2.VideoCapture(0)
fourcc = cv2.VideoWriter_fourcc("I", "4", "2", "0") # 编解码4字标记值
out = cv2.VideoWriter("output.avi", # 文件名
fourcc, # 编解码类型
20, # fps(帧速度)
(640, 480)) # 视频分辨率
while cap.isOpened():
ret, frame = cap.read() # 读取帧
if ret == True:
out.write(frame) # 写入帧
cv2.imshow("frame", frame)
if cv2.waitKey(1) == 27: # ESC键
break
else:
break
cap.release()
out.release()
cv2.destroyAllWindows()
2.综合案例
1)利用OpenCV实现图像校正
分析过程:需要对图像特征进行分析:先灰度化处理->提取图像边缘->找图像轮廓->轮廓矩形拟合->得出角点->透视变换。需要我们不断尝试方法与边观察图像。实现方法有很多,参数调节需要我们慢慢折腾、
【任务描述】
我们对图像中的目标进行分析和检测时,目标往往具有一定的倾斜角度,自然条件下拍摄的图像,完全平正是很少的。因此,需要将倾斜的目标“扶正”的过程就就叫做图像矫正。该案例中使用的原始图像如下:
【代码】
# 02_perspective_demo.py
# 利用透视变换实现图像形状矫正
import cv2
import numpy as np
# 读取原图
im = cv2.imread("../data/paper.jpg")
cv2.imshow("im", im)
im_gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
cv2.imshow("im_gray", im_gray)
# 模糊、膨胀处理,合并细节
im_blur = cv2.GaussianBlur(im_gray, (5, 5), 0) # 模糊
im_dilate = cv2.dilate(im_blur, (3, 3)) # 膨胀
cv2.imshow("im_dilate", im_dilate)
# canny边沿提取
im_canny = cv2.Canny(im_dilate, # 在模糊膨胀后的图像上提取边沿
30,
120)
cv2.imshow("im_canny", im_canny)
# 查找轮廓
img, cnts, hie = cv2.findContours(
im_canny, # 在canny检测结果上查找轮廓
cv2.RETR_EXTERNAL, # 只检测外部轮廓
cv2.CHAIN_APPROX_SIMPLE) # 简化格式存储
# 绘制轮廓
im_cnt = cv2.drawContours(im, # 原图上绘制
cnts, # 轮廓数据
-1, # 绘制全部轮廓
(0, 0, 255), 2) # 颜色、粗细
cv2.imshow("im_cnt", im_cnt)
# 对轮廓按照面积排序,用多边形拟合,面积最大的四边形即为纸张轮廓
docCnt = None
if len(cnts) > 0: # 如果找到轮廓
cnts = sorted(cnts, # 待排序的可迭代对象
key=cv2.contourArea, # 排序依据
reverse=True) # 倒序排列
for c in cnts:
peri = cv2.arcLength(c, True) # 计算周长
eps = 0.02 * peri # 多边形拟合精度
approx = cv2.approxPolyDP(c, eps, True) # 多边形拟合
if len(approx) == 4: # 如果返回是四边形,跳出循环
docCnt = approx
break
print("docCnt.shape:", docCnt.shape)
# 用小圆圈标记出4个点的位置
points = []
for p in docCnt: # 遍历轮廓中的每个点
p = p[0] # 去掉多余的维度
cv2.circle(im,
tuple(p), # 转元组类型
10, # 半径
(0, 0, 255), 2) # 颜色、粗细
points.append(p) # 点的坐标添加到列表
cv2.imshow("im_circle", im)
# 计算纸张高度、宽度:勾股定理
import math
h = int(math.sqrt((points[1][0] - points[0][0]) ** 2 +
(points[1][1] - points[0][1]) ** 2))
w = int(math.sqrt((points[2][0] - points[1][0]) ** 2 +
(points[2][1] - points[1][1]) ** 2))
# 定义透视变换原点、目标点
src = np.float32(
[points[0], points[1], points[2], points[3]])
dst = np.float32([[0, 0], [0, h - 1], [w - 1, h - 1], [w - 1, 0]])
# 生成透视变换矩阵
m = cv2.getPerspectiveTransform(src, dst)
# 透视变换
result = cv2.warpPerspective(im_gray, m, (w, h))
cv2.imshow("result", result)
cv2.waitKey()
cv2.destroyAllWindows()
【执行结果】
2)利用OpenCV检测芯片瑕疵
【任务描述】
分析思路:灰度化处理->二值化处理->图像减法->图像闭运算->圆圈标记 :整个过程搞大概半天时间。
利用图像技术,检测出芯片镀盘区域瑕疵。样本图像中,粉红色区域为镀盘区域,镀盘内部空洞为瑕疵区域,利用图像技术检测镀盘是否存在瑕疵,如果存在则将瑕疵区域标记出来。
【代码】
# 03_chip_detection.py
# 利用图像技术实现芯片瑕疵检测
import cv2
import numpy as np
import math
# 读取图像
im = cv2.imread("../data/CPU3.png")
cv2.imshow("im", im)
# 灰度化
im_gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
cv2.imshow("im_gray", im_gray)
# 二值化(主题部分颜色较浅)
t, im_bin = cv2.threshold(im_gray,
162, 255,
cv2.THRESH_BINARY)
cv2.imshow("im_bin", im_bin)
# 查找轮廓,实心填充
img, cnts, hie = cv2.findContours(im_bin,
cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_NONE)
## 实心填充
mask = np.zeros(im_bin.shape, np.uint8)#产生全黑背景
## 在全黑背景上绘制实心轮廓
mask = cv2.drawContours(mask, # 全黑背景上绘制
cnts, # 轮廓数据
-1,# 绘制所有轮廓
(255,0,0),#灰度图像上显示为白色
-1)#实心填充
cv2.imshow("mask", mask)
# 图像相减
im_sub = cv2.subtract(mask, im_bin)
cv2.imshow("im_sub", im_sub)
# 图像闭运算,合并细节
k = np.ones((10, 10), np.uint8)
im_close = cv2.morphologyEx(im_sub, # 图像
cv2.MORPH_CLOSE,# 闭运算
k, iterations=3)#计算核,迭代次数
cv2.imshow("im_close", im_close)
# 查找瑕疵区域的轮廓,并绘制外接圆形
img, cnts, hie = cv2.findContours(im_close,
cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_NONE)
# 产生外接圆形定位数据
(x, y), radius = cv2.minEnclosingCircle(cnts[1])
center = (int(x), int(y)) # 转整型
radius = int(radius)# 转整型
# 绘制圆圈
cv2.circle(im_close, center, radius, (255,0,0), 2)
cv2.imshow("im_close2", im_close)
cv2.circle(im, center, radius, (0, 0, 255), 2)
cv2.imshow("result", im)
cv2.waitKey()
cv2.destroyAllWindows()
【执行结果】



