OpenCV的滤波与卷积

目录

预备知识

滤波、核和卷积

边界外推和边界处理

阈值化操作

Otsu算法

自适应阈值

平滑

简单模糊和方框型滤波器

中值滤波器

高斯滤波器

双边滤波器

导数和梯度

索贝尔导数

Scharr滤波器

拉普拉斯变换

图像形态学

膨胀和腐蚀

通用形态学函数

开操作和闭操作

形态学梯度

顶帽和黑帽

自定义核

用任意线性滤波器做卷积

用cv::filter2D()进行卷积

通过cv::sepFilter2D使用可分核

生成卷积核


预备知识

滤波、核和卷积

滤波器指的是一种由一幅图像 I(x,y)根据像素点x,y附近的区域计算得到一幅新图像 I'(x,y)的算法。其中,模板规定了滤波器的形状以及这个区域内像素的值的组成规律,也称“滤波器”或“核”。在下面的介绍中多采用的是线性核,即 I'(x,y)的像素的值由 I(x,y)及其周围的像素的值的加权相加得来的。可由以下方程表示:

I'(x, y)=\sum _{i, \: j\in kernal}k_{i,\: j}\cdot I(x+i,\: y+j)

\begin{bmatrix} 1 & 1 & 1& 1 & 1\\ 1 & 1& 1& 1 & 1\\ 1& 1 & \mathbf{1} & 1& 1\\ 1 & 1& 1 & 1 & 1\\ 1 & 1 & 1 & 1& 1 \end{bmatrix}\frac{1}{25}\begin{bmatrix} 1 & 1 & 1& 1 & 1\\ 1 & 1& 1& 1 & 1\\ 1& 1 & \mathbf{1} & 1& 1\\ 1 & 1& 1 & 1 & 1\\ 1 & 1 & 1 & 1& 1 \end{bmatrix}\begin{bmatrix} -1 & 0 &1 \\ -2 &\mathbf{0} & 2\\ -1& 0& 1 \end{bmatrix}\frac{1}{273}\begin{bmatrix} 1 & 4 & 7& 4 & 1\\ 4 & 16& 26& 16 & 4\\ 7& 26 & \mathbf{41} & 26& 7\\ 4 & 16& 26 & 16 & 4\\ 1 & 4 & 7 & 4& 1 \end{bmatrix}
(A)5×5盒状核(B)规范化的5×5盒状核(C)3×3的Sobel核(D)5×5规范化高斯核

注:“锚点”均用粗体表示

边界外推和边界处理

自定义边框

在处理图像时,只要告诉调用的函数添加虚拟像素的规则,库函数就会自动创建虚拟像素。cv::copyMakeBorder()就是一个为图像创建边框的函数。

cv::copyMakeBorder(InputArray src, InputArray dst, int top, int bottom, int left, int right, int borderType, const cv::Scalar& value=cv::Scalar())

作用:通过指定两幅图像,同时指明填充方法,该函数就会将第一幅图填补后的结果保存在第二幅图像中。其中,src是原图像,dst是填充后的图像,top、bottom、left、right分别是四个方向上的尺寸,borderType是像素填充的方式,value是常量填充时的值。

borderType的取值及效果
取值效果
cv::BORDER_CONSTANT为每个边框像素赋予一个相同的值。
cv::BORDER_WRAP类似于平铺扩充
cv::BORDER_REPLICATE复制边缘的像素扩充
cv::BORDER_REFLECT通过镜像复制扩充
cv::BORDER_REFLECT_101通过镜像复制扩充,边界像素除外
cv::BORDER_DEFAULTcv::BORDER_REFLECT_101

自定义外推

 int cv::borderInterpolate(int p, int len, int borderType)

作用:计算一个维度上的外推,p为原图上一个坐标,len是p指维度上的大小,borderType是边界类型。

例子:混合的边界条件下计算一个特定像素的值,在一维中使用BORDER_REFLECT_101,在二维中使用BORDER_WRAP:

float val = img.at<float>(cv::borderInterpolate(100, img.rows, cv::BORDER_REFLECT_101),cv::borderInterpolate(-5, img.cols, cv::BORDER_WRAP)
)

阈值化操作

阈值化操作的原理是对于数组中每个值,根据其高于或低于某个阈值做出相对应的处理,OpenCV中提供了实现这种功能的方法cv::threshold()。

