Filter2D线性滤波
函数说明:可实现对图像应用任意线性滤波器。支持就地操作。边界像素取值可参考CopyMakeBorder。
该函数实际计算相关性,而非卷积:即,内核不是围绕锚点镜像的。如果你需要做卷积,可使用Flip函数对核进行翻转并将锚点设置为(kernel.cols - anchro.x - 1,kernel.rows - anchor.y -1)。 当核大小大于等于(11x11)时,基于DFT(离散傅里叶变换)算法,小内核时使用直接算法。 dst ( x , y ) = ∑ 0 ≤ x ′ < kernel.cols 0 ≤ y ′ < kernel.rows kernel ( x ′ , y ′ ) ∗ src ( x + x ′ − anchor.x , y + y ′ − anchor.y ) \texttt{dst} (x,y) = \sum _{ \substack{0\leq x' < \texttt{kernel.cols}\\{0\leq y' < \texttt{kernel.rows}}}} \texttt{kernel} (x',y')* \texttt{src} (x+x'- \texttt{anchor.x} ,y+y'- \texttt{anchor.y} ) dst(x,y)=∑0≤x′<kernel.cols0≤y′<kernel.rowskernel(x′,y′)∗src(x+x′−anchor.x,y+y′−anchor.y)
//函数原型
void Filter2D(InputArray src,
OutputArray dst,
MatType ddepth,
InputArray kernel,
Point? anchor = null,
double delta = 0.0,
BorderTypes borderType = BorderTypes.Reflect101)`
参数 | 说明 |
---|---|
InputArray src | 输入图像 |
OutputArray dst | 输出图像。大小与通道数与输入图像一致 |
MatType ddepth | 期望的输出深度,具体见Depth combinations表 |
InputArray kernel | 卷积核(相关性内核):单通道浮点型矩阵。如果想对不同通道使用不同核,可先将图像用Split进行分离单独处理 |
Point? anchor | 核的锚点,默认值为null或(-1,-1),表示核的中心点 |
double delta | 计算结果上加该值,可理解为调亮(正数)或调暗(负数) |
BorderTypes borderType | 边框外像素取值方法,不支持Wrap |
Depth combinations
输入深度(Src.Depth() | 输出深度(-1表示与输入深度相同) |
---|---|
CV_8U | -1/CV_16S/CV_32F/CV_64F |
CV_16U/CV_16S | -1/CV_32F/CV_64F |
CV_32F | -1/CV_32F |
CV_64F | -1/CV_64F |
SepFilter2D可分离线性滤波
函数说明:对图像进行可分离线性滤波。首先用一维核KernelX对每一行进行滤波计算,再用一维核KernelY对每一列进行滤波计算,再将结果与Delta进行相加生成最终图像。
//函数原型
void SepFilter2D(InputArray src,
OutputArray dst,
MatType ddepth,
InputArray kernelX,
InputArray kernelY,
Point? anchor = null,
double delta = 0.0,
BorderTypes borderType = BorderTypes.Reflect101)
参数 | 说明 |
---|---|
InputArray src | 输入图像 |
OutputArray dst | 输出图像。大小与通道数与输入图像一致 |
MatType ddepth | 期望的输出深度,具体见Depth combinations表 |
InputArray kernelX | 行滤波核(必须为一维,cols或rows等于1) |
InputArray kernelY | 列滤波核(必须为一维,cols或rows等于1) |
Point? anchor | 核的锚点,默认值为null或(-1,-1),表示核的中心点 |
double delta | 计算结果上加该值,可理解为调亮(正数)或调暗(负数) |
BorderTypes borderType | 边框外像素取值方法,不支持Wrap |
目的
使用指定大小的核对所选图像进行Filter2D和SepFilter2D线性滤波
当核为3x3时,计算公式如下
K = 1 3 ⋅ 3 [ 1 1 1 1 1 1 1 1 1 ] K = \dfrac{1}{3 \cdot 3} \begin{bmatrix} 1 & 1 & 1 \\ 1 & 1 & 1 \\ 1 & 1 & 1 \end{bmatrix} K=3⋅31 111111111
程序可拖动滚动条指定核大小和Delta的值图像示例
代码示例
Mat src;
string winName = "Filter2D Demo Esc:退出";
double delta = 0;
public void Run()
{
//如果未选择图像,则用默认的Lena
if (!Utils.SelectFile(out string fileName)) fileName = ImagePath.Lena;
src = Cv2.ImRead(fileName, ImreadModes.Color);
if (src.Empty()) throw new Exception($"图像打开有误:{fileName}");
Cv2.NamedWindow(winName, WindowFlags.Normal);
Cv2.CreateTrackbar("Size 2n+1", winName, 30, SizeOnChanged);
Cv2.CreateTrackbar("Delta n-100", winName, 200, DeltaOnChanged);
Cv2.SetTrackbarPos("Delta n-100", winName, 100);
while(true)
{
//Esc退出
if ((Cv2.WaitKey(50) == 27)) break;
}
Cv2.DestroyAllWindows();
}
private void OnChanged()
{
Mat kernel = Mat.Ones(new Size(kernelSize, kernelSize), MatType.CV_32F) / (float)(kernelSize * kernelSize);
using var filter2DResult = new Mat();
Cv2.Filter2D(src, filter2DResult, -1, kernel, null, delta, BorderTypes.Default);
Utils.PutText(filter2DResult, $"Size={kernelSize},delta={delta.ToString("0.0")}");
Cv2.ImShow(winName, filter2DResult);
using var sepFilter2DResult = new Mat();
Mat kernelX = Mat.Ones(new Size(kernelSize, 1), MatType.CV_32F) / (float)kernelSize;
Mat kernelY = Mat.Ones(new Size(1, kernelSize), MatType.CV_32F) / (float)kernelSize;
//kernelX与kernelY必须是一维(cols或rows其中一个必须为1)
Cv2.SepFilter2D(src, sepFilter2DResult, -1, kernelX, kernelY, null, delta, BorderTypes.Default);
// 只要核的cols或rows为1,也可以这样调用,具体根据实际情况定义kernelX与kernelY
//Cv2.SepFilter2D(src, dst2, -1, kernelY, kernelX, null, delta, BorderTypes.Default);
Utils.PutText(sepFilter2DResult, $"Size={kernelSize},delta={delta.ToString("0.0")}");
Cv2.NamedWindow("SepFilter2D", WindowFlags.Normal);
Cv2.ImShow("SepFilter2D", sepFilter2DResult);
}
int kernelSize = 1;
/// <summary>
/// 改变核大小
/// </summary>
/// <param name="pos"></param>
/// <param name="userData"></param>
private void SizeOnChanged(int pos, IntPtr userData)
{
kernelSize = pos * 2 + 1;
OnChanged();
}
/// <summary>
/// 改变Delta值
/// </summary>
/// <param name="pos"></param>
/// <param name="userData"></param>
private void DeltaOnChanged(int pos, IntPtr userData)
{
delta = pos -100;
OnChanged();
}
OpenCvSharp函数示例(目录)
参考
https://docs.opencv.org/4.7.0/d4/dbd/tutorial_filter_2d.html