opencv 图像与视频分析教程
二值图像分析
图像二值化
二值图像轮廓分析
霍夫检测
图像检测与几何形状识别
轮廓匹配
形态学
视频读写
视频读写
视频背景分析
颜色对象提取
案例分析
视频内容分析
案例实战
第一节:认识二值图像
二值图像的定义与说明
只有0或255俩种值
简单图像二值化:
手动选取阈值,Trackbar ,无厘头的方式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MKizO7vc-1649234244982)(C:\Users\LENOVO\AppData\Roaming\Typora\typora-user-images\image-20220403151532779.png)]
API:二值化函数threshold()
#二值化函数 cv.threshold() src:必须为灰度图像, thresh:阈值,大于为255,小于为0 可手动填入,也可利用算法查找 maxvalue:变成二值图像最大值为多少,一般255 type:可以是多个选项的组合,一般cv.THRESH_BINARY
def binary_demo():
src=cv.imread("./picture/lena.jpg",cv.IMREAD_GRAYSCALE) #灰度图像
cv.imshow("input",src)
#二值化函数 cv.threshold() src:必须为灰度图像, thresh:阈值,大于为255,小于为0 可手动填入,也可利用算法查找 maxvalue:变成二值图像最大值为多少,一般255 type:可以是多个选项的组合,一般cv.THRESH_BINARY
ret,dst=cv.threshold(src,127,255,cv.THRESH_BINARY) #二值化分割 ret:阈值, dst:二值化后的图像
cv.imshow("binary",dst)
print(ret)
#建立Tracebar
cv.namedWindow("input", cv.WINDOW_AUTOSIZE)
cv.createTrackbar("Threshold", "input", 0, 255,do_nothing) # tracebar_name window_name value取值 count最大值 onchange是callback的方法
while True:
threshold=cv.getTrackbarPos("Threshold", "input")
ret, dst = cv.threshold(src, threshold, 255, cv.THRESH_BINARY)
cv.imshow("input",dst)
t=cv.waitKey(10)
if t==27:
break#ESC
第二节:图像二值化
图像二值化:将灰度图像通过阈值实现分割,就是图像的阈值化
图像二值化是阈值分割的二分类分割算法
THRESH_BINARY:将低于阈值的变为0,高于阈值的变为255
THRESH_BINARY_INV : 与上一个相反,将高于的置为0,低于的置为255
THRESH_TRUNC:截断,将高于阈值的变为255
THRESH_TOZERO:截断,将低于阈值的变为0
THRESH_TOZERO_INV,将高于阈值的变为0
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Rx5BEmiE-1649234244984)(C:\Users\LENOVO\AppData\Roaming\Typora\typora-user-images\image-20220403151514561.png)]
#二值化函数 cv.threshold() src:必须为灰度图像, thresh:阈值,大于为255,小于为0 可手动填入,也可利用算法查找 maxvalue:变成二值图像最大值为多少,一般255 type:可以是多个选项的组合,一般cv.THRESH_BINARY[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pcKx4ZD7-1649234244985)(C:\Users\LENOVO\AppData\Roaming\Typora\typora-user-images\image-20220403151751730.png)]
API:threshold()
阈值方法共四种:有全局阈值和自适应阈值
第三节:全局阈值
全局阈值:
①均值法
OTSU阈值:通过寻找内类最小方差来寻去t阈值
三角阈值:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K33tnILX-1649234244986)(C:\Users\LENOVO\AppData\Roaming\Typora\typora-user-images\image-20220403154725279.png)]
#第二节:全局阈值
def threshold_segmentation_demo1():
src=cv.imread("./picture/lena.jpg",cv.IMREAD_GRAYSCALE) #灰度图像
cv.imshow("input",src)
#二值化函数 cv.threshold() src:必须为灰度图像, thresh:阈值,大于为255,小于为0 可手动填入,也可利用算法查找 maxvalue:变成二值图像最大值为多少,一般255 type:可以是多个选项的组合,一般cv.THRESH_BINARY
ret1, dst1 = cv.threshold(src, 0, 255, cv.THRESH_BINARY|cv.THRESH_OTSU)
ret2, dst2= cv.threshold(src, 0, 255, cv.THRESH_BINARY|cv.THRESH_TRIANGLE)
cv.imshow("threshold_segmentation1", dst1)
cv.imshow("threshold_segmentation2", dst2)
print(ret1) #117.0
print(ret2)#115.0
第四节:自适应阈值
自适应阈值概述
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3KUlHWKQ-1649234244987)(C:\Users\LENOVO\AppData\Roaming\Typora\typora-user-images\image-20220403160001153.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PorxHNQq-1649234244988)(C:\Users\LENOVO\AppData\Roaming\Typora\typora-user-images\image-20220403155834928.png)]
API:adaptiveThreshold()
void adaptiveThreshold(InputArray src, OutputArray dst,
2. double maxValue, int adaptiveMethod,
3. int thresholdType, int bolckSize, double C)
参数1:InputArray类型的src,输入图像,填单通道,单8位浮点类型Mat即可。
参数2:函数运算后的结果存放在这。即为输出图像(与输入图像同样的尺寸和类型)。
参数3:预设满足条件的最大值。
参数4:指定自适应阈值算法。可选择ADAPTIVE_THRESH_MEAN_C 或 ADAPTIVE_THRESH_GAUSSIAN_C两种。(具体见下面的解释)。
参数5:指定阈值类型。可选择THRESH_BINARY或者THRESH_BINARY_INV两种。(即二进制阈值或反二进制阈值)。
参数6:表示邻域块大小,用来计算区域阈值,一般选择为3、5、7......等。
参数7:参数C表示与算法有关的参数,它是一个从均值或加权均值提取的常数,可以是负数。(具体见下面的解释)。
ADAPTIVE_THRESH_MEAN_C,为局部邻域块的平均值,该算法是先求出块中的均值,再减去常数C。
ADAPTIVE_THRESH_GAUSSIAN_C,为局部邻域块的高斯加权和。该算法是在区域中(x, y)周围的像素根据高斯函数按照他们离中心点的距离进行加权计算,再减去常数C。
def threshold_method_demo():
src = cv.imread("./picture/text.jpg", cv.IMREAD_GRAYSCALE) # 灰度图像
cv.imshow("input", src)
# 二值化函数 cv.threshold() src:必须为灰度图像, thresh:阈值,大于为255,小于为0 可手动填入,也可利用算法查找 maxvalue:变成二值图像最大值为多少,一般255 type:可以是多个选项的组合,一般cv.THRESH_BINARY
dst1 = cv.adaptiveThreshold(src,255,cv.ADAPTIVE_THRESH_MEAN_C,cv.THRESH_BINARY,15,10,None)
dst2 = cv.adaptiveThreshold(src,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY,25,10)
cv.imshow("threshold_segmentation1", dst1)
cv.imshow("threshold_segmentation2", dst2)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rL5Pm5SP-1649234244989)(C:\Users\LENOVO\AppData\Roaming\Typora\typora-user-images\image-20220403161650359.png)]
opencv共支持四种阈值分割方法:全局阈值:OTSU阈值、三角阈值
自适应阈值:
第五节:去噪声对二值化的影响
去噪声对全局值域的影响
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9vnWAkKu-1649234244990)(C:\Users\LENOVO\AppData\Roaming\Typora\typora-user-images\image-20220403174547414.png)]
API
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jOARortq-1649234244991)(C:\Users\LENOVO\AppData\Roaming\Typora\typora-user-images\image-20220403174624491.png)]阈值的几种方法
def threshold_noise_demo():
src = cv.imread("./picture/rice_noise.jpg", cv.IMREAD_GRAYSCALE) # 灰度图像
cv.imshow("input", src)
# src=cv.GaussianBlur(src,(3,3),5) #高斯去噪
src = cv.medianBlur(src, 5) #中值去噪
# 二值化函数 cv.threshold() src:必须为灰度图像, thresh:阈值,大于为255,小于为0 可手动填入,也可利用算法查找 maxvalue:变成二值图像最大值为多少,一般255 type:可以是多个选项的组合,一般cv.THRESH_BINARY
dst1 = cv.adaptiveThreshold(src,255,cv.ADAPTIVE_THRESH_MEAN_C,cv.THRESH_BINARY,15,10,None)
res,dst2 = cv.threshold(src,0,255,cv.THRESH_BINARY|cv.THRESH_OTSU) #OTSU阈值
cv.imshow("threshold_segmentation1", dst1)
cv.imshow("threshold_segmentation2", dst2)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sRfbcmyo-1649234244992)(C:\Users\LENOVO\AppData\Roaming\Typora\typora-user-images\image-20220403174202961.png)]
第六节:连通组件扫描
基本概念解释:
基于图搜索算法
俩部分法:只看上面和左边,先标记数字,再合并。
基于等价队列合并
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-crA81Z8o-1649234244992)(C:\Users\LENOVO\AppData\Roaming\Typora\typora-user-images\image-20220403175934026.png)]
int cv::connectedComponents (
cv::InputArrayn image, // input 8-bit single-channel (binary)
cv::OutputArray labels, // output label map
int connectivity = 8, // 4- or 8-connected components
int ltype = CV_32S // Output label type (CV_32S or CV_16U)
);
其中 connectedComponents()仅仅创建了一个标记图(图中不同连通域使用不同的标记,和原图宽高一致),
#第六节:连通组件扫描
def connected_components_demo():
src = cv.imread("./picture/rice_noise.jpg", cv.IMREAD_GRAYSCALE) # 灰度图像
cv.imshow("input", src)
src = cv.medianBlur(src, 5) #中值去噪
res,dst1 = cv.threshold(src,0,255,cv.THRESH_BINARY|cv.THRESH_OTSU) #OTSU阈值
cv.imshow("threshold_segmentation2", dst1)
output=cv.connectedComponents(dst1,ltype=cv.CV_32S) #ltype输出的数据的类型
print(output) #算上背景一共26个区域,其中25个白色的非连通区域
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UZySGv7D-1649234244993)(C:\Users\LENOVO\AppData\Roaming\Typora\typora-user-images\image-20220403182152450.png)]
output_more=cv.connectedComponentsWithStats(dst1,connectivity=8,ltype=cv.CV_32S)
num_lables=output_more[0] #区域数
lables=output_more[1] #标记图
stats=output_more[2] #每个区域的状态x,y,width,height,area
centers=output_more[3] #每个区域的中心点,为float类型,在显示时需要转为int类型 (cx)
output_more=cv.connectedComponentsWithStats(dst1,connectivity=8,ltype=cv.CV_32S)
num_lables=output_more[0]
lables=output_more[1]
stats=output_more[2] #每个区域的状态x,y,width,height,area
centers=output_more[3] #每个区域的中心点
image_stats=np.copy(src)
image_stats=cv.cvtColor(image_stats,cv.COLOR_GRAY2BGR)
for i in range(num_lables):
if i==0: #背景这一区域
continue
cx,cy=centers[i] #中心位置,为float数据
x,y,width,height,area=stats[i]
cv.rectangle(image_stats,(x,y),(x+width,y+height),(0,0,255),2,0,0)
cv.circle(image_stats,((cx),(cy)),2,(255,0,0),-1,0,0)
cv.imshow("statistic",image_stats)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u6AQDBy5-1649234244994)(C:\Users\LENOVO\AppData\Roaming\Typora\typora-user-images\image-20220403193322982.png)]
第七节:轮廓发现
基本概念解释:
图像轮廓-图像边界
主要针对二值图像,轮廓是一系列点的集合
API知识点:findContours
drawContours
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zYy7cL0z-1649234244994)(C:\Users\LENOVO\AppData\Roaming\Typora\typora-user-images\image-20220403195130987.png)]
contours, hierarchy = cv.findContours( image, mode, method[, contours[, hierarchy[, offset]]] )
- 参数1:源图像
- 参数2:轮廓的检索方式,这篇文章主要讲解这个参数
- 参数3:一般用 cv.CHAIN_APPROX_SIMPLE,就表示用尽可能少的像素点表示轮廓
- contours:图像轮廓坐标,是一个链表
- hierarchy:[Next, Previous, First Child, Parent],文中有详细解释
def find_contours_demo():
src = cv.imread("./picture/coins.jpg")
cv.imshow("input", src)
src = cv.GaussianBlur(src,(3,3),0)#高斯去噪
gray=cv.cvtColor(src,cv.COLOR_BGR2GRAY)
res,binary = cv.threshold(gray,0,255,cv.THRESH_BINARY|cv.THRESH_OTSU) #OTSU阈值
cv.imshow("threshold_segmentation2", binary)
contours, hierarchy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE) #只绘制外轮廓 #cv.RETR_TREE内外轮廓都会绘制
for i in range(len(contours)):
cv.drawContours(src ,contours, i, (0, 0, 255), 2)
cv.imshow("contpurs", str)
cv.RETR_EXTERNAL外轮廓
cv.RETR_TREE内外轮廓都会绘制
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NsL3bkju-1649234244995)(C:\Users\LENOVO\AppData\Roaming\Typora\typora-user-images\image-20220403203625799.png)]
第八节:图像测量:面积,周长
图像测量
计算面积与周长 单位:像素单位
外接矩形与横纵比率
API知识点:
cv.boundingRect:外接矩形 最小x,y 和最大x,y计算
cv.contourArea:面积,像素个数
cv.arcLength:弧长
#基于界边界求:
area=cv.contourArea(contours[i]) #求面积
arclen=cv.arcLength(contours[i],True)#求周长 closed:是否是封闭
x,y,w,h=cv.boundingRect(contours[i]) #外接矩形 的x,y,w,h
#第八节:图像测量:面积,周长
def measure_contours_demo():
#获得二值图像
src = cv.imread("./picture/right.jpg")
cv.imshow("input", src)
src = cv.GaussianBlur(src, (3, 3), 0) # 高斯去噪
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
res, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU) # OTSU阈值
cv.imshow("threshold_segmentation2", binary)
contours, hierarchy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)#求外边界
for i in range(len(contours)):
#求面积:
area=cv.contourArea(contours[i])
arclen=cv.arcLength(contours[i],True)#求周长 closed:是否是封闭
x,y,w,h=cv.boundingRect(contours[i]) #外接矩形 的x,y,w,h
print("area:%d, arclen: %d"%(area,arclen))
if area<50 or arclen<20: #过滤掉面积太小,或者,周长太小的
continue
#利用横纵比找,斜度
# ratio=np.minimum(w,h)/np.maximum(w,h)
# if ratio>0.8:
# continue
cv.drawContours(src, contours, i, (0, 0, 255), 2)
cv.imshow("contpurs", src)
第九讲:几何分析
几何距:
故中心位置x=M10/M00 y=M01/M00
计算角度与中心:
contours:外边轮廓发现
API:cv.moments(contour) :求几何距
cv.fitEllipse(contour)
#第九讲:几何分析
def measure_contours_demo1():
src = cv.imread("./picture/rice_noise.jpg")
cv.imshow("input", src)
src = cv.GaussianBlur(src, (3, 3), 0) # 高斯去噪
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
res, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU) # OTSU阈值
cv.imshow("threshold_segmentation2", binary)
contours, hierarchy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)#求外边界
for i in range(len(contours)):
#求面积:
area=cv.contourArea(contours[i])
arclen=cv.arcLength(contours[i],True)#求周长 closed:是否是封闭
x,y,w,h=cv.boundingRect(contours[i]) #外接矩形 的x,y,w,h
print("area:%d, arclen: %d"%(area,arclen))
if area<50 or arclen<20: #过滤掉面积太小,或者,周长太小的
continue
# 利用横纵比找,斜度
ratio=np.minimum(w,h)/np.maximum(w,h)
if ratio>0.8:
mm=cv.moments(contours[i])
m00=mm["m00"]
m10 = mm["m10"]
m01 = mm["m01"]
cx=(m10/m00)
cy=(m01/m00)
(x,y),(a,b),degree=cv.fitEllipse(contours[i]) #左上角位置,长短轴,角度
print("长轴%d 短轴:%d 角度%d"%(b,a,degree))
cv.circle(src,(cx,cy),2,(255,0,0),-1,8,0) #绘制中心
cv.putText(src,str((degree)),(cx-20,cy-20),cv.FONT_HERSHEY_PLAIN,1.0,(255,0,255),1)
cv.drawContours(src, contours, i, (0, 0, 255), 2)
cv.imshow("contpurs", src)
第十节:距离变换
距离变换
距离度量
API:知识点
dist=cv.distanceTransform(binary,cv.DIST_L1,3,dstType=cv.CV_8U)
dist1 = cv.distanceTransform(binary1, cv.DIST_L2,3, dstType=cv.CV_32F)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ol58iEwb-1649234244996)(C:\Users\LENOVO\AppData\Roaming\Typora\typora-user-images\image-20220404091019626.png)]
#第十节:距离变换
def distance_demo():
src = cv.imread("./picture/right1.jpg")
cv.imshow("input", src)
src = cv.GaussianBlur(src, (3, 3), 0) # 高斯去噪
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
res, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU) # OTSU阈值
cv.imshow("threshold_segmentation2", binary)
#距离变换
dist=cv.distanceTransform(binary,cv.DIST_L1,3,dstType=cv.CV_8U)
cv.imshow("distance-transform",dist)
src1 = cv.imread("./picture/rice_noise.jpg")
cv.imshow("input", src1)
src1 = cv.medianBlur(src1, 5) # 中值去噪
gray = cv.cvtColor(src1, cv.COLOR_BGR2GRAY)
res, binary1 = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU) # OTSU阈值
cv.imshow("threshold", binary1)
dist1 = cv.distanceTransform(binary1, cv.DIST_L2,3, dstType=cv.CV_32F)
dist2=cv.normalize(dist1,0,255,cv.NORM_MINMAX) #把区间变换到0-255, 此时为浮点数,下面直接show时,会出现截断
print(dist2)
res,binary2=cv.threshold(dist2,1.5,255,cv.THRESH_BINARY)
cv.imshow("distanc_transform2",dist2)
cv.imshow("binary2",binary2)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qXIUiGqj-1649234244996)(C:\Users\LENOVO\AppData\Roaming\Typora\typora-user-images\image-20220404090913832.png)]
第十一节:点多边形测试
应用场景:
判断一个点是否在一个多边形内
判断一个对象是否在指定范围之内
API知识点:
retval=cv.pointPolygonTest(contour,pt,measureDist)
pointPolygonTest(InputArray contour, Point2f pt, bool measureDist)
contour 某一轮廓集合点
Point2f 某一测试点
用于测试一个点是否在多边形中
当measureDist设置为true时,返回实际距离值。若返回值为正,表示点在多边形内部,返回值为负,表示在多边形外部,返回值为0,表示在多边形上。
当measureDist设置为false时,返回 -1、0、1三个固定值。若返回值为+1,表示点在多边形内部,返回值为-1,表示在多边形外部,返回值为0,表示在多边形上。
#第十一节:点多边形测试
def point_polygon_test_demo():
src = cv.imread("./picture/right1.jpg")
cv.imshow("input", src)
src = cv.GaussianBlur(src, (3, 3), 0) # 高斯去噪
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
res, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU) # OTSU阈值
cv.imshow("binary", binary)
contours,hierachy=cv.findContours(binary,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE) #轮廓查找
print("total number",len(contours))
#不计算距离
h,w=src.shape[:2]
for row in range(h):
for col in range(w):
dist_flag=cv.pointPolygonTest(contours[0],(col,row),False) #为False返回 -1、0、1三个固定值。若返回值为+1,表示点在多边形内部
if dist_flag>0: #当measureDist设置为true时,返回实际距离值。若返回值为正,表示点在多边形内部,返回值为负,表示在多边形外部
src[row,col]=(255,0,0)
if dist_flag<0:
src[row,col]=(0,0,255)
cv.imshow("ppt-demp",src)
#计算距离
h,w=src.shape[:2]
src1=np.copy(src)
for row in range(h):
for col in range(w):
dist=cv.pointPolygonTest(contours[0],(col,row),True) #为False返回 -1、0、1三个固定值。若返回值为+1,表示点在多边形内部
if dist>0: #内部 #当measureDist设置为true时,返回实际距离值。若返回值为正,表示点在多边形内部,返回值为负,表示在多边形外部
src1[row,col]=(np.abs(dist),0,0)
if dist<0: #外部
src1[row,col]=(0,0,155-np.abs(dist))
cv.imshow("ppt-demp1",src1)
第十二节:图像投影
图像投影的基本概念
插值拟合与权重分割
API知识点:没有新的API知识点,就是遍历,记录每行每列的点数,用plt显示
二值化
像素统计
直方图显示
from matplotlib import pyplot as plt
def binary_projection_demo():
src = cv.imread("./picture/canjian.jpg")
cv.imshow("input", src)
src = cv.GaussianBlur(src, (3, 3), 0) # 高斯去噪
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
res, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU) # OTSU阈值
cv.imshow("binary", binary)
#投影
h,w=gray.shape
y_projection=np.zeros((h),dtype=32)
x_projection = np.zeros((w), dtype=32)
for row in range(h):
count=0
for col in range(w):
pv=binary[row,col]
if pv==255: #因为二值化过了
count+=1
y_projection[row]=count
for col in range(w):
count=0
for row in range(h):
pv=binary[row,col]
if pv==255: #因为二值化过了
count+=1
x_projection[col]=count
plt.plot(y_projection,color="b")
plt.xlim([0,h])
plt.show()
plt.plot(x_projection, color="r")
plt.xlim([0, w])
plt.show()
第十三节:轮廓匹配
Hu距不变性
Hu不变距,Hu不变矩在图像旋转、缩放、平移等操作后,仍能保持矩的不变性,所以有时候用Hu不变距更能识别图像的特征
计算方法
moments()来计算图像中的中心矩(最高到三阶),HuMoments()用于由中心矩计算Hu矩.
def match_shape_demo():
src1 = cv.imread("./picture/m2.jpg",cv.IMREAD_GRAYSCALE)
src2 = cv.imread("./picture/m3.jpg",cv.IMREAD_GRAYSCALE)
cv.imshow("input-1",src1)
cv.imshow("input-2",src2)
#二值化
ret1,binary1=cv.threshold(src1,0,255,cv.THRESH_BINARY|cv.THRESH_OTSU) #利用OSTU,自动二值化
ret2, binary2 = cv.threshold(src2, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU) # 利用OSTU,自动二值化
cv.imshow("binary1", binary1)
cv.imshow("binary2", binary2)
contours1,hierachy2=cv.findContours(binary1,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE)
contours2,hierachy2=cv.findContours(binary2,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE)
mm1=cv.moments(contours1[0])
mm2=cv.moments(contours2[0])
hu1=cv.HuMoments(mm1)
hu2=cv.HuMoments(mm2)
distance=cv.matchShapes(hu1,hu2,cv.CONTOURS_MATCH_I1,0) #数值越小,差距越小
print(distance)
第十四节:直线检测
霍夫直线检测
API知识点
#第十四节:直线检测
def hough_line_demo():
src =cv.imread("./picture/route.jpg")
cv.imshow("input",src)
src=cv.GaussianBlur(src,(3,3),0)
#边缘提取 #阈值
edges=cv.Canny(src,180,300,apertureSize=3)
cv.imshow("edges",edges)
lines=cv.HoughLines(edges,1,np.pi/180,150,None,0,0)
if lines is not None:
for i in range(0,len(lines)):
rho=lines[i][0][0]
theta=lines[i][0][1]
a=math.cos(theta)
b=math.sin(theta)
x0=a*rho
y0=b*rho
pt1=(int(x0+500*(-b)),int(y0+a*500))
pt2=(int(x0-500*(-b)),int(y0-a*500))
cv.line(src,pt1,pt2,(0,0,255),2,8,0)
cv.imshow("hough-line",src)
image=np.copy(src)
linesP=cv.HoughLinesP(edges,1,np.pi/180,100,None,50,10)
if lines is not None:
for i in range(0, len(linesP)):
l=linesP[i][0]
cv.line(src,(l[0],l[1]),(l[2],l[3]),(255,0,0),2,8,0)
cv.imshow("hough-line_s",image)
第二十节:视频读写
视频文件读写
摄像头读写
摄像头读写属性
Videocapture函数,摄像头index从0开始
视频帧率与宽高
API知识点
capture=cv.VideoCapture(“./picture/vtest.avi”)#读视频文件
capture=cv.VideoCapture(0) #读摄像头
#写出保存视频 out=cv.VideoWriter(“C:/Users/LENOVO/Desktop/mv/test.mp4”,cv.VideoWriter_fourcc(‘D’,‘I’,‘V’,‘x’),15,((width),(height)),True)
#第二十节:视频读写
def video_io_demo():
capture=cv.VideoCapture("./picture/vtest.avi")#读视频文件
height=capture.get(cv.CAP_PROP_FRAME_HEIGHT) #获取视频高度
width=capture.get(cv.CAP_PROP_FRAME_WIDTH) #获取视频宽度
count = capture.get(cv.CAP_PROP_FRAME_COUNT) #获取帧数
fps=capture.get(cv.CAP_PROP_FPS) #获得帧率 :每秒钟的帧数
print(height,width,count,fps)
while(True):
ret,frame=capture.read()
if ret is True:
cv.imshow("video-input",frame)
c=cv.waitKey(100)
if c==27:
break #ESC
#第二十节:摄像头读写
def camera_i_demo():
capture=cv.VideoCapture(0) #读摄像头
height=capture.get(cv.CAP_PROP_FRAME_HEIGHT) #获取视频高度
width=capture.get(cv.CAP_PROP_FRAME_WIDTH) #获取视频宽度
count = capture.get(cv.CAP_PROP_FRAME_COUNT) #获取帧数
fps=capture.get(cv.CAP_PROP_FPS) #获得帧率 :每秒钟的帧数
print(height,width,count,fps)
#写出保存视频
out=cv.VideoWriter("C:/Users/LENOVO/Desktop/mv/test.mp4",cv.VideoWriter_fourcc('D','I','V','x'),15,((width),(height)),True)
while(True):
ret,frame=capture.read()
if ret is True:
cv.imshow("video-input",frame)
out.write(frame) #写出保存视频
c=cv.waitKey(100)
if c==27:
break #ESC
第二十一节:视频帧处理
#第二十一节:视频帧处理
def process_frame(frame,type):
if type==0:
gray =cv.cvtColor(frame,cv.COLOR_BGR2GRAY)
ret,binary=cv.threshold(gray,0,255,cv.THRESH_BINARY | cv.THRESH_OTSU)
binary=cv.adaptiveThreshold(gray,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,cv.THRESH_BINARY,25,10) #自适应阈值
return binary
if type ==1:
dst =cv.GaussianBlur(frame,(0,0),25)
return dst
if type==2: #unsharp_mask
kernel = np.array([[0, -1, 0], [-1, 4, -1], [0, -1, 0]])
im=cv.filter2D(frame,-1,kernel)
aw=cv.addWeighted(im,2,cv.GaussianBlur((frame,(0,0),15),-2,128))
return aw
else:
return frame
def camera_i_demo1():
capture=cv.VideoCapture(0) #读摄像头
height = capture.get(cv.CAP_PROP_FRAME_HEIGHT) # 获取视频高度
width = capture.get(cv.CAP_PROP_FRAME_WIDTH) # 获取视频宽度
#写出保存视频
out=cv.VideoWriter("C:/Users/LENOVO/Desktop/mv/test.mp4",cv.VideoWriter_fourcc('D','I','V','x'),15,((width),(height)),True)
while(True):
ret,frame=capture.read()
if ret is True:
cv.imshow("video-input",frame)
type=0
result=process_frame(frame,type)
cv.imshow("video-result",result)
c=cv.waitKey(100)
if c==27:
break #ESC
out.write(frame) # 写出保存视频
第二十二节:实时人脸检测
HAAR 与LBP人脸检测文件
HAAR
C:\Users\LENOVO\Desktop\opencv学习\opencv-4.x\data\haarcascades
人脸检测原理
API参数
#设置级联器:
#face_detecor=cv.CascadeClassifier("./picture/haarcascade_frontalface_alt_tree.xml")
face_detecor =cv.CascadeClassifier("picture/haarcascade_frontalface_default.xml")
def detect_face(frame):
gray=cv.cvtColor(frame,cv.COLOR_BGR2GRAY)
gray=cv.equalizeHist(gray) #利用直方图来增强对比度
faces=face_detecor.detectMultiScale(gray,1.2,4,minSize=(100,100),maxSize=(400,400)) #检测的最小,最大值
for x,y,w,h in faces:
cv.rectangle(frame,(x,y),(x+w,y+h),(0,0,255),2,8,0)
return frame
def camera_i_demo2():
capture=cv.VideoCapture(0) #读摄像头
height = 600
width =480
#写出保存视频
out=cv.VideoWriter("C:/Users/LENOVO/Desktop/mv/test.mp4",cv.VideoWriter_fourcc('D','I','V','x'),15,((width),(height)),True)
while(True):
ret,frame=capture.read()
if ret is True:
result=detect_face(frame)
cv.imshow("video-result",result)
c=cv.waitKey(100)
if c==27:
break #ESC
out.write(frame) # 写出保存视频
第二十三节:背景分析
背景分析基本原理
常用方法:
KNN
GMM
BackgroundSubtractorMOG2用到的是基于自适应混合高斯背景建模的背景减除法,相对于BackgroundSubtractorMOG,其具有更好的抗干扰能力,特别是光照变化。
****ps:****BackgroundSubtractorMOG2等一些背景减除法、帧差法仅仅做运动检测,网上经常有人做个运动检测,再找个轮廓,拟合个椭圆就说跟踪了,混淆了概念,凡是没有建立帧与帧之间目标联系的,没有判断目标产生和目标消失的都不能算是跟踪吧。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QS3BrRrI-1649234244997)(C:\Users\LENOVO\AppData\Roaming\Typora\typora-user-images\image-20220404163648516.png)]
getStructuringElement函数会返回指定形状和尺寸的结构元素。
Mat getStructuringElement(int shape, Size esize, Point anchor = Point(-1, -1));
这个函数的第一个参数表示内核的形状,有三种形状可以选择。矩形:MORPH_RECT;
交叉形:MORPH_CROSS;
椭圆形:MORPH_ELLIPSE;
第二和第三个参数分别是内核的尺寸以及锚点的位置。一般在调用erode以及dilate函数之前,先定义一个Mat类型的变量来获得getStructuringElement函数的返回值。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-erU6p0KJ-1649234244998)(C:\Users\LENOVO\AppData\Roaming\Typora\typora-user-images\image-20220404164450911.png)]
##第二十三节:背景分析
def background_demo():
capture = cv.VideoCapture(0) # 读摄像头
bgfg=cv.createBackgroundSubtractorMOG2() #建立模型
k=cv.getStructuringElement(cv.MORPH_RECT,(3,3))
while (True):
ret, frame = capture.read()
if ret is True:
cv.imshow("video-input",frame)
mask=bgfg.apply(frame) #把模型应用到frame上
bg_image = bgfg.getBackgroundImage() #获得背景
mask=cv.morphologyEx(mask,cv.MORPH_OPEN,k) #获得前景mask
cv.imshow("video-result",mask)
cv.imshow("backgroung",bg_image)
c = cv.waitKey(100)
if c == 27:
break # ESC
第二十四:颜色对象跟踪
色彩空间变换与mask提取
形态学处理
#第二十四:颜色对象跟踪
def color_object_trace():
capture = cv.VideoCapture(0) # 读摄像头
k=cv.getStructuringElement(cv.MORPH_RECT,(5,5)) #用来给mask去噪
while (True):
ret, frame = capture.read()
if ret is True:
#利用颜色图像获得mask
cv.imshow("video-input", frame)
hsv=cv.cvtColor(frame,cv.COLOR_BGR2HSV)
mask=cv.inRange(hsv,(0,0,0),(180,255,46)) #获取指定颜色:黑色 范围内的mask
mask=cv.morphologyEx(mask,cv.MORPH_OPEN,k)
cv.imshow("mask",mask)
#利用mask,标记原图
contours, hierachy = cv.findContours(mask, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE) # 轮廓查找
print("total number", len(contours)) #获取轮廓
#获取最大轮廓
max=0
temp=0
index=-1
for i in range(len(contours)):
x,y,w,h=cv.boundingRect(contours[i])
temp=w*h
if temp>max:
max=temp
index=i
if index>=0:#防止一开始为空
x, y, w, h = cv.boundingRect(contours[index])
cv.rectangle(frame,(x,y),(x+w,h+y),(0,0,255),2,4,0)
cv.imshow("trace-object-demo",frame)
c = cv.waitKey(100)
if c == 27:
break # ESC
第二十五节:几何识别
多边形逼近几何形状识别
基本流程
contours, hierachy = cv.findContours(mask, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE) # 轮廓查找
print("total number", len(contours)) #获取轮廓
#获取最大轮廓
max=0
temp=0
index=-1
for i in range(len(contours)):
x,y,w,h=cv.boundingRect(contours[i])
temp=w*h
if temp>max:
max=temp
index=i
if index>=0:#防止一开始为空
x, y, w, h = cv.boundingRect(contours[index])
cv.rectangle(frame,(x,y),(x+w,h+y),(0,0,255),2,4,0)
cv.imshow("trace-object-demo",frame)
c = cv.waitKey(100)
if c == 27:
break # ESC
## 第二十五节:几何识别
多边形逼近几何形状识别
<img src="C:\Users\LENOVO\AppData\Roaming\Typora\typora-user-images\image-20220404194729420.png" alt="image-20220404194729420" style="zoom:67%;" />
基本流程
<img src="C:\Users\LENOVO\AppData\Roaming\Typora\typora-user-images\image-20220404194717631.png" alt="image-20220404194717631" style="zoom:67%;" />