double cv::threshold(InputArray src, cv::OutputArray dst, double thresh, double maxValue, int thresholdType)

thresholdType的可选项及其操作
阈值类型操作
cv::THRESH_BINARYDST_i=(SRC_i > thresh)\: ?\: MAXVALUE:0
cv::THRESH_BINARY_INVDST_i=(SRC_i > thresh)\: ?\: 0:MAXVALUE
cv::THRESH_TRUNCDST_i=(SRC_i > thresh)\: ?\: THRESH:SRC_i
cv::THRESH_TOZERODST_i=(SRC_i > thresh)\: ?\: SRC_i:0
cv::THRESH_TOZERO_INVDST_i=(SRC_i > thresh)\: ?\: 0:SRC_i
不同阈值类型对应的结果

 

例一:将一幅图像的三个通道相加并将像素值限制在100以内

#include "stdafx.h"
#include <opencv2/opencv.hpp>
#include <iostream>using namespace std;void sum_rgb(const cv::Mat& src, cv::Mat& dst) {// 分通道vector<cv::Mat> planes;cv::split(src, planes);cv::Mat b = planes[0];cv::Mat g = planes[1];cv::Mat r = planes[2];cv::Mat s;// 加权融合,防止越界cv::addWeighted(r, 1. / 3, g, 1. / 3, 0.0, s);cv::addWeighted(s, 1., r, 1. / 3, 0.0, s);// 阈值化操作cv::threshold(s, dst, 100, 100, cv::THRESH_TRUNC);
}void help() {cout << "Call: ./ch10_ex10_1 faceScene.jpg" << endl;cout << "Show use of alpha blending (addWeighted) and threshold" << endl;
}int main()
{help();cv::Mat src = cv::imread("D:\\personal-data\\wallpapers\\test.png");cv::Mat dst;if (src.empty()){cout << "can not load the image" << endl;return -1;}sum_rgb(src, dst);cv::imshow("img", dst);cv::waitKey(0);cv::destroyAllWindows();return 0;
}

运行结果: 

例二:对于浮点型图像进行三个通道相加并将像素值限制在100以内

#include "stdafx.h"
#include <opencv2/opencv.hpp>
#include <iostream>using namespace std;void sum_rgb(const cv::Mat& src, cv::Mat& dst) {// 分通道vector<cv::Mat> planes;cv::split(src, planes);cv::Mat b = planes[0];cv::Mat g = planes[1];cv::Mat r = planes[2];// 全0初始化s矩阵cv::Mat s = cv::Mat::zeros(b.size(), CV_32F);// accumulate可将8位整型的图像累加到一幅浮点型的图像中cv::accumulate(b, s);cv::accumulate(g, s);cv::accumulate(r, s);// 阈值化操作cv::threshold(s, dst, 100, 100, cv::THRESH_TRUNC);s.convertTo(dst, b.type());
}void help() {cout << "Call: ./ch10_ex10_1 faceScene.jpg" << endl;cout << "Show use of alpha blending (addWeighted) and threshold" << endl;
}int main()
{help();cv::Mat src = cv::imread("D:\\personal-data\\wallpapers\\test.png");cv::Mat dst;if (src.empty()){cout << "can not load the image" << endl;return -1;}sum_rgb(src, dst);cv::imshow("img", dst);cv::waitKey(0);cv::destroyAllWindows();return 0;
}

运行结果:

Otsu算法

函数cv::threshold()也可以自动决定最优的阈值,只需将参数thresh传递值cv::THRESH_OTSU即可。

简而言之,Otsu算法就是遍历所有可能的阈值,然后对每个阈值结果的两类像素(低于阈值和高于阈值两类像素)计算方差\sigma _i^2,然后计算\sigma _w^2的值,取其最小的阈值。

\sigma _w^2\equiv w_1(t)\cdot \sigma _1^2+w_2(t)\cdot \sigma _2^2

式中,w_1(t)w_2(t)是根据两类像素的数量计算而来的权重。由于要遍历所有可能的阈值,所以这并不是一个相对高效的过程。

自适应阈值

自适应阈值方法中阈值在整个过程中自动产生变化,这由OpenCV中的cv::adaptiveThreshold()实现。

void cv::adaptiveThreshold(InputArray src, OutputArray dst, double maxValue, int adaptiveMethod, int threshType, int blockSize, double C)

