96SEO 2026-02-20 07:32 13
}
上周在生产环境遇到了这个问题,排查了2天才定位到原因。
今天分享一下完整的解决方案,希望帮大家避坑。
id="content_views">
系列内容:OpenCV概述与环境配置,OpenCV基础知识和绘制图形,图像的算数与位运算,图像视频的加载和显示,图像基本变换,滤波器,形态学,图像轮廓,图像直方图,车辆统计项目,特征检测和匹配,图像查找和拼接,虚拟计算器项目,信用卡识别项目,图像的分割与修复,人脸检测与车牌识别,目标追踪,答题卡识别判卷与文档ocr扫描识别,光流估计
图像卷积就是卷积核在图像上按行滑动遍历像素时不断相乘求和的过程.
如图6.1所示:
src="https://i-blog.csdnimg.cn/direct/fd14a84197ef4e04b8f7e3224d084658.png">
步长就是卷积核在图像上移动的步幅,上面的例子中卷积核每次移动一个像素步长的结果,如果步长为2,结果如何?
如图6.2所示:
src="https://i-blog.csdnimg.cn/direct/d90393996c604545b899d11c4b424165.png">
上面的例子中我们发现,卷积之后图片的长宽会变小,如果要保持图片大小不变,我们需要在图片周围填充0,padding指的值就是填充的0的圈数.如图6.3所示:
src="https://i-blog.csdnimg.cn/direct/97f927d9947c45438253235f4898caeb.png">
我们可以通过公式计算出所需要填充0的圈数.
输入体积大小$H_{1}*W_{1}*D_{1}$
四个超参数:
输出体积大小为$H_{2}*W_{2}*D_{2}$
alt="H_{2}=\dfrac{(H_{1}-F+2P)}{S}+1"
src="https://latex.csdn.net/eq?H_%7B2%7D%3D%5Cdfrac%7B%28H_%7B1%7D-F+2P%29%7D%7BS%7D+1">
alt="W_{2}=\dfrac{(W_{1}-F+2P)}{S}+1"
src="https://latex.csdn.net/eq?W_%7B2%7D%3D%5Cdfrac%7B%28W_%7B1%7D-F+2P%29%7D%7BS%7D+1">
src="https://latex.csdn.net/eq?D_%7B2%7D%3Dk">
如果要保持卷积之后图片大小不变,可以得出等式$(N+2P-F+1)=N$,从而可以推导出$P=\frac{F-1}{2}$
图片卷积中,卷积核一般为奇数,比如$3*3,5*5,7*7$,原因:
filter2D(src,ddepth,kernel[,dst[,anchor[,delta[,borderType]]]])
其中:
(1)正常操作(奇数卷积核)
class="language-python">#OpenCV图像卷积操作
import
kernel=np.ones((5,5),np.float32)/25
dst=cv2.filter2D(img,-1,kernel)
cv2.imshow('img',np.hstack((img,dst)))
cv2.waitKey(0)
cv2.destroyAllWindows()
正常结果如图6.4所示:
src="https://i-blog.csdnimg.cn/direct/9bc4551cb97849659a0af4cbd49aa2bb.png">
(2)尝试其他卷积核:
class="language-python">#OpenCV图像卷积操作
import
kernel=np.ones((5,5),np.float32)/25
#尝试其他卷积核
kernel=np.array([[-1,-1,-1],[-1,8,-1],[-1,-1,-1]])
#浮雕效果
kernel=np.array([[-2,1,0],[-1,1,1],[0,1,2]])
#锐化
kernel=np.array([[0,-1,0],[-1,5,-1],[0,-1,0]])
dst=cv2.filter2D(img,-1,kernel)
cv2.imshow('img',np.hstack((img,dst)))
cv2.waitKey(0)
cv2.destroyAllWindows()
src="https://i-blog.csdnimg.cn/direct/875051e803d94b16b4528f4ca3b1cc44.png">
src="https://i-blog.csdnimg.cn/direct/32885f98b3c24baf9f4fe3da2cc737c2.png">
src="https://i-blog.csdnimg.cn/direct/0b89ff34514943e6a9c97a2a6df2ac67.png">
boxFilter(src,ddepth,ksize[,dst[,anchor[,normalize[,borderType]]]])方盒滤波
一般情况我们取True,这时,方盒滤波等价于均值滤波
blur(src,ksize[,dst[,anchor[,borderType]]])均值滤波(模糊化)
卷积核表示:
src="https://latex.csdn.net/eq?K%20%3D%20a%5Cleft%5B%20%5Cbegin%7Barray%7D%20%7B%20c%20c%20c%20c%20c%20%7D%201%20%26%201%20%26%201%20%26%20%5Ccdots%20%26%201%20%5C%5C%201%20%26%201%20%26%201%20%26%20%5Ccdots%20%26%201%20%5C%5C%20%5Ccdots%20%5Ccdots%20%5Ccdots%20%5Ccdots%20%5Ccdots%20%5Ccdots%20%5Ccdots%20%5Ccdots%20%5C%5C%201%20%26%201%20%26%201%20%26%20%5Ccdots%20%26%201%20%5Cend%7Barray%7D%20%5Cright%5D">
方盒滤波等价于均值滤波。
dst=cv2.boxFilter(img,-1,(5,5),normalize=True)
cv2.imshow('img',np.hstack((img,dst)))
cv2.waitKey(0)
cv2.destroyAllWindows()
方盒滤波如图6.8所示:
src="https://i-blog.csdnimg.cn/direct/d077cf750ccb49438ded6bfcf4d0f3e7.png">
cv2.imshow('img',np.hstack((img,dst)))
cv2.waitKey(0)
cv2.destroyAllWindows()
均值滤波,如图6.9所示:
src="https://i-blog.csdnimg.cn/direct/4acba168c3c147b2b5a148ca6b903611.png">
要理解高斯滤波,前置知识是高斯函数,高斯函数是符合高斯分布(正态分布)的概率密度函数,其图像如如图6.10所示:
src="https://i-blog.csdnimg.cn/direct/f0a4c948d4f64df7880b53ecc69433e0.png">
若连续型随机变量X的概率密度为
alt="f(x)=\frac{1}{\sqrt{2\pi\sigma^{2}}}e^{-\frac{(x
src="https://latex.csdn.net/eq?f%28x%29%3D%5Cfrac%7B1%7D%7B%5Csqrt%7B2%5Cpi%5Csigma%5E%7B2%7D%7D%7De%5E%7B-%5Cfrac%7B%28x%20-%20%5Cmu%29%5E%7B2%7D%7D%7B2%5Csigma%5E%7B2%7D%7D%7D">
其中$\mu$,$\sigma$($\sigma>0$)为常数,则称X服从参数为$\mu$,$\sigma$的正太分布或高斯分布(Gauss),记为
$X
src="https://i-blog.csdnimg.cn/direct/fa82512c02ba4ae0a664ff4d05ed6793.png">
二维随机变量(X,Y)的概率密度为:
\frac{2\rho(x-\mu_X)(y-\mu_Y)}{\sigma_X
src="https://latex.csdn.net/eq?f%28x%2Cy%29%20%3D%20%5Cfrac%7B1%7D%7B2%5Cpi%20%5Csigma_X%20%5Csigma_Y%20%5Csqrt%7B1-%5Crho%5E2%7D%7D%20%5Cexp%5Cleft%28%20-%5Cfrac%7B1%7D%7B2%281-%5Crho%5E2%29%7D%20%5Cleft%5B%20%5Cfrac%7B%28x-%5Cmu_X%29%5E2%7D%7B%5Csigma_X%5E2%7D%20+%20%5Cfrac%7B%28y-%5Cmu_Y%29%5E2%7D%7B%5Csigma_Y%5E2%7D%20-%20%5Cfrac%7B2%5Crho%28x-%5Cmu_X%29%28y-%5Cmu_Y%29%7D%7B%5Csigma_X%20%5Csigma_Y%7D%20%5Cright%5D%20%5Cright%29">
其中$\mu_x,\mu_y,\sigma_x,\sigma_y,\rho$都是常数,且$\sigma_x
>0,\sigma_y>0,-1<\rho<1$,我们称(X,Y)为服从参数为$\mu_x,\mu_y,\sigma_x,\sigma_y,\rho$的二维正态分布,如图6.11(2)所示
src="https://i-blog.csdnimg.cn/direct/991ceff3b299445c937f2a32540419f7.png">
高斯滤波就是使用符合高斯分布的卷积核对图片进行1卷积操作,所以高斯滤波的重点就是如何计算符合高斯分布的卷积核,即高斯模板.
假定中心点的坐标为(0,0),那么取距离它最近的8个点坐标,为了计算,假定$\sigma=1.5$,则模糊半径为1的高斯模板计算如图6.12所示
src="https://i-blog.csdnimg.cn/direct/9c4b4132b14542db8cc5e69b706b7bb9.png">
我们可以观察到越靠近中心,数值越大,越边缘的数值越小,符合高斯分布.
通过高斯分布计算出来的是概论密度函数,所以我们还要确保这几个点加起来的和为1,这九个点的权重总和等于0.4787147,因此上面九个值还要分别除以0.4787147,得到最终的高斯模板
注意,有些整数高斯模板是在归一化后的高斯模板的基础上每个数除以左上角的值,然后取整.如图6.13所示
src="https://i-blog.csdnimg.cn/direct/caf694b4c7fc46b096b5d58c4b3612ec.png">
有了卷积核,计算高斯滤波就简单了,假设有9个像素点,灰度值(0-255)的高斯滤波计算如如图6.14所示
src="https://i-blog.csdnimg.cn/direct/27617461761e414799aff9f28fc6c9cf.png">
将这九个值加起来,就是中心点的高斯滤波的值,对于所有点重复这个过程,就得到了高斯模糊后的图像.
GaussianBlur(src,ksize,sigmaX[,dst[,sigmaY[,borderType]]])
如果没有指定的sigma的值,会分别从ksize的宽度和高度中计算sigma
选择不同的sigma值会对应不同的平滑效果,sigma越大,平滑效果越强,如图6.15所示
src="https://i-blog.csdnimg.cn/direct/e624100d96c8419591abcd89c153de11.png">
没有指定sigma时,ksize越大,平滑效果越明显,如图6.16所示
src="https://i-blog.csdnimg.cn/direct/acadb8cac04b42618958853b6686cd7a.png">
dst=cv2.GaussianBlur(img,(5,5),sigmaX=1)
cv2.imshow('img',np.hstack((img,dst)))
cv2.waitKey(0)
cv2.destroyAllWindows()
处理结果对比图,lena处理结果对比图(指定sigmaX)如图6.17所示
src="https://i-blog.csdnimg.cn/direct/06c434bde4e04280bf112bf1f88876e4.png">
不指定sigmaX时,
dst=cv2.GaussianBlur(img,(5,5),sigmaX=1)
dst=cv2.GaussianBlur(img,(5,5),sigmaX=0)
cv2.imshow('img',np.hstack((img,dst)))
cv2.waitKey(0)
cv2.destroyAllWindows()
lena处理结果对比图(不指定sigmaX),如图6.18所示
src="https://i-blog.csdnimg.cn/direct/84f3fe52db2446258838237a6a63b329.png">
中值滤波原理非常简单,假设有一个数组(1556789),取其中间值(即中位数)作为卷积后的结果值即可,中值滤波对胡椒噪音(椒盐噪音)效果明显。
cv2.imshow('img',np.hstack((img,dst)))
cv2.waitKey(0)
cv2.destroyAllWindows()
src="https://i-blog.csdnimg.cn/direct/3404e22539e947c2b7242730a4642299.png">
高斯滤波处理ikun,效果不好,如图6.20所示:
dst=cv2.GaussianBlur(img,(5,5),sigmaX=1)
cv2.imshow('img',np.hstack((img,dst)))
cv2.waitKey(0)
cv2.destroyAllWindows()
src="https://i-blog.csdnimg.cn/direct/3d5d7121316b4b87a6855c36d5db9d7e.png">
双边滤波对于图像的边缘信息能够更好地保存,其原理为一个与空间距离相关的高斯函数与一个与灰度相关的高斯函数相乘.
alt="d=exp^{-\dfrac{(x_{i}-x_{c})^{2}+(y_{i}-y_{c})^{2}}{2
src="https://latex.csdn.net/eq?d%3Dexp%5E%7B-%5Cdfrac%7B%28x_%7Bi%7D-x_%7Bc%7D%29%5E%7B2%7D+%28y_%7Bi%7D-y_%7Bc%7D%29%5E%7B2%7D%7D%7B2%20%5Csigma%5E%7B2%29%7D%7D%7D">
其中,$(x_{i},y_{i})$为当前点位置,$(x_{c},y_{c})$为中心点的位置,$\sigma$为空间域标准差.
最佳实践:
经过多个项目的验证,我总结了几个关键点:1)
这些看似简单,但能避免很多生产环境问题。
alt="d=exp^{-\dfrac{(gray(x_{i},y_{i})-gray(x_{c},y_{c}))^{2}}{2
src="https://latex.csdn.net/eq?d%3Dexp%5E%7B-%5Cdfrac%7B%28gray%28x_%7Bi%7D%2Cy_%7Bi%7D%29-gray%28x_%7Bc%7D%2Cy_%7Bc%7D%29%29%5E%7B2%7D%7D%7B2%20%5Csigma%5E%7B2%7D%7D%7D">
其中$gray(x_{i},y_{i})$为当前点灰度值,$gray(x_{c},y_{c})$为中心点灰度值,$\sigma$为值域标准差
双边滤波本质上是高斯滤波,双边滤波和高斯滤波不同的就是:双边滤波既利用了位置信息又利用了像素信息来定义滤波窗口的权重。
而高斯滤波只用了位置信息。
对于高斯滤波,仅用空间距离的权值系数核与图像卷积后,确定中心点的灰度值。
即认为离中心点越近的点,其权重系数越大。
双边滤波中加入了对灰度信息的权重,即在邻域内,灰度值越接近中心点灰度值的点的权重更大,灰度值相差大的点权重越小。
此权重大小,则由值域高斯函数确定。
两者权重系数相乘,得到最终的卷积模板。
由于双边滤波需要每个中心点邻域的灰度信息来确定其系数,所以其速度与一般的滤波慢很多,而且计算量增长速度为核大小的平方。
src="https://i-blog.csdnimg.cn/direct/4c8614d7537c436bab619b5aee9b4aca.png">
双边滤波可以保留边缘,同时可以对边缘内的区域进行平滑处理
双边滤波的作用就相当于做了美颜.
bilateralFilter(src,d,sigmaColor,sigmaSpace[,dst[,borderType]])
双边滤波对椒盐噪声处理
dst=cv2.bilateralFilter(img,7,50,50)
cv2.imshow('img',np.hstack((img,dst)))
cv2.waitKey(0)
cv2.destroyAllWindows()
src="https://i-blog.csdnimg.cn/direct/70fb88da32fb4d1c9ab7190bbc142056.png">
美颜效果
dst=cv2.bilateralFilter(img,7,50,50)
cv2.imshow('img',np.hstack((img,dst)))
cv2.waitKey(0)
cv2.destroyAllWindows()
美颜效果,如图6.23所示:
src="https://i-blog.csdnimg.cn/direct/46b78cd0f02b4e1688d3e313753c4365.png">
0)">(六)sobel算子
边缘是像素值发生跃迁的位置,是图像的显著特征之一,在图像特征提取,对象检测,模式识别等方面都有重要的作用。
人眼如何识别图像边缘?
比如有一幅图,图里面有一条线,左边很亮,右边很暗,那人眼就很容易识别这条线作为边缘.也就是像素的灰度值快速变化的地方.
sobel算子对图像求一阶导数。
一阶导数越大,说明像素在该方向的变化越大,边缘信号越强。
sobel算子采用离散差分算子计算图像像素点亮度值的近似梯度.
src="https://latex.csdn.net/eq?G_x%20%3D%20%5Cbegin%7Bbmatrix%7D%20-1%20%26%200%20%26%20+1%20%5C%5C%20-2%20%26%200%20%26%20+2%20%5C%5C%20-1%20%26%200%20%26%20+1%20%5Cend%7Bbmatrix%7D%20*%20I">
垂直方向
src="https://latex.csdn.net/eq?G_y%20%3D%20%5Cbegin%7Bbmatrix%7D%20-1%20%26%20-2%20%26%20-1%20%5C%5C%200%20%26%200%20%26%200%20%5C%5C%20+1%20%26%20+2%20%26%20+1%20%5Cend%7Bbmatrix%7D%20*%20I">
这样的话,我们就得到了两个新的矩阵,分别反映了每一点像素在水平方向上的亮度变化情况和在垂直方向上的亮度变化情况.
综合考虑这两个方向的变化,我们使用以下公式反映某个像素的梯度变化情况:
alt="G=\sqrt{G^{2}_{x}+G^{2}_{y}}"
src="https://latex.csdn.net/eq?G%3D%5Csqrt%7BG%5E%7B2%7D_%7Bx%7D+G%5E%7B2%7D_%7By%7D%7D">
有时为了简单起见,也直接使用绝对值相加来代替$G=|G_{x}|+|G_{y}|$
用方格为例,如图6.24所示:
src="https://i-blog.csdnimg.cn/direct/3699c881c776412c8defb96f34cb19f4.png">
class="language-python">#sobel算子
import
dx=cv2.Sobel(img,cv2.CV_64F,1,0,ksize=1)
#y轴方向获取水平边缘
dy=cv2.Sobel(img,cv2.CV_64F,0,1,ksize=1)
#dst=dx+dy
cv2.imshow('dx',np.hstack((dx,dy,dst)))
cv2.waitKey(0)
cv2.destroyAllWindows()
src="https://i-blog.csdnimg.cn/direct/395ba28ab0614476a1e0be2f454165b8.png">
Scharr(src,
borderType]]]])
当内核大小为
时,以上Sobel内核可能产生比较明显的误差(毕竟,Sobel算子只是求了导数的近似值)。
函数,但该函数仅作用于大小为3的内核。
该函数的运算与Sobel函数一样快,但结果却更加精确。
Scharr算子和Sobel很类似,只不过使用不同的kernel值,放大了像素变换的情况:
src="https://latex.csdn.net/eq?G_x%20%3D%20%5Cbegin%7Bbmatrix%7D%20-3%20%26%200%20%26%20+3%20%5C%5C%20-10%20%26%200%20%26%20+10%20%5C%5C%20-3%20%26%200%20%26%20+3%20%5Cend%7Bbmatrix%7D">
src="https://latex.csdn.net/eq?G_y%20%3D%20%5Cbegin%7Bbmatrix%7D%20-3%20%26%20-10%20%26%20-3%20%5C%5C%200%20%26%200%20%26%200%20%5C%5C%20+3%20%26%20+10%20%26%20+3%20%5Cend%7Bbmatrix%7D">
说明:
3的kernel所以没有kernel参数了.
以lena为例,对lena进行scharr算子计算
class="language-python">#scharr算子
import
dx=cv2.Scharr(img,cv2.CV_64F,dx=1,dy=0)
#y轴方向获取水平边缘
dy=cv2.Scharr(img,cv2.CV_64F,dx=0,dy=1)
dst=cv2.addWeighted(dx,0.5,dy,0.5,gamma=0)
cv2.imshow('img',np.hstack((dx,dy,dst)))
cv2.waitKey(0)
cv2.destroyAllWindows()
src="https://i-blog.csdnimg.cn/direct/4efb74cb453d4b7fb377ea2d66b7f3f2.png">
sobel算子是模拟一阶求导,导数越大的地方说明变换越剧烈,越有可能是边缘.
如图6.27所示:
src="https://i-blog.csdnimg.cn/direct/e87a5f11e5c44ceeabbd768a13b8d59c.png">
那如果继续对$f^{'}(t)$求导呢,如图6.28所示:
src="https://i-blog.csdnimg.cn/direct/6a6f949bfe3c4c4595dfc175ecb7008c.png">
可以发现"边缘处"的二阶导数等于0,我们可以利用这一特性去寻找图像的边缘。
注意有一个问题,二阶导求导为0的位置也可能是无意义的位置.
f''(x,y)=f_{x}'(x,y)+f_{y}'(x,y)
\(
src="https://latex.csdn.net/eq?f%27%27%28x%2Cy%29%3D%5Cbegin%7Bbmatrix%7D%200%20%26%201%20%26%200%20%5C%5C%201%20%26%20-4%20%26%201%20%5C%5C%200%20%26%201%20%26%200%20%5Cend%7Bbmatrix%7D%20%5Codot%20%5Cbegin%7Bbmatrix%7D%20f%28x%20-%201%2Cy%20-%201%29%20%26%20f%28x%2Cy%20-%201%29%20%26%20f%28x%20+%201%2Cy%20-%201%29%20%5C%5C%20f%28x%20-%201%2Cy%29%20%26%20f%28x%2Cy%29%20%26%20f%28x%20+%201%2Cy%29%20%5C%5C%20f%28x%20-%201%2Cy%20+%201%29%20%26%20f%28x%2Cy%20+%201%29%20%26%20f%28x%20+%201%2Cy%20+%201%29%20%5Cend%7Bbmatrix%7D">
这样就得到了拉普拉斯算子的卷积核即卷积模板
Laplacian(src,
borderType]]]]])
可以同时求两个方向的边缘
dst=cv2.Laplacian(img,-1,ksize=3)
cv2.imshow('img',np.hstack((img,dst)))
cv2.destroyAllWindows()
src="https://i-blog.csdnimg.cn/direct/7c170cd57fa543eea49b23850708d430.png">
Canny边缘检测算法是
年开发出来的一个多级边缘检测算法,也被很多人认为是边缘检测的最优算法,最优边缘检测的三个主要评价标准是:
(1).去噪:边缘检测算法容易受到噪声影响,在进行边缘检测前通常需要先进行去噪,一般用高斯滤波去除噪声。
(2).计算梯度:对平滑后的图像采用sobel算子计算梯度和方向。
\arctan\left(\frac{G_{y}}{G_{x}}\right)$
src="https://i-blog.csdnimg.cn/direct/8556ebccdc6f40c0925ff3478ca31b26.png">
(3).非极大值抑制
判断当前像素点是否是周围像素点中具有相同方向梯度的最大值.
梯度方向垂直于边缘如下图6.31所示.
保留该点;否则,它被抑制(归零)
src="https://i-blog.csdnimg.cn/direct/f46946a137bb4f78a17ac4689a0b056a.png">
src="https://i-blog.csdnimg.cn/direct/72f9a4bdc35549f9927243ada7fb66aa.png">
src="https://i-blog.csdnimg.cn/direct/470476b84b924cfa95f4886d163f35dd.png">
(4).Canny(img,minVal,maxVal,$\dots$)
cv2.imshow('lena',np.hstack((lena1,lena2)))
cv2.destroyAllWindows()
码运行结果如下图6.34所示:
src="https://i-blog.csdnimg.cn/direct/60e57322dcfe4f118238bad9f0d5d0d9.png">
class="post-meta-container">
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback