黄捷洲 CSDN-AI13期学员
一个二维的滤波器矩阵(也就是卷积核)和一个要处理的二维图像;对于图像的每一个像素点,计算它的邻域像素和滤波器矩阵的对应元素的乘积,然后加起来,作为该像素位置的值,这样就完成了滤波过程。
不难发现,用3×3的核对一副6×6的图像进行卷积,得到的是4×4的图,图片缩小了!那怎么办呢?我们可以把原图扩充一圈,再卷积,这个操作叫padding。
事实上,原图为n×n,卷积核为f×f,最终结果图大小为(n-f+1) × (n-f+1)
cv2.copyMakeBorder()
用来给图片添加边框,它有下面几个参数:
常用的填充类型有:固定值填充,取镜像对称的像素填充等。
均值滤波是一种典型的线性滤波算法,主要是利用像素点邻域的像素值来计算像素点的值。其具体方法是首先给出一个滤波模板kernel,该模板将覆盖像素点周围的其他邻域像素点,去掉像素本身,将其邻域像素点相加然后取平均值即为该像素点的新的像素值,这就是均值滤波的本质。
函数:
cv2.blur(InputArray src, OutputArray dst, Size ksize, Point anchor=Point(-1,-1), int borderType=BORDER_DEFAULT )
参数解释:
优点:使用简单,计算方便
特点:核中区域贡献率相同
高斯滤波是对整幅图像进行加权平均的过程,每一个像素点的值都由其本身和邻域内的其他像素值经过加权平均后得到。
函数:
cv2.GaussianBlur(InputArray src, OutputArray dst, Size ksize, double sigmaX, double sigmaY=0, int borderType=BORDER_DEFAULT )
参数解释:
优点:对于服从正太分布的噪声非常有效
特点:核中区域贡献率与距离中心成正比,权重与高斯分布相关
用像素点邻域灰度值的中值来代替该像素点的灰度值,让周围的像素值接近真实的值从而消除孤立的噪声点。该方法在取出脉冲噪声、椒盐噪声的同时能保留图像的边缘细节。
函数:
cv2.medianBlur(InputArray src, OutputArray dst, int ksize)
参数解释:
优点:对于椒盐噪声有效
特点:中心点的像素值被核中的中位数的像素代替
结合图像的空间邻近度和像素值相似度的一种折衷处理,同时考虑空间与信息和灰度相似性,达到保边去噪的目的,具有简单、非迭代、局部处理的特点。
函数:
cv2.bilateralFilter(InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace, int borderType=BORDER_DEFAULT)
参数解释:
作用:可以很好的保存图像边缘细节而滤除掉低频分量的噪音
特点:双边滤波器的效率不是太高,花费的时间相较于其他滤波器而言也比较长
# -*- coding:utf-8 -*-
#本程序用于实现各种滤波算法
import cv2 #导入opencv模块
import numpy as np
print("Hellow word!") #打印“Hello word!”,验证模块导入成功
img = cv2.imread("imag2.jpg") #导入图片,图片放在程序所在目录
cv2.namedWindow("imagshow", 2) #创建一个窗口
cv2.imshow('imagshow', img) #显示原始图片
# 均值滤波
img_mean = cv2.blur(img, (3,3)) #参数1输入图像,参数2核大小
cv2.namedWindow("mean", 2) #创建一个窗口
cv2.imshow('mean', img_mean) #显示原始图片
# 高斯滤波
img_Guassian = cv2.GaussianBlur(img,(3,3),0)
cv2.namedWindow("Guassian", 2) #创建一个窗口
cv2.imshow('Guassian', img_Guassian) #显示原始图片
# 中值滤波
img_median = cv2.medianBlur(img, 5)
cv2.namedWindow("median", 2) #创建一个窗口
cv2.imshow('median', img_median) #显示原始图片
# 双边滤波
img_bilater = cv2.bilateralFilter(img,9,75,75)
cv2.namedWindow("bilater", 2) #创建一个窗口
cv2.imshow('bilater', img_bilater) #显示原始图片
cv2.waitKey()
效果图:
下载完整代码请到: opencv常见滤波算法python 语言实现
从左到右分别为:原图、中值滤波、双边滤波、均值滤波、高斯滤波。
图象的边缘是指图象局部区域亮度变化显著的部分,该区域的灰度剖面一般可以看作是一个阶跃,既从一个灰度值在很小的缓冲区域内急剧变化到另一个灰度相差较大的灰度值。图象的边缘部分集中了图象的大部分信息,图象边缘的确定与提取对于整个图象场景的识别与理解是非常重要的,同时也是图象分割所依赖的重要特征,边缘检测主要是图象的灰度变化的度量、检测和定位。
边缘检测的基本原理: 边缘检测的本质是微分,如上图所示,当相邻两个像素点的灰度值差异越大时,也就是其斜率越陡,也就是微分值越大,进而通过这个来判断边缘,实际中常用差分,x方向和y方向。
原理:算子使用两个3X3的矩阵(图1)算子使用两个3X3的矩阵(图1)去和原始图片作卷积,分别得到横向G(x)和纵向G(y)的梯度值,如果梯度值大于某一个阈值,则认为该点为边缘点。
原理:首先对图像做高斯滤波,然后再求其拉普拉斯(Laplacian)二阶导数。即图像与 Laplacian of the Gaussian function 进行滤波运算。最后,通过检测滤波结果的零交叉(Zero crossings)可以获得图像或物体的边缘。因而,也被业界简称为Laplacian-of-Gaussian (LoG)算子。
算法步骤:
Canny算法通常处理的图像为灰度图,因此如果摄像机获取的是彩色图像,那首先就得进行灰度化。对一幅彩色图进行灰度化,就是根据图像各个通道的采样值进行加权平均。图像高斯滤波的实现可以用两个一维高斯核分别两次加权实现,也可以通过一个二维高斯核一次卷积实现。
关于图像灰度值得梯度可使用一阶有限差分来进行近似,这样就可以得图像在x和y方向上偏导数的两个矩阵。
图像梯度幅值矩阵中的元素值越大,说明图像中该点的梯度值越大,但这不不能说明该点就是边缘(这仅仅是属于图像增强的过程)。
Canny算法中减少假边缘数量的方法是采用双阈值法。选择两个阈值(关于阈值的选取方法在扩展中进行讨论),根据高阈值得到一个边缘图像,这样一个图像含有很少的假边缘,但是由于阈值较高,产生的图像边缘可能不闭合,为解决这样一个问题采用了另外一个低阈值。在高阈值图像中把边缘链接成轮廓,当到达轮廓的端点时,该算法会在断点的8邻域点中寻找满足低阈值的点,再根据此点收集新的边缘,直到整个图像边缘闭合。
三种边缘检测的程序实现:
# -*- coding:utf-8 -*-
#本程序用于边缘检测
import cv2 #导入opencv模块
import numpy as np
print("Hellow word!") #打印“Hello word!”,验证模块导入成功
img = cv2.imread("lena.jpg") #导入图片,图片放在程序所在目录
cv2.namedWindow("imagshow", 2) #创建一个窗口
cv2.imshow('imagshow', img) #显示原始图片
#高斯模糊
blurred = cv2.GaussianBlur(img, (3, 3), 0)
#转换为灰度图
out_img_GRAY=cv2.cvtColor(blurred,cv2.COLOR_BGR2GRAY)#将图片转换为灰度图
cv2.namedWindow("img_GRAY", 2) #创建一个窗口
cv2.imshow('img_GRAY', out_img_GRAY) #显示原始图片
#使用Canny算子进行边缘检测
edge_output = cv2.Canny(out_img_GRAY, 10, 300)
cv2.namedWindow("Canny", 2) #创建一个窗口
cv2.imshow('Canny', edge_output) #显示原始图片
#使用sobel算子进行边缘检测
sobel = cv2.Sobel(out_img_GRAY,-1,1,0,ksize=3)
cv2.namedWindow("sobel", 2) #创建一个窗口
cv2.imshow('sobel', sobel) #显示原始图片
#使用laplacian算子进行边缘检测
laplacian = cv2.Laplacian(out_img_GRAY,-1)
cv2.namedWindow("laplacian", 2) #创建一个窗口
cv2.imshow('laplacian', laplacian) #显示原始图片
cv2.waitKey()
统计各个灰度级别在图像中的出现次数或概率,并用直方图显示出来,一般直方图显示图像数据时会以左暗又亮的分布曲线形式呈现出来。
且具有图像平移、旋转、缩放不变性等众多优点,直方图在进行图像计算处理时代价较小,所以经常用于图像处理。
Lena图像的灰度直方图和RGB直方图显示:
python程序实现,使用matplotlib模块绘制:
# -*- coding:utf-8 -*-
#本程序用于显示图片的直方图
import cv2 #导入opencv模块
import numpy as np
import matplotlib.pyplot as plt
print("Hellow word!") #打印“Hello word!”,验证模块导入成功
img = cv2.imread("lena.jpg") #导入图片,图片放在程序所在目录
cv2.namedWindow("imagshow", 2) #创建一个窗口
cv2.imshow('imagshow', img) #显示原始图片
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #转换为灰度图
plt.hist(gray.ravel(), 256, [0, 256]) #计算灰度直方图
plt.show()
# 蓝 绿 红
color = ('b', 'g', 'r')#颜色分量
for i, col in enumerate(color):
histr = cv2.calcHist([img], [i], None, [256], [0, 256]) #计算颜色分量直方图
plt.plot(histr, color=col) #绘制直方图
plt.xlim([0, 256])
plt.show() #显示直方图
cv2.waitKey()
遍历灰度取值,确定最佳阈值,使背景和目标之间的类间方差最大 (因为二者差异最大);
python算法实现及效果:
# -*- coding:utf-8 -*-
#本程序用于大津算法的实现
import cv2 #导入opencv模块
import numpy as np
print("Hellow word!") #打印“Hello word!”,验证模块导入成功
img = cv2.imread("test.jpg") #导入图片,图片放在程序所在目录
cv2.namedWindow("imagshow", 2) #创建一个窗口
cv2.imshow('imagshow', img) #显示原始图片
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #转换为灰度图
retval,dst = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU) #使用大津算法进行图像二值化
cv2.namedWindow("dst", 2) #创建一个窗口
cv2.imshow("dst", dst)
cv2.waitKey()
二值化效果图及图像直方图:
Harris算子是Harris和Stephens在1998年提出的一种基于信号的点特征提取算子。其前身是Moravec算子。
其基本思想是:在图像中设计一个局部检测窗口,当该窗口沿各个方向做微小移动时,考察窗口的平均能量变化,当该能量变化超过设定的阈值时,就将窗口的中心像素点提取为角点。
在角点处,任意方向移动,窗口灰度值均剧烈变化
对于图像I(x,y)I(x,y),当在点(x,y)(x,y)处平移(Δx,Δy)(Δx,Δy)后的自相似性,可以通过自相关函数给出:
c(x,y;Δx,Δy)=∑(u,v)∈W(x,y)w(u,v)(I(u,v)–I(u+Δx,v+Δy))2
根据泰勒展开,对图像I(x,y)I(x,y)在平移(Δx,Δy)(Δx,Δy)后进行一阶近似:
I(u+Δx,v+Δy)=I(u,v)+Ix(u,v)Δx+Iy(u,v)Δy+O(Δx2,Δy2)≈I(u,v)+Ix(u,v)Δx+Iy(u,v)Δy
其中,Ix,IyIx,Iy是图像I(x,y)I(x,y)的偏导数,这样的话,自相关函数则可以简化为:
c(x,y;Δx,Δy)≈∑w(Ix(u,v)Δx+Iy(u,v)Δy)2=[Δx,Δy]M(x,y)[ΔxΔy]
也就是说图像I(x,y)I(x,y)在点(x,y)(x,y)处平移(Δx,Δy)(Δx,Δy)后的自相关函数可以近似为二项函数:
c(x,y;Δx,Δy)≈AΔx2+2CΔxΔy+BΔy2
其中
A=∑wI2x,B=∑wI2y,C=∑wIxIy
二次项函数本质上就是一个椭圆函数。椭圆的扁率和尺寸是由M(x,y)M(x,y)的特征值λ1、λ2λ1、λ2决定的,椭贺的方向是由M(x,y)M(x,y)的特征矢量决定的,如下图所示,椭圆方程为:
[Δx,Δy]M(x,y)[ΔxΔy]=1
椭圆函数特征值与图像中的角点、直线(边缘)和平面之间的关系如下图所示。共可分为三种情况:
根据二次项函数特征值的计算公式,我们可以求M(x,y)M(x,y)矩阵的特征值。但是Harris给出的角点差别方法并不需要计算具体的特征值,而是计算一个角点响应值RR来判断角点。RR的计算公式为:
R=detM−α(traceM)2
R为正值是,检测到的是角点,R为负时检测到的是边,R很小时检测到的是平坦区域。
import cv2
import numpy as np
img = cv2.imread("left03.jpg")
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #图像灰度化
gray = np.float32(gray)
#图像转换为float32
dst = cv2.cornerHarris(gray,2,3,0.04)#角点检测
#result is dilated for marking the corners, not important
dst = cv2.dilate(dst,None)#图像膨胀提升后续图像角点标注的清晰准确度
# Threshold for an optimal value, it may vary depending on the image.
#print(dst)
#img[dst>0.00000001*dst.max()]=[0,0,255] #可以试试这个参数,角点被标记的多余了一些
img[dst>0.01*dst.max()]=[0,0,255]#角点位置用红色标记
#这里的打分值以大于0.01×dst中最大值为边界
cv2.namedWindow("Harris", 2) #创建一个窗口
cv2.imshow('Harris',img)
cv2.waitKey()
主要函数cv2.cornerHarris(img,blockSize,ksize,k) 可以用来进行角点检测。参数如下:
效果图:
Hough变换思想(参数空间变换): 在原始图像坐标系下的一个点对应了参数坐标系中的一条直线,同样参数坐标系的一条直线对应了原始坐标系下的一个点,然后,原始坐标系下呈现直线的所有点,它们的斜率和截距是相同的,所以它们在参数坐标系下对应于同一个点。这样在将原始坐标系下的各个点投影到参数坐标系下之后,看参数坐标系下有没有聚集点,这样的聚集点就对应了原始坐标系下的直线。
在实际应用中,y=kx+b形式的直线方程没有办法表示x=c形式的直线(这时候,直线的斜率为无穷大)。所以实际应用中,是采用参数方程p=xcos(theta)+y*sin(theta)。这样,图像平面上的一个点就对应到参数p---theta平面上的一条曲线上,其它的还是一样。
Hough变换思想(参数空间划分网格统计): 为了检测出直角坐标X-Y中由点所构成的直线,可以将极坐标a-p量化成许多小格。根据直角坐标中每个点的坐标(x,y),在a = 0-180°内以小格的步长计算各个p值,所得值落在某个小格内,便使该小格的累加记数器加1。当直角坐标中全部的点都变换后,对小格进行检验,计数值最大的小格,其(a,p)值对应于直角坐标中所求直线。
import cv2
import numpy as np
#hough变换的程序实现
img = cv2.imread("building.jpg")#读取图片
img2 = img.copy()
gray =cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#将图片转换为灰度图
edges = cv2.Canny(gray,50,150,apertureSize = 3)#canny算法提取轮廓
#基于概率的hough变换......................................................
lines_Probabilitys = cv2.HoughLinesP(edges,1,np.pi/180,30,minLineLength=100,maxLineGap=10)#概率hough变换
lines_Probability = lines_Probabilitys[:,0,:]#提取为二维
for x1,y1,x2,y2 in lines_Probability[:]:
cv2.line(img,(x1,y1),(x2,y2),(255,0,0),1)
cv2.namedWindow("HoughLines_Probabilitys", 2) #创建一个窗口
cv2.imshow('HoughLines_Probabilitys', img) #显示原始图片
#标准的hough变换......................................................
lines_standards = cv2.HoughLines(edges,1,np.pi/180,200) #标准hough变换查找直线
#绘制hough变换后找到的所有直线,返回数据是一个二位数组
for lines_standard in lines_standards:
for rho,theta in lines_standard:
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))
cv2.line(img2,(x1,y1),(x2,y2),(0,0,255),2)
print(lines_standards)#打印出找到的直线的极坐标系坐标、
cv2.namedWindow("HoughLines_standards", 2) #创建一个窗口
cv2.imshow('HoughLines_standards', img2) #显示原始图片
cv2.waitKey()
HoughLinesP(image, rho, theta, threshold, lines=None, minLineLength=None, maxLineGap=None)
cvHoughLines2( CvArr* image, void* line_storage, int method,double rho, double theta, int threshold,double param1=0, double param2=0 );
SIFT算法分为如下四步:
尺度空间极值检测:搜索所有尺度上的图像位置。通过高斯微分函数来识别潜在的对于尺度和旋转不变的兴趣点。
关键点定位:在每个候选的位置上,通过一个拟合精细的模型来确定位置和尺度。关键点的选择依据于它们的稳定程度。
方向确定:基于图像局部的梯度方向,分配给每个关键点位置一个或多个方向。所有后面的对图像数据的操作都相对于关键点的方向、尺度和位置进行变换,从而提供对于这些变换的不变性。
关键点描述:在每个关键点周围的邻域内,在选定的尺度上测量图像局部的梯度。这些梯度被变换成一种表示,这种表示允许比较大的局部形状的变形和光照变化。
尺度空间理论的基本思想是:在图像信息处理模型中引入一个被视为尺度的参数,通过连续变化尺度参数获得多尺度下的尺度空间表示序列,对这些序列进行尺度空间主轮廓的提取,并以该主轮廓作为一种特征向量,实现边缘、角点检测和不同分辨率上的特征提取等。
方向直方图原理:为了使描述符具有旋转不变性,需要利用图像的局部特征为给每一个关键点分配一个基准方向。使用图像梯度的方法求取局部结构的稳定方向。对于在DOG金字塔中检测出的关键点点,采集其所在高斯金字塔图像3σ邻域窗口内像素的梯度和方向分布特征。
ORB采用FAST(features from accelerated segment test)算法来检测特征点。FAST核心思想就是找出那些卓尔不群的点,即拿一个点跟它周围的点比较,如果它和其中大部分的点都不一样就可以认为它是一个特征点。
FAST具体计算过程:
从图片中选取一个像素点P,下面我们将判断它是否是一个特征点。我们首先把它的密度(即灰度值)设为Ip。
设定一个合适的阙值t :当2个点的灰度值之差的绝对值大于t时,我们认为这2个点不相同。
考虑该像素点周围的16个像素。(见上图)
现在如果这16个点中有连续的n个点都和点不同,那么它就是一个角点。 这里n设定为12。
我们现在提出一个高效的测试,来快速排除一大部分非特征点的点。该测试仅仅检查在位置1、9、5和13四个位置的像素(首先检查1和9,看它们是否和点相同。如果是,再检查5和13)。如果是一个角点,那么上述四个像素点中至少有3个应该和点相同。如果都不满足,那么不可能是一个角点。
BRIEF:
得到特征点后我们需要以某种方式F描述这些特征点的属性。这些属性的输出我们称之为该特征点的描述子(Feature DescritorS).ORB采用BRIEF算法来计算一个特征点的描述子。BRIEF算法的核心思想是在关键点P的周围以一定模式选取N个点对,把这N个点对的比较结果组合起来作为描述子。
具体来讲分为以下几步。
1.以关键点P为圆心,以d为半径做圆O。
2.在圆O内某一模式选取N个点对。这里为方便说明,N=4,实际应用中N可以取512.
假设当前选取的4个点对如上图所示分别标记为:
3.定义操作T
4.分别对已选取的点对进行T操作,将得到的结果进行组合。
假如:
则最终的描述子为:1011
import numpy as np
import cv2
#from matplotlib import pyplot as plt
#print cv2.__version__
img1 = cv2.imread('box.png',0) # queryImage
img2 = cv2.imread('box_in_scene.png',0) # trainImage
def drawMatches(img1, kp1, img2, kp2, matches):
# Create a new output image that concatenates the two images together
# (a.k.a) a montage
rows1 = img1.shape[0]
cols1 = img1.shape[1]
rows2 = img2.shape[0]
cols2 = img2.shape[1]
out = np.zeros((max([rows1,rows2]),cols1+cols2,3), dtype='uint8')
# Place the first image to the left
out[:rows1,:cols1] = np.dstack([img1, img1, img1])
# Place the next image to the right of it
out[:rows2,cols1:] = np.dstack([img2, img2, img2])
# For each pair of points we have between both images
# draw circles, then connect a line between them
for mat in matches:
# Get the matching keypoints for each of the images
img1_idx = mat.queryIdx
img2_idx = mat.trainIdx
# x - columns
# y - rows
(x1,y1) = kp1[img1_idx].pt
(x2,y2) = kp2[img2_idx].pt
# Draw a small circle at both co-ordinates
# radius 4
# colour blue
# thickness = 1
cv2.circle(out, (int(x1),int(y1)), 4, (255, 0, 0), 1)
cv2.circle(out, (int(x2)+cols1,int(y2)), 4, (255, 0, 0), 1)
# Draw a line in between the two points
# thickness = 1
# colour blue
cv2.line(out, (int(x1),int(y1)), (int(x2)+cols1,int(y2)), (255, 0, 0), 1)
# Show the image
cv2.imshow('Matched Features', out)
cv2.waitKey(0)
cv2.destroyWindow('Matched Features')
# Also return the image if you'd like a copy
return out
# Initiate SIFT detector
orb = cv2.ORB_create()
# find the keypoints and descriptors with SIFT
kp1, des1 = orb.detectAndCompute(img1,None)
kp2, des2 = orb.detectAndCompute(img2,None)
# create BFMatcher object
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
# Match descriptors.
matches = bf.match(des1,des2)
# Sort them in the order of their distance.
matches = sorted(matches, key = lambda x:x.distance)
# Draw first 10 matches.
img3 = drawMatches(img1,kp1,img2,kp2,matches[:10])
cv2.imshow('dst',img3)
if cv2.waitKey(0) & 0xff == 27:
cv2.destroyAllWindows()
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。