该方法是逐个像素地计算自适应阈值T(x, y),具体计算过程是:计算每个像素位置周围的blockSize×blockSize区域的加权平均值,然后减去常数C。求均值时所用权重和adaptiveMethod有关,若是cv::ADAPTIVE_THRESH_MEAN_C,则权重相等,若是cv::ADAPTIVE_THRESH_GAUSSIAN_C,则权重由高斯方差得到。

注:该方法只适应与单通道8位或浮点型图像

#include "stdafx.h"
#include <opencv2/opencv.hpp>
#include <iostream>using namespace std;int main()
{// 设置参数double fixed_threshold = 15;int threshold_type = 1 ? cv::THRESH_BINARY : cv::THRESH_BINARY_INV;int adaptive_method = 1 ? cv::ADAPTIVE_THRESH_MEAN_C : cv::ADAPTIVE_THRESH_GAUSSIAN_C;int block_size = 71;double offset = 15;// 以灰度图形式加载图片cv::Mat Igray = cv::imread("D:\\personal-data\\wallpapers\\test.png", cv::IMREAD_GRAYSCALE);// 判断图像是否加载成功if (Igray.empty()) { cout << "Can not load " << "D:\\personal-data\\wallpapers\\test.png" << endl; return -1; }// 声明输出矩阵cv::Mat It, Iat;// 阈值化操作cv::threshold(Igray,It,fixed_threshold,255,threshold_type);// 自适应阈值cv::adaptiveThreshold(Igray,Iat,255,adaptive_method,threshold_type,block_size,offset);// 展示结果图像cv::imshow("Raw", Igray);cv::imshow("Threshold", It);cv::imshow("Adaptive Threshold", Iat);cv::waitKey(0);cv::destroyAllWindows();return 0;
}

运行结果:

当threshold_type=1且adaptive_method=1

原图

阈值化操作

自适应阈值化

当threshold_type=0且adaptive_method=0

原图

阈值化操作

自适应阈值化

平滑

平滑也称“模糊”,是一种简单而又常用的图像处理操作。平滑图像的目的有很多,但通常都是为了减少噪声和伪影。在降低图像分辨率的时候,平滑也十分重要,可以防止图片出现锯齿状。

简单模糊和方框型滤波器

void cv::blur(InputArray src,OutputArray dst,Size ksize,Point anchor=Point(-1,-1),int borderType=BORDER_DEFAULT)

作用:实现简单的滤波,目标图像中的每个值都是原图像中相应位置一个窗口(核)中像素的平均值,窗口的尺寸由ksize声明;anchaor指定计算时核与源图像的对齐方式,默认情况下anchor为cv::Point(-1, -1),表示核相对于滤波器居中。

void cv::boxFilter(InputArray src, OutputArray dst, cv::Size ksize, cv::Point anchor=cv::Point(-1,-1), bool normalize=true;  int borderType=cv::BORDER_DEFAULT)

作用:方框滤波器是一种矩形的并且滤波器中所有值k_{i,\: j}全部相等的滤波器。通常,所有的k_{i,\: j}为1或者1/A,其中A是滤波器的面积。后一种滤波器称为“归一化方框型滤波器”,下面所示的是一个5×5的模糊滤波器,也称“归一化方框型滤波器”。

\frac{1}{25}\begin{bmatrix} 1 & 1 & 1& 1 & 1\\ 1 & 1& 1& 1 & 1\\ 1& 1 & \mathbf{1} & 1& 1\\ 1 & 1& 1 & 1 & 1\\ 1 & 1 & 1 & 1& 1 \end{bmatrix}

通过上述介绍,可以发现cv::boxFilter()是一种一般化的形式,而cv::blur()是一种特殊化的形式。但前者可以以非归一化形式调用,并且输出图像深度可以控制,但后者智能以归一化形式调用,且输出图像深度必须和原图像保持一致。

中值滤波器

中值滤波器(Median Filter)将每个像素替换为围绕这个像素的矩形领域内的中值或“中值”像素(相对于平均像素)。通过均值滤波器对噪声图像,尤其是有较大孤立的异常值非常敏感,少量具有较大偏差的点也会严重影响到均值滤波器。中值滤波器可以采用取其中间点的方式来消除异常值。

void cv::medianBlur(InputArray src, OutputArray dst, Size ksize)

高斯滤波器

关于高斯滤波器,在之前的文章中已做了详细介绍,可以参考OpenCV高斯滤波GaussianBlur

双边滤波器

