一、图像的IO操作
cv2.imread(r‘路径’,0/1/-1) #读取图像
1表示彩图,0表示灰阶图像,-1带阿尔法通道 (透明度调整的通道)
img=cv2.imread(同上) #命名
print(img) #打印二维数组
print(img.shape) #打印尺寸
cv2.imshow(”名字“,图像的对象(上面这个图的名字如img)) #显示图像
cv2,.imwrite(r’保存路径‘,对象) #保存图像
k=cv.2.waitkey(0) #括号里的0使键盘处于等待状态‘
cv2.destroywindow(“名字”) #关闭窗口 destroyAllWindows关闭全部窗口
二、绘制基本图形
1、全0矩阵
zeros(shape,dtype=None,order=‘C’) #全0矩阵 类似于画布,画其他东西必须有这个!
· shape:矩阵大小 dtype:数据类型 order:数据排列顺序,默认按列排序
import numpy as np #好像需要numpy模块
img = np.zeros((300,300,3),dtype="uint8") #最后的3好像是通道的意思
2、直线
cv2.line(img,pt1,pt2,color,thickness=1,line_type=8 shift=0) # 直线 两点定线(起点终点)
· 主要参数 ——pt1:直线起点 pt2:直线终点 color:线颜色 thickness:线宽
green = (0,255,0) #定义颜色 (B,G,R)
cv2.line(canvas,(0,0),(300,300),green,2) #绿线 起点终点都是坐标
cv2.imshow("Canvas",canvas)
cv2.waitKey(0)
3、矩形
cv2.rectangle(img, pt1, pt2, color, thickness=None, lineType=None, shift=None) # 矩形
· 主要参数——pt1:左上角起点 pt2:右下角终点 color:颜色 thickness:线宽/4。
cv2.rectangle(canvas,(10,10),(60,60),green) #绿色矩形
cv2.imshow("Canvas",canvas)
cv2.waitKey(0)
4、圆形
cv2.circle(img, center, radius, color, thickness=None, lineType=None, shift=None) #圆形
· 主要参数——center:圆心 radius:半径 color:颜色 thickness:线宽
cv2.circle(canvas,(150,150),50,(55,255,155),5)
cv2.circle(canvas,(150,150),50,(55,255,155),-1) #-1表示颜色填充
cv2.imshow("Canvas",canvas)
cv2.waitKey(0)
5、椭圆
cv2.ellipse(img, center, axes, angle, start_angle, end_angle, color, thickness=1, line_type=8, shift=0) #椭圆
· 主要参数——center:圆心 axes:(长轴长度,短轴长度) angle:偏转角度 start_angle:椭圆弧起始角度 end_angle:椭圆弧终止角度
cv2.ellipse(img,(200,200),(200,100),20,0,360,250,-1)
cv2.imshow("tuo",img)
#(200,200)是中心,(200长轴,100短轴),20旋转角度,0从几度开始画,360画到360度
6、随机圆
import cv2
import numpy as np
from matplotlib import pyplot as plt
for i in range(0, 25):
radius = np.random.randint(5, high=200)
color = np.random.randint(0, high=256, size=(3,)).tolist()
pt = np.random.randint(0, high=300, size=(2,))
cv2.circle(canvas, tuple(pt), radius, color, -1)
#np.random.randint(下限,high=上限-不含这个数,size=(几个,-加逗号,1的话不用写))
plt.imshow(canvas, 'brg')
plt.show()
7、同心圆
for a in range(0, 7):
radius = np.random.randint(5,high=200)
color = np.random.randint(0, high=256, size=(3,)).tolist()
cv2.circle(heart,(200,200),radius,color,2)
cv2.imshow("heart",heart)
8、多边形
三、色彩空间的改变
基础:每一原色就是一个通道,有时BGR三个通道再加一个A通道,阿尔法通道,控制透明度
1、在OpenCV中,有超过150种色彩空间转换的函数。但这里只介绍两种常用的:BGR与Gray,BGR与HSV。BGR:三原色。HSV:色调,饱和度,明度。
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #BGR转GRAY
hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV) #BGR转HSV
cv2.imshow("hsv",hsv)
cv2.imshow("gray",gray)
四、几何变换
1、图像缩放
(1)手动指定
cv2.resize(画布,(xxx,xxx新尺寸),interpolation=) #修改尺寸(不等比)
new_gua = cv2.resize(img,(200,200),interpolation=cv2.INTER_AREA)
优选的插值方法是用于缩小的cv2.INTER_AREA #缩小用这个
用于缩放的cv2.INTER_CUBIC(慢)和cv2.INTER_LINEAR #放大
(2)等比指定
cv2.resize(img,(int(img.shape [1] / 2 ),int(img.shape [0] / 2 ) )) #等比缩小
cv2.resize(src,dsize=,dst=,fx=,fy=,interpolation=)
new_gua = cv2.resize(img,None,fx=2,fy=2,interpolation=cv2.INTER_AREA)
dsize是目标图像大小,dst:目标图像,fx=是水平方向变成几倍,fy=是竖直方向变成几倍,inter插值方式
- 因为dsize是没有默认值的,所以必须指定,也即我们使用fx和fy来控制大小的时候必须设置dsize=(0,0)或者None
插值方式 | 含义 |
---|---|
cv2.INTER_NEAREST | 最近邻插值法 |
cv2. INTER_LINEAR | 双线性插值法(默认) |
cv2.INTER_AREA | 基于局部像素的重采样 |
cv2.INTER_CUBIC | 基于4x4像素邻域的3次插值法 |
cv2.INTER_LANCZOS4 | 基于8x8像素邻域的Lanczos插值 |
2、图像旋转
(1)翻转
cv2.flip (画布,flipCode,dst )
flipCode | 指令 |
---|---|
1 | 水平翻转 |
0 | 垂直翻转 |
-1 | 水平垂直翻转 |
new = cv2.flip(img,0)
cv2.imshow("new",new)
new = cv2.flip(img,1)
cv2.imshow("new",new)
new = cv2.flip(img,-1)
cv2.imshow("new",new)
cv2.waitKey(0)
(2)旋转 / / 引出仿射变换
仿射变换变化包括缩放(Scale、平移(transform)、旋转(rotate)、反射(reflection,对图形照镜子)、错切(shear mapping,感觉像是一个图形的倒影),原来的直线仿射变换后还是直线,原来的平行线经过仿射变换之后还是平行线,这就是仿射。只需要三个点的原因是,三点确定一个平行四边形,而经过仿射变换的平行四边形仍为平行四边形。
通过 warpAffine函数实现
M:变换矩阵 dsize:图像大小 flags:插值方式 borderMode :边界像素模式 borderValue:边界填充值; 默认情况下,它为0
rot_mat = cv2.getRotationMatrix2D((0,0),45, 1) #变换矩阵
img2 = cv2.warpAffine(img,rot_mat,(img.shape[1], img.shape[0]))
#实现变换
cv2.imshow("xuan_zhuan",img2) #显示变换后的图像
getRbtationMatrix2D函数为计算旋转中变换矩阵的函数,
cv2.getRotationMatrix2D ( ( 旋转中心 ) , 旋转角度-有正负 , 按什么比例的图片旋转)
3、图像平移
pst1 = np.float32([[0,0],[162,0],[0,120]])
pst2 = np.float32([[20,20],[182,20],[20,140]])
M = cv2.getAffineTransform(pst1, pst2)
dst = cv2.warpAffine(img, M, (img.shape[0],img.shape[1]))
cv2.imshow("pingyi",dst)
pst1 = np.float32([[0,0],[img.shape[0],0],[0,img.shape[1]]]) ##用这种方式表示也能出来
pst2 = np.float32( [ [img.shape[0],img.shape[1]],
[2*img.shape[0],img.shape[1]],
[img.shape[0],img.shape[1]*2] ] )
getAffineTransform 函数为求得仿射变化矩阵的函数,由三对变化前后对应的点可求得:
getAffineTransform(变化前的三个点,变化后的三个点)
点的坐标由np.float32 ( [ [点1],[点2],[点3] ] ) 表示出来
4、仿射变换
仿射变换变化包括缩放(Scale、平移(transform)、旋转(rotate)、反射(reflection,对图形照镜子)、错切(shear mapping,感觉像是一个图形的倒影),原来的直线仿射变换后还是直线,原来的平行线经过仿射变换之后还是平行线,这就是仿射。只需要三个点的原因是,三点确定一个平行四边形,而经过仿射变换的平行四边形仍为平行四边形。在opencv中可以利用cv2.warpAffine(img,M,(cols,rows))实现仿射变换,变换矩阵可以通过cv2.GetAffineTransform(src,dst)获得。在opencv中可以利用cv2.warpPerspective(img,M,(cols,rows))实现仿射变换,参数与仿射变换相同——源图像、变换矩阵、形状。
(1)仿射变换里的缩放
pst1 = np.float32([[0,0],[img.shape[0],0],[0,img.shape[1]]])
pst2 = np.float32([[0,0],[img.shape[0]/2,0],[0,img.shape[1]/2]]) #右上左下两个端点变成1/2
M = cv2.getAffineTransform(pst1, pst2)
dst = cv2.warpAffine(img, M, (img.shape[0],img.shape[1]))
cv2.imshow("pingyi",dst)
(2)平移
(3)旋转
(4)镜像
原理一样
pst1 = np.float32([[0,0],[162,0],[0,img.shape[1]]])
pst2 = np.float32([[162,0],[0,0],[162,img.shape[1]]])
M = cv2.getAffineTransform(pst1, pst2)
dst = cv2.warpAffine(img, M, (162,120))
cv2.imshow("pingyi",dst)
5、透射变换
透射变换是二维(x,y)到三维(X,Y,Z),再到另一个二维(x’,y’)空间的映射,利用透射中心、像点、目标点三点共线的条件,将图片投影到一个新的视平面,仍能保持承影面上投影几何图形不变。在opencv中可以利用**cv2.warpPerspective(img,M,(cols,rows))实现透射变换,参数与仿射变换相同——源图像、变换矩阵、形状。变换矩阵通过函数cv2.getPerspectiveTransform(src,dst)**获得,与仿射变换不同的是,需要四个对应点的坐标,因为在透射变换中平行四边形变为了一个四边形,而非平行四边形。
cv2.imshow("xie_",img1)
pst1 = np.float32([[123,175],[222,222],[127,249],[214,303]]) #原图上的坐标点(需要4个)
pst2 = np.float32([[0,0], [200,0], [0,200], [200,200]]) #新图上的四个位置 要一一对应
M = cv2.getPerspectiveTransform(pst1,pst2)
zheng = cv2.warpPerspective(img1,M,(200,200))
cv2.imshow("zheng",zheng) #效果图如下
6、图像金字塔(可以实现图像融合)
高斯金字塔,拉普拉斯金字塔(还原清晰度)
pyrUP pyrDown
五、形态学操作
1、腐蚀
new1 = cv2.erode(img,None,iterations=5)
cv2.imshow("new1",new1)
new2 = cv2.erode(img,None,iterations=10)
cv2.imshow("new2",new2)
iteration的值越高,模糊程度(腐蚀程度)就越高 呈正相关关系
iterations的值越大,腐蚀的越彻底( 图一为原图 图二为 it = 5 , 图三为 it = 10,经过测试=100是全没了)
作用:
1、前景物体会变小,整幅图像的白色区域会减少,这对于去除白噪声很有用。
2、平滑对象边缘
3、弱化或分割图像之间的半岛型连接
2、膨胀
old1 = cv2.dilate(img,None,iterations=5)
cv2.imshow("old1",old1)
与上大致相同
3、开闭运算
(1)开运算 cv2.morphologyEx( img, cv2.MORPH_OPEN, kernel )
开运算 = 先腐蚀运算,再膨胀运算(看上去把细微连在一起的两块目标分开了)
(1)开运算能够除去孤立的小点,毛刺和小桥,而总的位置和形状不便。
(2)开运算是一个基于几何运算的滤波器。
(3)结构元素大小的不同将导致滤波效果的不同。
(4)不同的结构元素的选择导致了不同的分割,即提取出不同的特征。
(2)闭运算 cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel, iterations=2)
闭运算 = 先膨胀运算,再腐蚀运算(看上去将两个细微连接的图块封闭在一起)
(1)闭运算能够填平小湖(即小孔),弥合小裂缝,而总的位置和形状不变。
(2)闭运算是通过填充图像的凹角来滤波图像的。
(3)结构元素大小的不同将导致滤波效果的不同。
(4)不同结构元素的选择导致了不同的分割。
new1 = cv2.morphologyEx(img,cv2.MORPH_OPEN,None,iterations=1)
cv2.imshow("new1",new1)
new2 = cv2.morphologyEx(img,cv2.MORPH_CLOSE,None,iterations=50)
cv2.imshow("new2",new2) #图一开 图二闭
六、图像平滑处理
图像滤波,即在尽量保留图像细节特征的条件下对目标图像的噪声进行抑制,是图像预处理中不可缺少的操作,其处理效果的好坏将直接影响到后续图像处理和分析的有效性和可靠性。
1、均值滤波
缺陷:均值滤波本身存在着固有的缺陷,即它不能很好地保护图像细节,在图像去噪的同时也破坏了图像的细节部分,从而使图像变得模糊,不能很好地去除噪声点。特别是椒盐噪声
实现均值滤波的核心函数如下:
result = cv2.blur(src,kernel),其中src是原图像,kernel是核大小。
jiangzao=cv2.blur(img,(10,10))
cv2.imshow("jiangzao",jiangzao)
2、高斯滤波
Python中OpenCV主要调用GaussianBlur函数,如下:
result = cv2.GaussianBlur(src, ksize, sigmaX)
其中sigmaX表示X方向方差,通常为0。核大小(N, N)必须是奇数。
result = cv2.GaussianBlur(img, (3,3), 0)
cv2.imshow("gaosi",result)
3、中值滤波
OpenCV主要调用medianBlur()函数实现中值滤波。
result = cv2.medianBlur(src, kernel)
核必须是大于1的奇数,如3、5、7等。
result1 = cv2.medianBlur(img, 3)
cv2.imshow("zhongzhi",result1)
七、直方图
1、灰度直方图
图像的灰度直方图(histogram),就是将图像转化成灰度图像之后,统计各个像素点的灰度值,绘制成直方图,其横轴是灰度值(0,255),纵轴是该灰度值所对应的像素的数目。对灰度直方图做积分=图像的size。
由原理可得:
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #转成灰色
cv2.imshow("kugua",gray)
new = plt.hist(gray.ravel(),256) #描绘出直方图
plt.show()
.hist()作用是绘制直方图
.ravel()作用是将多维数组降为一维数组,格式为:一维数组 = 多维数组.ravel()
2、直方图均衡化
直方图均衡化的目的是使得图片的灰度直方图分布更加平均,为了维持同一灰度 级的像素点均衡化后仍然是同一灰度级的,均衡化后的直方图往往不是完全平均分配的)
equ = cv2.equalizeHist(img2)
cv2.imshow("night",equ)
print(img.shape)
3、自适应的直方图均衡化
确实,直方图均衡后背景对比度有所改善.但比较两个图像,由于亮度过高,我们丢失了大部分信息,这是因为它的直方图并不局限于特定区域
img=cv2.imread(r"D:\XTNDX\pic\night.JPG",0) #注意要导入黑白的图片或者随后转换成黑白的
equ = cv2.equalizeHist(img2) #使用cv2.equalizeHist实现像素点的均衡化
# 使用自适应直方图均衡化
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8)) # 第一步:实例化自适应直方图均衡化函数
clahe = clahe.apply(img2) # 第二步:进行自适应直方图均衡化
cv2.imshow("auto",clahe) # 第三步:进行图像的展示
原图和自动化均衡化的对比:wogua为原图
自动化均衡和一般均衡的对比:auto为自动化
七、边缘检测
1、sobel 算子(精确度低1 2 1)
sobel算子的原理,对传进来的图像像素做卷积,卷积的实质是在求梯度值,或者说给了一个加权平均,其中权值就是所谓的卷积核;然后对生成的新像素灰度值做阈值运算,以此来确定边缘信息。
· 计算不同方向的梯度: 卷积核
dst = cv2.Sobel( src , ddepth , dx , dy , [ ksize] )
src:原始图像 ddepth:处理结果图像深度 dx:x方向 dy:y方向 ksize:核大小(3或者奇数)
· 计算两幅图像的权重和:
dst = cv2.addWeighted( src1,alpha,src2,beta,gamma)
alpha:图像1的系数 beta:2的系数 gamma:修正值
dst = saturate( 图1 * 系数 +图2 * 系数+gamma)
# sobely = cv2.Sobel ( o,cv2.CV_64F,0,1 ) #-1表示负数舍去变成0
sobely = cv2.Sobel ( o,cv2.CV_64F,0,1 ) #cv2.CV_64F表示保留负数
sobelx = cv2.Sobel ( o,cv2.CV_64F,1,0 )
sobely = cv2.convertScaleAbs( sobely ) #将得到的负值手动调整为正值
sobelx = cv2.convertScaleAbs( sobelx )
sobelxy=cv2.addWeighted ( soblex,0.5,sobely,0.5,0) #下图的all
sobelxy = cv2.Sobel ( o,cv2,CV_64F,1,1 ) #一起显示出来没一个一个显示完加起来效果好 下图的all2
优点:计算简单,速度很快;
缺点:计算方向单一,对复杂纹理的情况显得乏力
2、Scharr算子(精确度高3 10 3)
虽然Sobel算子可以有效的提取图像边缘,但是对图像中较弱的边缘提取效果较差。因此为了能够有效的提取出较弱的边缘,需要将像素值间的差距增大,因此引入Scharr算子。
函数类似于sobel,完全等价于sobel括号里加-1
x2=cv2.Scharr(o,cv2.CV_64F,1,0) #等价于sobelx = cv2.Sobel ( o,cv2.CV_64F,1,0,-1 )
x2=cv2.convertScaleAbs(x2)
cv2.imshow("charr_x",x2)
y2=cv2.Scharr(o,cv2.CV_64F,0,1)
y2=cv2.convertScaleAbs(y2)
cv2.imshow("charr_y",y2)
all_charr=cv2.addWeighted(x2,1,y2,1,0)
cv2.imshow("all_charr",all_charr)
比较:精度高低体现在不同像素点之间处理时是否体现出不同,体现出来就是Scharr可以检测出差别更小的各像素点,所以更图像更花,sobel因为检测不出来所以差别较小的差异自动忽略,所以就不是那么花。
3、laplacian算子
类似于二阶sobel导数,通过调用sobel算子来计算拉普拉斯算子
dst = cv2.Laplacian( src,ddepth )
lap_all=cv2.Laplacian(o,cv2.CV_64F)
cv2.imshow("lap",lap_all)
八、Canny边缘检测
1、基本原理
由四步组成:
(1)噪声去除:由于边缘检测很容易收到噪声的影响,所以首先使用 5x5 高斯滤波去除噪声。——用图像平滑部分的高斯滤波。
result = cv2.GaussianBlur(img, (5,5), 0)
(2)计算图像梯度:对平滑后的图像用Sobel算子计算dx和dy。
(3)非极大值抑制:不是极大值就被抑制为0,最后得到有细边的二进制图像(只有黑白)。具体操作:在获得梯度的方向和大小之后,对整幅图像进行扫描,去除那些非边界上的点,对每一个像素进行检查,看这个点的梯度是不是周 围具有相同梯度方向的点中最大的
(4)滞后阈值
设置两个阈值,minVal和maxVal。灰度梯度高于max被确定为真边界,低于min的被抛弃,位于两者之间的,就考虑是否跟真边界相连,如果相连就保存,不相连被抛弃。
2、API分析(设置阈值?)
canny = cv2.Canny( img,threshold1,threshold2) # threshold:门槛
img:灰度图 th1:minVal,较小的阈值将间断的边缘连接起来
th2:maxVal,较大的阈值检测图像中明显的边缘
“API(Application-Programming-Interface,应用程序编程接口)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。”
3、实例
img=cv2.imread(r"D:\XTNDX\pic\tom.jpg",0) #导入灰色图
cv2.imshow("old",img)
img=cv2.medianBlur(img,3) #应该用高斯滤波,这里中值滤波效果好
x=cv2.Sobel(img,cv2.CV_64F,1,0) #算梯度
x=cv2.convertScaleAbs(x)
y=cv2.Sobel(img,cv2.CV_64F,0,1)
y=cv2.convertScaleAbs(y)
all=cv2.addWeighted(x,0.3,y,0.3,0) #sobel算子边缘图
canny=cv2.Canny(all,200,255) #canny检测
cv2.imshow("result",canny)
img=cv2.imread(r"D:\XTNDX\pic\tom.jpg",1) #没有用算子的情况 更清楚
cv2.imshow("old",img)
img=cv2.medianBlur(img,3)
canny=cv2.Canny(img,200,255)
cv2.imshow("result",canny)
九、模板匹配和霍夫变换
1、模板匹配
模板匹配就是拿到一个模板图像,然后模板在原图像里从左到右,从上到下,每次移动一个像素,就能得到原图像里跟模板图像大小相同的一块,然后计算两者的是否相似,直到 模板在原图像中游走完。计算得到两者相似的计算量后,就可以找到最小值或最大值,从而确定模板与原图像哪一小块的图像最接近,即可以得到模板从属原图像的位置。
OpenCV中进行匹配的函数是:matchTemplate,六种匹配方式,平方差匹配,互相关匹配,相关性系数匹配,另外三种则是在此三种的基础上进行归一化。
cv2.matchTemplata ( img_big,img_temp,cv2.method )
img_big:在该图上查找图像
img_temp:待查找的图像,模板图像
method: 模板匹配的方法
六种方法:
1、TM_SQDIFF 判断 minVal 越小,效果越好
计算模板与目标图像的方差,由于是像素值差值的平方的和,所以值越小匹配程度越高;
2、TM_SQDIFF_NORMED 判断 minVal 越接近0,效果越好
范化的cv::TM_SQDIFF,取值为0-1之间,完美匹配返回值为0;(测试里这个识别出来了)
3、TM_CCORR 判断 maxVal 越大,效果越好
使用dot product计算匹配度,越高匹配度就好;
4、TM_CCORR_NORMED 判断 maxVal 越接近1,效果越好
范化的cv::TM_CCORR,0-1之间,(网传效果最好)
5、TM_CCOEFF 判断 maxVal 越大,效果越好
采用模板与目标图像像素与各自图像的平均值计算dot product,正值越大匹配度越高,负值越大图像的区别越大,但如果图像没有明显的特征(即图像中的像素值与平均值接近)则返回值越接近0;
6、TM_CCOEFF_NORMED 判断 maxVal 越接近1,效果越好
范化的cv::TM_CCOEFF,-1 ~ 1之间。
yuan1=cv2.imread(r"D:\XTNDX\pic\ju_jing_yi.jpg",1)
yuan=cv2.imread(r"D:\XTNDX\pic\ju_jing_yi.jpg",0)
ban=cv2.imread(r"D:\XTNDX\pic\mu_ban.jpg",0)
w,h=ban.shape[::-1]
print(w,h)
res=cv2.matchTemplate(yuan,ban,cv2.TM_SQDIFF_NORMED)
min_val,max_val,min_loc,max_loc=cv2.minMaxLoc(res)
L_U = min_loc
R_D = (L_U[0]+w , L_U[1]+h )
cv2.rectangle(yuan1,L_U,R_D,(0,0,255),2)
cv2.imshow("over",yuan1)
cv2.imshow("tu",ban)
2、霍夫变换(识别图像中的几何图形)
经典的霍夫变换,用于检测图像中的直线
改进的霍夫变换,可检测图像中任意形状的图形
(1)霍夫线变换
标准霍夫变换、多尺度霍夫变换函数:HoughLines()
HoughLines(InputArray image, OutputArray lines, double rho, double theta, int threshold, double srn=0, double stn=0 )
参数1:要检测的二值图(一般是阈值分割或边缘检测后的图)
参数2:距离r的精度,值越小,考虑越多的线
参数3:角度θ的精度,值越小,考虑越多的线
参数4:累加数阈值,值越小,考虑越多的线
cv2.imshow("原图",img1)
black=cv2.medianBlur(img,3)
black=cv2.Canny(img,50,255)
cv2.imshow("二值图",black)
lines=cv2.HoughLines(black,1,np.pi/180,20)
for line in lines:
r,st=line[0]
a=np.cos(st)
b=np.sin(st)
x0=r*a
y0=r*b
x1 = int(x0 + 1000 * (-b))
y1 = int(y0 + 1000 * a)
x2 = int(x0 - 1000 * (-b))
y2 = int(y0 - 1000 * a)
cv2.line(img1,(x1,y1),(x2,y2),(0,0,250),2)
cv2.imshow("画线",img1)
累计概率霍夫变换函数:HoughLinesP
(2)霍夫圆变换
cv2.HoughCircles
circles = cv2.HoughCircles(black,cv2.HOUGH_GRADIENT,1,30,param1=40,param2=20,minRadius=5,maxRadius=100)
if not circles is None:
circles = np.uint16(np.around(circles))
for circle in circles:
x,y,r=circle[0]
cv2.circle(img1,(x,y),r,(0,0,225),4)
cv2.imshow("yuan",img1)
十、角点特征
滑动窗口各个方向上的像素值变化都很大,就是角点,只有一个方向的像素值变化大,是原来的边缘点。
Moravec只考虑4种方向,harris把方向细化考虑多个方向,
结论:与正面图相比,近景图和旋转图没有太大差别,远景图角点较多,亮光线图角点较少。
1、harris检测
函数:(图像,窗口大小,k)
cv2.imshow("harris",img)
#img2=cv2.cvtColor(img,cv2.COLOR_GRAY2BGR)
thres = 0.01*dst.max()
img2[ harris < thres ] = [255,255,255]
cv2.imshow("harris",img)
2、Shi-Tomasi 角点检测
函数:cv2.goodFeatuToTrack
shis=cv2.goodFeaturesToTrack(img,10,0.01,10)
shis=np.int0(shis)
red=(255,255,255)
for shi in shis: #把点画出来
x,y=shi.ravel()
cv2.circle(img,(x,y),2,red,2)
cv2.imshow("Shi",img)
第二个参数:绘制点的数量 第三个:最低标准
十一、视频操作
1、视频的读取和播放
1,视频也是由图像组成的,由一帧一帧组成,每一帧是一张图快速连贯起来变成视频。
2,cv2.VideoCapture( ‘xxxxxxxx’ ) 读取视频
展示视频的时候是把视频拆分成每一帧再把每一帧作展示操作
# 检查是否打开
if vc.isOpened():
open,frame = vc.read()
else:
open = 0
while open:
ret,frame = vc.read()
if frame is None:
break
if ret == 1:
cv2.imshow('result',frame)
ret,frame = vc.read()
if cv2.waitKey(100) & 0xFF == ord('q'):
break
vc.release()
(1)vc.read()表示当前读取的那一帧图像,一张普通图片,
(2)open,ret是布尔变量,只有真和假,为真说明视频拆分的每帧图像还有继续进行展示或者其他操作,为假说明图像拆完了。
(3)cv2.waitKey(n),括号里的n为数字,表示等待指令的时间,单位为毫秒,比如n=10000的时候,窗口打开10秒后自动关闭,为0时表示无限时间。| | | 在此处表示每一帧展示0.1秒后自动关闭开始展示下一帧也就是下一张图片,0.1s的间隔就会让视频看起来很卡。
(4)cap = cv2.VideoCapture(0) 括号里是数字的时候表示调用电脑的摄像头,0是内部摄像头,1,2,3…为外接摄像头。
(5)注意:Python2 版本中True False不是关键字,可被赋值,Python3中会报错;
2、视频保存
定义输出编码格式
cv2.VideoWriter_fourcc( *‘XVID’ )
也可以反过来写cv2.VideoWriter_fourcc( ‘D’ , ‘I’ , ‘V’ , ‘X’ )
输出文件配置
out = cv2.VidieoWriter( xxxxxxxxxxx )
( “文件名.avi”,编码格式,帧率,分辨率 )
(1)如果视频成功打开的话,读取视频当前帧的图像(2)如果还有图像(即视频还没播完)out.write(image),保存这一帧的图像到刚刚定义的输出文件out变量中,然后展示这帧的图像,等待一段时间waitKey后如果视频还有继续这个循环,继续读下一帧图像、存起来、展示、等待、继续下一帧···(3)如果视频播完就break。(4)释放视频,释放保存的文件。
cap = cv2.VideoCapture(0) # 摄像头录像
fourcc = cv2.VideoWriter_fourcc('D','I','V','X')
out = cv2.VideoWriter(r"D:\XTNDX\sucai\vid\test.avi",fourcc,30.0,(640,480))
while 1:
ret,frame = cap.read()
if ret == 1:
out.write(frame)
cv2.imshow("test",frame)
if cv2.waitKey(50) & 0xFF == ord('q'):
break
else:
break
cap.release()
out.release()
cv2.destroyAllWindows()
vc = cv2.VideoCapture(r"D:\XTNDX\sucai\vid\bear.mp4")
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter(r"D:\XTNDX\sucai\vid\record.avi",fourcc,30,(640,480))
while(vc.isOpened()):
ret,frame = vc.read()
if ret == 1:
out.write(frame)
cv2.imshow("show",frame)
cv2.waitKey(50)
else:
break
vc.release()
out.release() #视频录取
十二、图片和视频相互转换
首先FFmpeg是一个可执行文件,要在Python中调用FFmpeg并且监控它的状态,需要使用类似os.system()
或者是subprocess
模块来创建子进程,需要自己处理很多工作,比较麻烦……
ffmpy库就是帮我们解决这个问题的,完美整合FFmpeg,把子进程管理封装好了,我们直接输入好参数调用就完事了
在合并音频和视频要使用到ffmpeg这个工具
ff = ffmpy3.FFmpeg(
inputs = { 文件地址:说明 },
outputs = { 文件地址:说明},
) ps:说明是普通ffmpeg指令中的其他设定
(1)修改视频格式
(注意:地址里的斜杠必须是向左斜,要么前面加个小写r 不然右斜杠有转义的意思)
ff = FFmpeg(
inputs={'D:/XTNDX/sucai/vid/bear.mp4':None},
outputs={'D:/XTNDX/sucai/vid/bear2.avi':None}
)
print(ff.cmd)
ff.run()
(2)视频转图片
ffmpeg -i 视频地址 -r 视频帧率 图片地址/%04d.png -loglevel error
ff2 = FFmpeg(
inputs={r"D:\XTNDX\sucai\vid\bear2.avi":None},
outputs={r"D:\XTNDX\sucai\pic\img-%04d.png":'-r 1 -loglevel error'}
)
print(ff2.cmd)
ff2.run()
(3)图片转视频
ffmpeg -f image2(图片格式) -i c:\temp\d.jpg -vcodec libx264(编码格式) -r 10(输出帧率) test.mp4
ff3 = FFmpeg(
inputs={r"D:\XTNDX\sucai\pic\%04d.png":'-f image2 -r 1'},
outputs={r"D:\XTNDX\sucai\vid\bear3.avi":None}
)
print(ff3.cmd)
ff3.run()
(4)在dos窗口中执行
直接输出口令就可以,在Python中需要ffmpy连接ffmpeg
ps:说明是普通ffmpeg指令中的其他设定
(1)修改视频格式
(注意:地址里的斜杠必须是向左斜,要么前面加个小写r 不然右斜杠有转义的意思)
ff = FFmpeg(
inputs={'D:/XTNDX/sucai/vid/bear.mp4':None},
outputs={'D:/XTNDX/sucai/vid/bear2.avi':None}
)
print(ff.cmd)
ff.run()
(2)视频转图片
ffmpeg -i 视频地址 -r 视频帧率 图片地址/%04d.png -loglevel error
ff2 = FFmpeg(
inputs={r"D:\XTNDX\sucai\vid\bear2.avi":None},
outputs={r"D:\XTNDX\sucai\pic\img-%04d.png":'-r 1 -loglevel error'}
)
print(ff2.cmd)
ff2.run()
(3)图片转视频
ffmpeg -f image2(图片格式) -i c:\temp\d.jpg -vcodec libx264(编码格式) -r 10(输出帧率) test.mp4
ff3 = FFmpeg(
inputs={r"D:\XTNDX\sucai\pic\%04d.png":'-f image2 -r 1'},
outputs={r"D:\XTNDX\sucai\vid\bear3.avi":None}
)
print(ff3.cmd)
ff3.run()
(4)在dos窗口中执行
直接输出口令就可以,在Python中需要ffmpy连接ffmpeg