注意:文中cv使用前先执行 import cv2 as cv
图像的基础操作
cv.imread()读取图像
cv.imshow()显示图像
cv.imwrite()保存图像
图像上绘制图像
cv.line(img,start,end,color,thickness宽度)绘制直线
cv.circle(img,centerpoint圆心,r半径,color,thickness)绘制圆形
cv.rectangle(img,leftupper,rightdown左上角和右下角坐标,color,thickness)绘制矩形
cv.putText(img,text,station文本放置位置,font,fontsize,color,thickness,cv.LINE_AA)图像上添加文字
图像的加法
cv.add(img1,img2)
图像的混合
cv.addWeighted(img1,权值1,img2,1-权值1,0)
图像几何变换
图像缩放:cv.resize(src:输入图像,dsize:绝对尺寸,fx=0,fy=0:相对尺寸,将dsize=None,interpolation:插值方法)
插值方法:cv.INTER_LINEAR双线性插值法,cv.INTER_NEAREST最近邻插值,cv.INTER_AREA像素区域重采样(默认),cv.INTER_CUBIC双三次插值
图像平移:cv.warpAffine(img,M,dsize)
M:平移矩阵np.float32([1,0,100],[0,1,50])移动(50,100)距离
图像旋转:cv.getRotationMatrix2D(center:旋转中心,angle:旋转角度,scale:缩放比例)获取旋转矩阵,然后调用cv.warpAffine()进行旋转
仿射变换:cv.getAffineTransform()将创建变换矩阵,最后该矩阵传递给cv.warpAffine()进行变换
透射变换:cv.getPerspectiveTransform()找到变换矩阵,将cv.warpPerspective()进行投射变换
金字塔:cv.pyrUp()向上采样,cv.pyrDown()向下采样
图像形态学操作
连通性:4连通,8连通,m连通
腐蚀:cv.erode(img,kernel核结构,iterations腐蚀次数默认为1)
膨胀:cv.dilate(img,kernel核结构,iterations腐蚀次数默认为1)
开运算:cv.morphologyEx(img,cv.MORPH_OPEN,kernel核结构)先腐蚀后膨胀,分离物体、消除小区域,消除噪点,去除小的干扰块
闭运算:cv.morphologyEx(img,cv.MORPH_CLOSE,kernel核结构)先膨胀后腐蚀,消除闭合物体里面的孔洞,可以填充闭合区域
礼帽运算:cv.morphologyEx(img,cv.MORPH_TOPHAT,kernel核结构),原图与开运算之差,突出比原图轮廓周围给明亮的区域
黑帽运算:cv.morphologyEx(img,cv.MORPH_BLACKHAT,kernel核结构),闭运算与原图之差,突出比原图轮廓周围更暗的区域
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
from pylab import mpl
# 设置显示中文字体
mpl.rcParams["font.sans-serif"] = ["SimHei"]
# 设置正常显示符号
mpl.rcParams["axes.unicode_minus"] = False# 图像读取
img = cv.imread("D:\\true.jpg")
img2 = cv.imread("D:\\w_b.jpg")
#创建核结构
kernel = np.ones((5,5),np.uint8)#图像的开闭运算
cvOpen = cv.morphologyEx(img,cv.MORPH_OPEN,kernel)
cvClose = cv.morphologyEx(img,cv.MORPH_CLOSE,kernel)
cvTop = cv.morphologyEx(img2,cv.MORPH_TOPHAT,kernel)
cvBlack = cv.morphologyEx(img2,cv.MORPH_BLACKHAT,kernel)## 图像展示
fig,axes = plt.subplots(nrows=4,ncols=2,figsize=(6,16),dpi=100)
axes[0,0].imshow(img)
axes[0,0].set_title("原图")
axes[0,1].imshow(cvOpen)
axes[0,1].set_title("开运算")
axes[1,0].imshow(img)
axes[1,0].set_title("原图")
axes[1,1].imshow(cvClose)
axes[1,1].set_title("闭运算")
axes[2,0].imshow(img2)
axes[2,0].set_title("原图")
axes[2,1].imshow(cvTop)
axes[2,1].set_title("礼帽运算")
axes[3,0].imshow(img2)
axes[3,0].set_title("原图")
axes[3,1].imshow(cvBlack)
axes[3,1].set_title("黑猫运算")
plt.show()
图像平滑处理
均值滤波:cv.blur()---->去噪的同时去掉了许多细节部分,使图像变模糊
高斯滤波:cv.GaussianBlur()---->去除高斯噪声:噪声的概率密度分布是正态分布
中值滤波:cv.medianBlur()---->去除椒盐噪音:图像中随机出现的白点或者黑点
直方图 cv.calcHist([img],channels灰度图:[0],mask掩膜图像,统计整张原图的直方图设置为None,histSize:BIN的数目[256],ranges像素值范围[0,256])
直方图是图像中像素强度分布的图形表达方式
它统计了每一个强度值所具有的像素个数
不同的图像的直方图可能是相同的
掩膜的应用:用选定的掩膜对要处理的图像进行遮挡,控制图像处理的区域
掩膜:cv.bitwise_and(img,img,mask=mask)
直方图均衡化:对图像进行非线性拉伸,重新分配图像像素值,使一定灰度范围内的像素数量大致相同,可以提高图像整体的对比度,
dist:均衡化结果 = cv.equalizeHist(img灰度图)
自适应均衡化:直方图中的bin超过对比度上限,其中超过的像素点均匀的分散到其他的bin中,然后进行直方图均衡化,最后为了去除每一个小块之间的边界,使用双线性差值对每一个小块进行拼接,
clahe = cv.createCLANE(clipLimit对比度限制默认40,tileGridSize分块的大小默认8*8)
处理后的结果 = clahe.apply(img)
边缘检测
Sobel检测算子:高斯平滑+微分操作,抗噪声能力强
sobel_x_or_y = cv.Sobel(src,ddepth图像的深度,dx,dy某个方向求导的阶数0或者1,ksize算子大小默认为3(必须为奇数),scale缩放倒数的比例常数,borderType图像边界的模式默认cv.BORDER_DEFAULT)
Laplacian算子:利用二阶导数来检测边缘,过零点
laplacian = cv.Laplacian(src,ddepth,ksize)
Canny边缘检测
第一步:噪声去除,使用5*5高斯滤波器去噪
第二步:计算图像梯度,对平滑后的图像使用Sobel算子进行处理,计算梯度大小和方向
第三步:非极大值抑制,对比每个点的梯度是否为周围具有相同梯度方向的点中最大值进行保留
第四步:滞后阈值,确定真正的边界(minVal,maxVal)
#读取图像
img = cv.imread("E:\\01.jpg",0)
#计算Sobel卷积结果,存在小于0或者大于255的结果所有使用cv.CV_16S
x_Sobel = cv.Sobel(img,cv.CV_16S,1,0)#x方向
y_Sobel = cv.Sobel(img,cv.CV_16S,0,1)#y方向
#Scharr算子进行边缘检测,存在小于0或者大于255的结果所有使用cv.CV_16S
x_Scharr = cv.Sobel(img,cv.CV_16S,1,0,ksize=-1)#x方向
y_Scharr = cv.Sobel(img,cv.CV_16S,0,1,ksize=-1)#y方向
#Laplacian算子进行边缘检测,存在小于0或者大于255的结果所有使用cv.CV_16S
result_Laplacian = cv.Laplacian(img,cv.CV_16S)#将数据进行转换,图像处理万后转回uiut8格式否则图像无法显示
Scale_Sobel_absx = cv.convertScaleAbs(x_Sobel)
Scale_Sobel_absy = cv.convertScaleAbs(y_Sobel)
Scale_Scharr_absx = cv.convertScaleAbs(x_Scharr)
Scale_Scharr_absy = cv.convertScaleAbs(y_Scharr)
Laplacian_abs = cv.convertScaleAbs(result_Laplacian)#结果合成
result_Sobel = cv.addWeighted(Scale_Sobel_absx,0.5,Scale_Sobel_absy,0.5,0)
result_Scharr = cv.addWeighted(Scale_Scharr_absx,0.5,Scale_Scharr_absy,0.5,0)#Canny边缘检测
canny = cv.Canny(img,0,100)#显示图像
fig,axes = plt.subplots(nrows=4,ncols=2,figsize=(10,16),dpi=100)
axes[0,0].imshow(img,cmap="gray")
axes[0,0].set_title("原图")
axes[0,1].imshow(result_Sobel,cmap="gray")
axes[0,1].set_title("Sobel结果")
axes[1,0].imshow(img,cmap="gray")
axes[1,0].set_title("原图")
axes[1,1].imshow(result_Scharr,cmap="gray")
axes[1,1].set_title("Scharr结果")
axes[2,0].imshow(img,cmap="gray")
axes[2,0].set_title("原图")
axes[2,1].imshow(Laplacian_abs,cmap="gray")
axes[2,1].set_title("Laplacian结果")
axes[3,0].imshow(img,cmap="gray")
axes[3,0].set_title("原图")
axes[3,1].imshow(canny,cmap="gray")
axes[3,1].set_title("Canny结果")
plt.show()
模板匹配和霍夫变换
模板匹配:设置模板平移匹配(W-w+1,H-h+1)
res = cv.matchTemplate(img,template模板,method实现模板匹配的算法)
cv.minMaxLoc()查找最大值所在的位置,平方差找最小值位置
算法:
平方差匹配(cv.TM_SQDIFF)利用模板和图像之间的平方差进行匹配,最好的匹配是0,匹配越差,匹配值越大
相关匹配(cv.TM_CCORR)利用模板与图像之间的乘法进行匹配,数值越大表示匹配程度越高
利用相关关系匹配(cv.TM_CCOEFF)利用模板和图像之间的相关系数匹配,1表示完美,-1表现最差
#图像和模板读取
img = cv.imread("E:\\IMGL8129.jpg")
template = cv.imread("E:\\eyes.jpg")#模板匹配
res = cv.matchTemplate(img,template,cv.TM_SQDIFF)#平方差匹配
#res = cv.matchTemplate(img,template,cv.TM_CCORR)#相关匹配#返回图像中最匹配的位置,确定左上角坐标,并将匹配位置绘制在图像上
min_val,max_val,min_loc,max_loc = cv.minMaxLoc(res)#平方差匹配最小值为最佳匹配位置
top_left = min_loc# top_left = max_val
bottom_right = (top_left[0] + w,top_left[1] + h)
cv.rectangle(img,top_left,bottom_right,(0,255,0),2)#绘制匹配位置#显示图像
plt.figure(figsize=(10,8),dpi=100)
plt.subplot(121)
plt.imshow(template[:,:,::-1])
plt.title("模板")
plt.subplot(122)
plt.imshow(img[:,:,::-1])
plt.title("匹配结果")
plt.show()
霍夫变换:用来提取图像中的直线和圆等几何图形
笛卡尔坐标系点/线 <-------> 霍夫坐标系线/点
cv.HoughLines(img,rho,theta:精确度,threshold阈值:只有累加器中的值大于该阈值时才被认为是直线)
circles输出圆向量 = cv.HoughCircles(img,method:CV_HOUGH_GRADIENT,dp:霍夫空间的分辨率1表示大小一致,minDist,param1=100边缘检测使用Canny算子的高阈值,param2=100检测圆心和半径时共有的阈值,minRadius=0,maxRadius=100)
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
import random
from pylab import mpl
mpl.rcParams["font.sans-serif"] = ["SimHei"]
mpl.rcParams["axes.unicode_minus"] = False#加载图片,转为二值图
img = cv.imread("E:\\parking.jpg")
img_copy = np.copy(img)
img_gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
edges = cv.Canny(img_gray,50,150)#霍夫直线变换
lines = cv.HoughLines(edges,0.8,np.pi/180,150)
#将检测的直线绘制在图像上(注意:是极坐标)
for line in lines:
#print(line)
rho,theta = line[0]
a = np.cos(theta)
b = np.sin(theta)
x0 = a*rho
y0 = b*rho
x1 = int(x0 + 1000*(-b))
y1 = int(y0 + 1000*(a))
x2 = int(x0 - 1000*(-b))
y2 = int(y0 - 1000*(a))
cv.line(img_copy,(x1,y1),(x2,y2),(0,0,255))#显示图像
fig,axes = plt.subplots(nrows=2,ncols=2,figsize=(10,8),dpi=100)
axes[0,0].imshow(img)
axes[0,0].set_title("原图")
axes[0,1].imshow(edges)
axes[0,1].set_title("Canny")
axes[1,0].imshow(img)
axes[1,0].set_title("原图")
axes[1,1].imshow(img_copy)
axes[1,1].set_title("霍夫变换线检测")
plt.show()
img_cicle = cv.imread("E:\\01.jpg")
img_cicle_gray = cv.cvtColor(img_cicle,cv.COLOR_BGR2GRAY)#中值滤波
img_blur = cv.medianBlur(img_cicle_gray,7)#霍夫圆检测
circle = cv.HoughCircles(img_blur,cv.HOUGH_GRADIENT,1,100,param1=60,param2=40,minRadius=0,maxRadius=100)c = circle[0][0]
cv.circle(img_cicle,(c[0],c[1]),c[2],(255,0,0),2)#(c[0],c[1])圆心 c[2]半径
#cv.circle(img_cicle,238,2,(0,255,0),-1) #圆点填充plt.imshow(img_cicle)
图像特征提取与描述
Harris角点检测:将矩阵M的行列式值与M的迹相减,利用差值判断是否为角点
角点:沿着任意方向移动,有明显灰度变化
dst = cv.cornerHarris(src:数据类型为float32,blockSize角点检测中考虑的邻域大小,ksize:sobei求导使用的核大小,k:角点检测方程中的自由参数[0.04,0.06])
Shi-Tomasi:若矩阵M的两个特征值中较小的一个大于阈值,则认为是角点
corners:检测到的角点 = cv.goodFeaturesToTrack(img:输入灰度图像maxCorners:获取角点数的数目,qualityLevel:最低可接受的焦点质量水平(0-1),minDistance:角点间最小的欧式距离
SIFT算法:尺度不变特征转换
第一步:尺度空间极值检测:通过高斯差分函数识别潜在的对于尺度和旋转不变的关键点
尺度空间滤波器:高斯核
第二步:关键点定位:通过一个拟合精细的模型缺点位置和尺度,依据于稳定程度
第三步:关键点方向确定:基于图像局部的梯度方向,分配给每个关键点位置方向
第四步:关键点描述:在选定的尺度上测量图像局部的梯度
sift = cv.xfeatures2d.SIFT_create()实例化
kp:关键点信息,des:关键点描述符->128个特征向量 = sift.detectAndCompute(gray:进行关键点检测的灰度图像,None)
cv.drawKeypoints(img,keypoints:关键点信息,outputimage:输出图像,color,flags:绘制功能的标识设置)
flags:
cv.DRAW_MATCHES_FLAGS_DEFAULT:创建输出图像矩阵,使用现存的输出图像绘制匹配对和特征值,只绘制中间点
cv.DRAW_MATCHES_FLAGS_DRAW_OVER_OUTIMG:不创建图像矩阵,在输出图像上绘制匹配对
cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS:对每一个特征点绘制带大小和方向的关键点图形
cv.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS:单点的特征点不被绘制
SURF算法:同上
Fast算法:用于角点检测的算法,若一个像素周围有一定数量的像素与该点像素值不同,则认为其为角点,r半径=3 --> M像素点=16 --> n连续像素点=12
实例化:fast:FastFeatureDetector对象 = cv.FastFeatureDetector_create(threshold:阈值t默认10,nonmaxSuppression:是否进行非极大值抑制默认True
检测关键点;kp:关键点信息 = fast.detect(gray,None)
绘制结果:cv.drawKeypoints(img,keypoints,outputimage,color,flags)
!!!免费 ORB算法:结合Fast和Brief算法
BRIEF算法:特征描述子提取算法,一种生成二值化描述子的算法
第一步:图像滤波
第二步:选取点对:特征点为中心
第三步:构建描述符,128-512位的字符串
实例化:orb = cv.xfeatures2d.orb_create(nfeatures:特征点的最大数量)
检测关键点并计算:kp,des = orb.detectAndCompute(gray,None)
绘制:cv.drawKeypoints(img,keypoints,outputimage,color,flags)
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
from pylab import mpl
# 设置显示中文字体
mpl.rcParams["font.sans-serif"] = ["SimHei"]
# 设置正常显示符号
mpl.rcParams["axes.unicode_minus"] = False#Harris检测
img = cv.imread("E:\\b_w.jpg")
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)#转换数据格式
gray = np.float32(gray)#src:数据类型为float32,blockSize角点检测中考虑的邻域大小,ksize:sobei求导使用的核大小,k:角点检测方程中的自由参数[0.04,0.06]
dst = cv.cornerHarris(gray,2,3,0.04)
img[dst>0.001*dst.max()] = (0,0,255)
plt.figure(figsize=(10,10),dpi=100)
plt.imshow(img[:,:,::-1])
tomas检测
img2 = cv.imread("E:\\kuchalou.jpg")
gray2 = cv.cvtColor(img2,cv.COLOR_BGR2GRAY)#corners:检测到的角点 = cv.goodFeaturesToTrack(img:输入灰度图像,maxCorners:获取角点数的数目,qualityLevel:最低可接受的焦点质量水平(0-1),minDistance:角点间最小的欧式距离
corners = cv.goodFeaturesToTrack(gray2,1000,0.01,10)for i in corners:
x,y = i.ravel()#评估为坐标
cv.circle(img2,(x,y),2,(0,0,255),-1)plt.figure(figsize=(10,10),dpi=100)
plt.imshow(img2[:,:,::-1])
plt.show()