双边滤波器是一种比较大的图像分析算子,也就是边缘保持平滑。高斯平滑的模糊过程是减缓像素在空间上的变化,因此与邻近的关系紧密,而随机噪声在像素间的变化幅度又会非常的大(即噪声不是空间相关的)。基于这种前提高斯平滑很好地减弱了噪声并且保留了小信号,但是却破坏了边缘信息,边缘也模糊了。

和高斯平滑类似,双边滤波对每个像素及其领域内的像素进行了加权平均。其权重由两部分组成,第一部分同高斯平滑,第二部分也是高斯权重,但是它不是基于空间距离而是色彩强度差计算而来的,在多通道(色彩)图像上强度差由各分量的加权累加代替。可将其当做高斯平滑,指示相似程度更高的像素权值更高,边缘更加明显,对比度更高。

cv::bilateralFilter(InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace, int borderType= cv::BORDER_DEFAULT)

参数:d是像素邻近的最大距离,处理视频时一般不大于5,非实时应用时可放大到9;sigmaColor是色彩空间滤波器的sigma值,该值越大,则色彩强度越大,不连续性越强;sigmaSpace是坐标空间滤波器的sigma值。

导数和梯度

卷积中最重要也是最基本的部分就是(近似)计算导数。

索贝尔导数

一般来说,用来表示微分的最常用的算子是索贝尔(Sobel)导数算子,可以实现任意阶导数和混合偏导数。

void sv::Sobel(InputArray src, OutputArray dst, int ddepth, int xorder, int yorder, cv::Size ksize=3, double scale=1, double delta=0, int borderType=cv::BORDER_DEFAULT)

参数:ddepth指明目标图像的深度或类型;xorder和yorder是求导顺序,其取值可为0,、1或2,其中0代表在该方向不求导,kszie是一个奇数,表示滤波器核的大小, 目前最大到31;阈值和偏移量在结果存入dst前进行调用,公式如下:

dst_i=scale\cdot \left \{ \sum _{i,\: j\in sobel\_kernel}k_{i,\: j}*I(x+i, y+j) \right \}+delta

Sobel算子的好处是可以将核定义为各种大小,并且可以快速迭代式地构造这些核。大的核可以更好地近似导数,因为可以消除噪声影响。其缺点是如果导数在空间上变化剧烈,核太大会使结果发生偏差,并且核比较小时准确度不高。

实际上,由于Sobel算子定义在离散空间上,所以它并不是真正的导数,而是一个多项式,即在x方向上进行Sobel运算表示的并不是二阶导数,而是对抛物线函数的局部拟合。

Scharr滤波器

为了将图像内的信息联系起来,可能需要测量一幅图像:在处理过程中,通过在目标附近组织一幅梯度直方图来收集其形状信息,这些直方图是许多形状分类器训练和使用的基础。因此,梯度角的误差会降低分类器识别的效果。

对于3×3的Sobel滤波器,梯度角距离水平或垂直方向越远,误差越明显。在OpenCV中,调用cv::Sobel()时设置ksize为cv::SCHARR,即可消除3×3这样小但是快的Sobel导数滤波器所带来的误差。Scharr滤波器核Sobel滤波器同样很快,但是前者精度更高。因此选择3×3的滤波器时,应当使用Scharr滤波器。

\begin{bmatrix} -3 & 0 & +3\\ -10 & 0 &+10 \\ -3& 0 & +3 \end{bmatrix}     或     \begin{bmatrix} -3 & -10 & -3\\ 0 & 0 &0 \\ +3& +10 & +3 \end{bmatrix}

拉普拉斯变换

OpenCV中的函数Laplacian实现了对拉普拉斯算子的离散近似:

Laplace(f)=\frac{\partial^2 f}{\partial x^2} + \frac{\partial^2 f}{\partial y^2}

void sv::Laplacian(InputArray src, OutputArray dst, int ddepth, cv::Size ksize=3, double scale=1, double delta=0, int borderType=cv::BORDER_DEFAULT)

只要ksize不为1,Laplacian算子的实现就是直接计算Sobel算子响应之和。当ksize=1时的卷积核如下所示:

\begin{bmatrix} 0 & 1 & 0\\ 1 & 4 &1 \\ 0& 1 & 0 \end{bmatrix}

Laplacian算子可应用于各种场景处理,一种常见的应用就是匹配“斑点”。Laplacian算子就是图像在x和y轴方向的导数之和,这意味着一个被较大值包围的点或小斑点(比ksize小)处的值将会变得很大。相反,被较小值包围的点或小斑点处的值将在负方向上变得很大。

