卷积的概念:
卷积是如何工作的:
把 kernel 放到像素数组上,求锚点周围覆盖的像素乘积之和(包括锚点),用来替换锚点覆盖下像素点值,成为卷积处理。
其数学表达式:
H ( x , y ) = ∑ i = 0 M i − 1 ∑ j = 0 M j − 1 I ( x + i − a i , y + j − a j ) K ( i , j ) H(x,y)=\sum_{i=0}^{M_i-1}\sum_{j=0}^{M_j-1} I(x+i-a_i,y+j-a_j)K(i,j) H(x,y)=i=0∑Mi−1j=0∑Mj−1I(x+i−ai,y+j−aj)K(i,j)
s u m = ( 11 × 1 ) + ( 8 × 1 ) + ( 23 × 1 ) + ( 11 × 1 ) + ( 8 × 1 ) + ( 23 × 1 ) + ( 11 × 1 ) + ( 8 × 1 ) + ( 23 × 1 ) sum=(11\times1)+(8\times1)+(23\times1)+(11\times1)+(8\times1)+(23\times1)+(11\times1)+(8\times1)+(23\times1) sum=(11×1)+(8×1)+(23×1)+(11×1)+(8×1)+(23×1)+(11×1)+(8×1)+(23×1)
new pixel=sum / (m * n)
卷积核在图像上的卷积动作:
从上到下,从左到右依次对每个像素进行卷积。
卷积一般有3个功能:
1;模糊图像,起到降低图像噪声作用。
2;可以对图像边缘提取。
3;增强图像,对亮度和图像锐化有显著效果。
Robert 算子:
Cv2.Filter2D :Convolves an image with the kernel (将图像与内核进行卷积)
参数 | 说明 |
---|---|
InputArray src | 源图像 |
OutputArray dst | 输出图像 |
MatType ddepth | 目标图像的所需深度。如果为负,则与src.depth()相同 |
InputArray kernel | 卷积核(或者说是相关核),一个单通道浮点矩阵。如果您想将不同的内核应用于不同的通道,可以使用split()将图像分割成单独的彩色平面,并分别处理它们 |
Point? anchor = null | 内核的锚,表示内核中经过过滤的点的相对位置。锚应该位于内核中。特殊的默认值(- 1,1)表示锚位于内核中心 |
double delta = 0 | 计算出来的像素值 + delte (增益值) ,默认值是 0 |
BorderTypes borderType = BorderTypes.Reflect101 | 边缘处理方法,选择默认即可 |
Robert算子:
private static void ImageOperator(string path)
{
using (Mat src = new Mat(path, ImreadModes.Color))
using (Mat dstX = new Mat())
{
#region Robert算子
Mat dstY = new Mat();
//Robert算子 X向量
///*
// * +1 0
// *
// * 0 -1
// *
// * 二位矩阵
// */
InputArray kernelRX = InputArray.Create(new int[2, 2] { { 1, 0 }, { 0, -1 } });
Cv2.Filter2D(src, dstX, src.Depth(), kernelRX, new Point(-1, -1), 0);
////Robert算子 Y向量
///*
//* 0 +1
//*
//* -1 0
//*
//* 二位矩阵
//*/
InputArray kernelRY = InputArray.Create(new int[2, 2] { { 0, 1 }, { -1, 0 } });
Cv2.Filter2D(src, dstY, src.Depth(), kernelRY, new Point(-1, -1), 0);
#endregion
using (new Window("Rober X", WindowMode.Normal, dstX))
using (new Window("Rober Y", WindowMode.Normal, dstY))
using (new Window("SRC", WindowMode.Normal, src))
{
Cv2.WaitKey(0);
}
}
}
Sobel算子
private static void ImageOperator(string path)
{
using (Mat src = new Mat(path, ImreadModes.Color))
using (Mat dstX = new Mat())
{
#region Sobel算子
Mat dstY = new Mat();
//Sobel算子 X向量
///*
// * -1 0 1
// * -2 0 2
// * -1 0 1
// *
// * 二位矩阵
// */
InputArray kernelRX = InputArray.Create(new int[3, 3] { { -1, 0, 1 }, { -2, 0, 2 }, { -1, 0, 1 } });
//Cv2.Filter2D(src, dstX, src.Depth(), kernelRX, new Point(-1, -1), 0);
Cv2.Filter2D(src, dstX, -1, kernelRX, new Point(-1, -1), 0, 0);
////Sobel算子 Y向量
///*
//* -1 -2 -1
//* 0 0 0
//* 1 2 1
//*
//* 二位矩阵
//*/
InputArray kernelRY = InputArray.Create(new int[3, 3] { { -1, -2, -1 }, { 0, 0, 0 }, { 1, 2, 2 } });
//Cv2.Filter2D(src, dstY, src.Depth(), kernelRY, new Point(-1, -1), 0);
Cv2.Filter2D(src, dstY, -1, kernelRY, new Point(-1, -1), 0, 0);
using (new Window("Sobel X", WindowMode.Normal, dstX))
using (new Window("Sobel Y", WindowMode.Normal, dstY))
using (new Window("SRC", WindowMode.Normal, src))
{
Cv2.WaitKey(0);
}
}
}
#region 拉普拉斯算子
////拉普拉斯算子
///*
// * 0 -1 0
// * -1 4 -1
// * 0 -1 0
// * 二位矩阵
// */
InputArray kernel = InputArray.Create(new int[3, 3] { { 0, -1, 0 }, { -1, 4, -1 }, { 0, -1, 0 } });
Cv2.Filter2D(src, dstX, -1, kernel, new Point(-1, -1), 0, 0);
#endregion
自动逐渐模糊:
private static void CustomBlur(string path)
{
Mat src = new Mat(path, ImreadModes.Color | ImreadModes.AnyDepth);
Mat dst = new Mat();
new Window("src", WindowMode.Normal, src);
new Window("Blus filter", WindowMode.Normal);
int e = 0;
int index = 0;
int ksize = 0;
while (true)
{
e = Cv2.WaitKey(500);
if ((char)e == 27) //ESC键退出
{
break;
}
ksize = 4 + 2 * (index % 5)+1;
Mat kernel = Mat.Ones(new Size(ksize, ksize), MatType.CV_32F);/// (ksize, ksize);// new Mat(new Size(ksize, ksize), MatType.CV_32F);
kernel = kernel / (ksize * ksize);
Cv2.Filter2D(src, dst, -1, kernel, new Point(-1, -1));
index++;
Cv2.ImShow("Blus filter", dst);
}
}