Laplacian算子同样可以用于边缘检测,函数一阶导数在原函数变化大的地方,值会相应变大,同样在图像边缘处也同样变化,所有导数在这些地方将变得很大。因此可以在二阶导数为0的地方搜寻这么一个极大值,原图像中的边缘通过Laplacian算子运算后会变成0。对于有些不是边缘也变成0的问题,可以通过滤掉Sobel一阶导数中较大值的点解决。

图像形态学

OpenCV提供了一种高效且易用的图像形态学变换接口。其中有很多形态学方法,但基本上所有的形态学操作都基于两种原始操作——膨胀与腐蚀。

膨胀和腐蚀

膨胀和腐蚀是最基本的形态学变换,可用于消除噪声、元素分割和连接等。基于这两种操作,可以实现更复杂的形态学操作,用来定位强度峰值或孔洞、另一种形式的图像梯度等。

膨胀是一种卷积操作,它将目标像素的值替换为卷积核覆盖区域的局部最大值,扩张了明亮区域,填充凹面。此卷积核是一个非线性核,是一个四边形或圆形的实心核,其锚点在中心。与膨胀对应,腐蚀是与之相反的操作,腐蚀操作计算的是核覆盖范围内的局部最小值缩减了明亮区,消除凸起。

原图

膨胀

腐蚀

void cv::erode(InputArray src, OutputArray dst, InputArray element, cv::Point anchor=cv::Point(-1, -1), int iterations=1 int borderType=cv::BORDER_CONSTANT, const cv::Scalar& borderValue = cv::morphologyDefaultBorderValue())

void cv::dilate(InputArray src, OutputArray dst, InputArray element, cv::Point anchor=cv::Point(-1, -1), int iterations=1 int borderType=cv::BORDER_CONSTANT, const cv::Scalar& borderValue = cv::morphologyDefaultBorderValue())

以上两个函数分别是膨胀和腐蚀对应的函数,第三个参数是核,可以传递一个未初始化的cv::Mat,会使用默认的锚点在中心的3×3的核。

erode(x, y)=\underset{(i,\: j)\in kernel}{min}src(x+i,\: y+j)

dilate(x, y)=\underset{(i,\: j)\in kernel}{max}src(x+i,\: y+j)

腐蚀操作通常用于消除图中斑点一样的噪声,原理是斑点经过腐蚀后会消失,而大的可见区域不会受影响。膨胀操作通常用于发生连通分支。

通用形态学函数

当处理的对象是二值图像时,像素只能是开(>0)或关(=0)的图像掩膜时,基本的腐蚀和膨胀操作就够用了。需要对灰度图或者彩色图进行处理时,一些其他操作就非常有用了,这些操作可以通过cv::morphologyEx()实现。

void cv::morphologyEx(InputArray src, OutputArray dst, int op, InputArray element, cv::Point anchor=cv::Point(-1, -1), int iterations=1, int borderType=cv::BORDER_CONSTANT, const cv::Scalar& borderValue = cv::morphologyDefaultBorderValue())

cv::morphologyEx()操作op选项
操作值形态学操作是否需要临时图像
cv::MORPH_OPEN开操作
cv::MORPH_CLOSE闭操作
cv::MORPH_GRADIENT形态学梯度总是需要
cv::MORPH_TOPHAT顶帽操作就地调用需要(src = dst)
cv::MORPH_BLACKHAT地貌操作就地调用需要(src = dst)

开操作和闭操作

开操作先将图像进行腐蚀,然后对腐蚀的结果进行膨胀。开操作常用语对二值图像中的区域进行计算。

闭操作想将图像进行膨胀,然后对膨胀的结果进行腐蚀。闭操作用于复杂连通分支算法中减少无用或噪声驱动的片段。

对于连通分支,通常先进行腐蚀或闭操作消除噪声,然后通过开操作连接相互靠近的大型区域。

对于一幅非布尔型图像进行形态学操作时,闭操作最明显的效果是消除值小于邻域内的点的孤立异常,而开操作消除的是大于邻域内点的孤立异常值。

形态学梯度

gradient(src)=dilate(src)-erode(src)

梯度操作的结果(扩张亮域)减腐蚀操作的结果(缩减亮域)产生了原图像中的目标边缘。对于灰度图像,其结果就是计算明暗变换的趋势。形态学梯度通常用于显示明亮区域的边界,然后便可以将他们看作目标或者目标的部分。用扩张的图像减去了收缩的图像便得到完整的边界。与计算梯度不同,它并不会关注某个物体的周围。

顶帽和黑帽

TopHat(src)=src-open(src)

BlackHat(src)=close(src)-src

顶帽用于显示与其邻近相比更亮的部分;黑帽用于显示与其邻近相比更暗的部分。

#include "stdafx.h"
#include <opencv2/opencv.hpp>int main()
{cv::namedWindow("image", cv::WINDOW_NORMAL);cv::namedWindow("erosion", cv::WINDOW_NORMAL);cv::namedWindow("dilation", cv::WINDOW_NORMAL);cv::namedWindow("opening", cv::WINDOW_NORMAL);cv::namedWindow("closing", cv::WINDOW_NORMAL);cv::namedWindow("gradient", cv::WINDOW_NORMAL);cv::namedWindow("topHat", cv::WINDOW_NORMAL);cv::namedWindow("blackHat", cv::WINDOW_NORMAL);cv::Mat img = cv::imread("D:\\personal-data\\wallpapers\\test.png");cv::Mat erosion, dilation, opening, closing, gradient, topHat, blackHat;cv::erode(img, erosion, cv::Mat());cv::dilate(img, dilation, cv::Mat());cv::morphologyEx(img, opening, cv::MORPH_OPEN, cv::Mat());cv::morphologyEx(img, closing, cv::MORPH_CLOSE, cv::Mat());cv::morphologyEx(img, gradient, cv::MORPH_GRADIENT, cv::Mat());cv::morphologyEx(img, topHat, cv::MORPH_TOPHAT, cv::Mat());cv::morphologyEx(img, blackHat, cv::MORPH_BLACKHAT, cv::Mat());cv::imshow("image", img);cv::imshow("erosion", erosion);cv::imshow("dilation", dilation);cv::imshow("opening", opening);cv::imshow("closing", closing);cv::imshow("gradient", gradient);cv::imshow("topHat", topHat);cv::imshow("blackHat", blackHat);cv::waitKey(0);cv::destroyAllWindows();return 0;
}

自定义核

在形态学上,核常常称为“构造元素”,OpenCV提供了创建自定义形态学核的函数cv::getStructuringElement()。

cv::Mat cv::getStructuringElement(int shape, cv::Size ksize, cv::Point anchor=cv::Point(-1, -1))

cv::getStructuringElement()的元素形状
形状值元素描述
cv::MOEPH_RECT矩形E_{i,\: j}=1,\forall i,j
cv::MOEPH_ELLIPSE椭圆形以ksize.width和ksize.height为两个半径做椭圆
cv::MOEPH_CROSS交叉

E_{i,\: j}=1,当 i == anchor.y或 j == anchor.x

用任意线性滤波器做卷积

\begin{bmatrix} -1 & 0 & +1\\ -2& 0 & +2\\ -1& 0 & +1 \end{bmatrix}=\begin{bmatrix} 1\\ 2\\ 1 \end{bmatrix}\bigotimes \begin{bmatrix} -1 & 0 & +1 \end{bmatrix}                    \begin{bmatrix} 0 & 1 & 0\\ 1 &1 &1 \\ 0 & 1 & 0 \end{bmatrix}

上述两个核中,左边的核是可分的,右边的是不可分的。一个可分核可以理解成两个一维核,在卷积时先调用x内核,然后再调用y内核。两个矩阵进行卷积所产生的消耗可以用两个矩阵的面积之积近似。如此一来,用n×n的核对面积为A的图像进行卷积所需要的时间是An^2,但如果分解为n×1和1×n的两个核,那么代价就是An+An=2An。由此可见,分解卷积核可以提高卷积计算的效率。

用cv::filter2D()进行卷积

void cv::filter2D(InputArray src, OutputArray dst, int ddepth, InputArray kernel, cv::Point anchor=cv::Point(-1, -1), double delta=0, int borderType=cv::BORDER_DEFAULT)

注:如果定义了锚点的位置,那么核的大小可以是偶数,否则必须是奇数。

通过cv::sepFilter2D使用可分核

void cv::sepFilter2D(InputArray src, OutputArray dst, int ddepth, InputArray rowKernel, InputArray  columnKernel, cv::Point anchor=cv::Point(-1, -1), double delta=0, int borderType=cv::BORDER_DEFAULT)

注:两个核的大小应当是n1×1和1×n2,n1和n2不一定相等。

生成卷积核

void cv::getDerivKernel(OutputArray kx, OutputArray ky, int dx, int dy, int ksize, bool normalize=true, int ktype=CV_32F)

作用:生成可分解核,如Sobel和Scharr核。dx和dy是求导顺序;ksize是核的大小,可以为1、3、5、7或cv::SCHARR;normalize指示是否核元素规范化,如果是浮点型图像,设为true,反之设为false;ktype表示滤波器的类型,可以使CV_32F和CV_64F。

cv::Mat cv::getGaussianKernel(int ksize, double sigma, int ktype=CV_32F)

作用:生成高斯核。

k_i=\alpha \cdot e^{-\frac{(i-(ksize-1)^2)^2}{(2\sigma )^2}}

α在滤波器需要规范化的时候才起作用。sigma可以为-1,这样将自动计算,其中\sigma =0.3\cdot (\frac{ksize-1}{2}-1)+0.8

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/491356.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

中国科协发布20个重大科学问题和工程技术难题

来源&#xff1a;晓艳的科技坊6月30日&#xff0c;中国科协在第二十一届中国科协年会闭幕式上发布了2019年20个对科学发展具有导向作用、对技术和产业创新具有关键作用的前沿科学问题和工程技术难题。   中国科学院院士、中国科协名誉主席韩启德表示&#xff0c;中国科协重大…

OpenCV常见的图像变换

拉伸、收缩、扭曲和旋转 最简单的图像变换是调整图像大小&#xff0c;使其变大或变小。但实际操作时要比想象的复杂一些&#xff0c;因为调整大小带来了像素如何插值&#xff08;放大&#xff09;或合并&#xff08;减少&#xff09;的问题。 均匀调整 cv::resize() void c…

边缘计算对于工业物联网的重要性

来源&#xff1a;物联网世界随着物联网的发展&#xff0c;工业制造设备所产生的数据量将越来越多。如果这些数据都要放到云端处理&#xff0c;就需要无穷无尽的频谱资源、传输带宽和数据处理能力&#xff0c;“云”难免不堪重负&#xff0c;此时就需要边缘计算来分担云计算的压…

全新算法助机器学习抵抗干扰

来源&#xff1a;科技日报 机器学习模型受到攻击将产生严重的后果&#xff0c;但如果对这一情形提前预防呢&#xff1f;就像人类针对即将到来的病毒去接种疫苗一样。据澳大利亚联邦科学与工业研究组织&#xff08;CSIRO&#xff09;官方网站消息&#xff0c;该机构的一个研究团…

磁共振成像技术发展简史丨科学史

来源&#xff1a;中国科学院苏州生物医学工程技术研究所编者按&#xff1a;核磁共振是一种常见的影像检查方式。全球首次为病人做核磁共振检查是在1977年7月3日。该技术是基于物理学家拉比有关测量原子核在磁场中性质的研究发展而来的。拉比在1988年去世前不久&#xff0c;也使…

最先进的AI还不如动物聪明?首届AI-动物奥运会英国开赛!

来源&#xff1a;animalaiolympics,新智元【导读】目前&#xff0c;即使是最先进的AI智能体&#xff0c;在适应环境变化的能力方面&#xff0c;还无法与动物相提并论。听上去很不可思议对不对&#xff0c;不服来比比看&#xff1f;日前&#xff0c;动物-AI奥运会正式拉开帷幕&a…

background-size 兼容ie8以下浏览器的方法

filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(srcimgs/section-1.png, sizingMethodscale); -ms-filter:"progid:DXImageTransform.Microsoft.AlphaImageLoader(srcimgs/section-1.png, sizingMethodscale)";转载于:https://www.cnblogs.com/wend…

一文尽览5G全产业链及新机遇

来源&#xff1a;5G产业圈5G牌照的发放&#xff0c;对通信产业发展具有重要的战略意义。这不仅仅是为了5G商用&#xff0c;更赋予了多重目的。比如为了利用5G技术推动经济结构创新、促进经济增长、帮助华为中兴、结交爱立信诺基亚&#xff0c;分化高通英特尔……甚至可能是为了…

Windows10+Ubuntu 18.04.2+ROS 安装笔记(SSD单硬盘)上

Windows10Ubuntu 18.04.2ROS 安装笔记&#xff08;SSD单硬盘&#xff09;上一、前言二、化繁为简三、补充说明小结一、前言 最近需要学习ROS和python,于是便需要装Linux系统&#xff0c;于是选则了主流的 Ubuntu 18.04系统&#xff0c;同时与ROS 也是兼容性最好的系统。 之前…

实验室蒋田仔研究员:脑网络组图谱近10年研究详解【附PPT】

来源&#xff1a;模式识别国家重点实验室【导读】脑是人体最为复杂的器官&#xff0c;脑图谱是理解脑的结构和功能的基石。它为探索复杂的脑部结构和异常变化进行"导航"。因此&#xff0c;脑图谱绘制一直以来都是神经科学、认知科学、心理学和脑疾病研究的共同前沿领…

5G最完整的PPT

来源&#xff1a;云数据中心5G未来智能实验室是人工智能学家与科学院相关机构联合成立的人工智能&#xff0c;互联网和脑科学交叉研究机构。未来智能实验室的主要工作包括&#xff1a;建立AI智能系统智商评测体系&#xff0c;开展世界人工智能智商评测&#xff1b;开展互联网&a…

Windows10+Ubuntu 18.04.2+ROS 安装笔记(SSD单硬盘)下

Windows10Ubuntu 18.04.2ROS 安装笔记&#xff08;SSD单硬盘&#xff09;下一、前言二、化繁为简二、补充说明三、测试ROS 是否安装成功一、前言 最近需要学习ROS和python,于是便需要装Linux系统&#xff0c;于是选则了主流的 Ubuntu 18.04系统&#xff0c;同时与ROS 也是兼容…

了解宇宙万物的“第三种方法”​,人工智能正在改变科学

来源&#xff1a;quantamagazine编辑&#xff1a;张卓骏、luciana、笪洁琼、Aileen当今物理和天文实验所产生的海量信息&#xff0c;没有任何一个人或者团队可以完整的处理。有些实验数据每天以千兆字节的规模在增加——而且这个趋势只会越来越明显。想象一下&#xff0c;一台以…

pytorch的backward参数

首先&#xff0c;如果out.backward()中的out是一个标量的话&#xff08;相当于一个神经网络有一个样本&#xff0c;这个样本有两个属性&#xff0c;神经网络有一个输出&#xff09;那么此时我的backward函数是不需要输入任何参数的。 运行结果&#xff1a; 不难看出&#xff0c…

C#表格文字多收缩样式

C#表格文字多收缩样式 <style>.divOpen {height: 24px;overflow: hidden;} </style> ----------------- var html <div class"divOpen" οnclick"divClick(this)" style"cursor: pointer; min-width:100px;">;html value;ht…

意识的哲学、生理及智能属性研究

来源&#xff1a;人机与认知实验室摘要&#xff1a;意识问题一直是各个领域最棘手的难题。本文将从意识的哲学属性、意识的脑属性和意识的智能属性三个角度&#xff0c;分别研究意识研究领域中主要观点与所遇困境&#xff0c;并在文章最后介绍目前已有的意识理论与模型。关键字…

美国反垄断调查背后,硅谷科技巨头不为人知的“阴暗面”

来源&#xff1a;军工圈6月4日&#xff0c;美国众议院司法机构小组委员会负责人向媒体证实&#xff0c;美国政府准备对亚马逊、苹果、Facebook和谷歌4大科技巨头进行反垄断调查。据称&#xff0c;执行反垄断法的美国联邦贸易委员会&#xff08;以下简称FTC&#xff09;和美国司…

第十一章 AtomicInteger源码解析

1、原子类 可以实现一些原子操作基于CAS下面就以AtomicInteger为例。 2、AtomicInteger 在没有AtomicInteger之前&#xff0c;对于一个Integer的线程安全操作&#xff0c;是需要使用同步锁来实现的&#xff0c;当然现在也可以通过ReentrantLock来实现&#xff0c;但是最好最方便…

趋势 | 2019年人工智能行业的25大趋势

来源&#xff1a;网易智能知名创投研究机构CB Insights调研了25种最大的AI趋势&#xff0c;以确定2019年该技术的下一步趋势&#xff0c;他们根据行业采用率和市场优势评估了每种趋势&#xff0c;并将其归类为必要、实验性、威胁性、暂时的。1胶囊网络将挑战最先进的图像识别算…