如何在 C# 中调用 Sobel 过滤器、图像处理的函数
Posted
技术标签:
【中文标题】如何在 C# 中调用 Sobel 过滤器、图像处理的函数【英文标题】:How can I call the function for Sobel filter,Image processing in C# 【发布时间】:2021-11-29 23:35:18 【问题描述】:我正在尝试编写一个 sobel 过滤器。简而言之,我应该将图像转换为灰度过滤器,然后我应该将 sobel 过滤器应用于图像。我找到了一个代码,但我不擅长面向对象编程。如何我按下按钮时调用该函数?
代码如下:
using AForge.Video.DirectShow;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace dnm1110
public partial class Form1 : Form
public Form1()
InitializeComponent();
public FilterInfoCollection devices;
public VideoCaptureDevice camera;
private void Form1_Load(object sender, EventArgs e)
devices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
foreach (FilterInfo item in devices)
comboBox1.Items.Add(item.Name);
camera = new VideoCaptureDevice();
comboBox1.SelectedIndexChanged += comboBox1_SelectedIndexChanged;
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
try
if (camera.IsRunning == false)
camera = new VideoCaptureDevice(devices[comboBox1.SelectedIndex].MonikerString);
camera.NewFrame += Camera_NewFrame;
camera.Start();
catch (Exception exc)
MessageBox.Show(exc.Message + "");
private void Camera_NewFrame(object sender, AForge.Video.NewFrameEventArgs eventArgs)
Bitmap bitmap = (Bitmap)eventArgs.Frame.Clone();
picoriginal.Image = bitmap;
private void btnapply_Click(object sender, EventArgs e)
private static Bitmap ConvolutionFilter(Bitmap bitmap,double[,] xkernel, double[,] ykernel, double factor = 1, int bias = 0, bool grayscale = false)
//Image dimensions stored in variables for convenience
int width = bitmap.Width;
int height = bitmap.Height;
//Lock source image bits into system memory
BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
//Get the total number of bytes in your image - 32 bytes per pixel x image width x image height -> for 32bpp images
int bytes = bmpData.Stride * bmpData.Height;
//Create byte arrays to hold pixel information of your image
byte[] pixelBuffer = new byte[bytes];
byte[] bitmap2Buffer = new byte[bytes];
//Get the address of the first pixel data
IntPtr srcScan0 = bmpData.Scan0;
//Copy image data to one of the byte arrays
Marshal.Copy(srcScan0, pixelBuffer, 0, bytes);
//Unlock bits from system memory -> we have all our needed info in the array
bitmap.UnlockBits(bmpData);
//Convert your image to grayscale if necessary
if (grayscale == true)
float rgb = 0;
for (int i = 0; i < pixelBuffer.Length; i += 4)
rgb = pixelBuffer[i] * .21f;
rgb += pixelBuffer[i + 1] * .71f;
rgb += pixelBuffer[i + 2] * .071f;
pixelBuffer[i] = (byte)rgb;
pixelBuffer[i + 1] = pixelBuffer[i];
pixelBuffer[i + 2] = pixelBuffer[i];
pixelBuffer[i + 3] = 255;
//Create variable for pixel data for each kernel
double xr = 0.0;
double xg = 0.0;
double xb = 0.0;
double yr = 0.0;
double yg = 0.0;
double yb = 0.0;
double rt = 0.0;
double gt = 0.0;
double bt = 0.0;
//This is how much your center pixel is offset from the border of your kernel
//Sobel is 3x3, so center is 1 pixel from the kernel border
int filterOffset = 1;
int calcOffset = 0;
int byteOffset = 0;
//Start with the pixel that is offset 1 from top and 1 from the left side
//this is so entire kernel is on your image
for (int OffsetY = filterOffset; OffsetY < height - filterOffset; OffsetY++)
for (int OffsetX = filterOffset; OffsetX < width - filterOffset; OffsetX++)
//reset rgb values to 0
xr = xg = xb = yr = yg = yb = 0;
rt = gt = bt = 0.0;
//position of the kernel center pixel
byteOffset = OffsetY * bmpData.Stride + OffsetX * 4;
//kernel calculations
for (int filterY = -filterOffset; filterY <= filterOffset; filterY++)
for (int filterX = -filterOffset; filterX <= filterOffset; filterX++)
calcOffset = byteOffset + filterX * 4 + filterY * bmpData.Stride;
xb += (double)(pixelBuffer[calcOffset]) * xkernel[filterY + filterOffset, filterX + filterOffset];
xg += (double)(pixelBuffer[calcOffset + 1]) * xkernel[filterY + filterOffset, filterX + filterOffset];
xr += (double)(pixelBuffer[calcOffset + 2]) * xkernel[filterY + filterOffset, filterX + filterOffset];
yb += (double)(pixelBuffer[calcOffset]) * ykernel[filterY + filterOffset, filterX + filterOffset];
yg += (double)(pixelBuffer[calcOffset + 1]) * ykernel[filterY + filterOffset, filterX + filterOffset];
yr += (double)(pixelBuffer[calcOffset + 2]) * ykernel[filterY + filterOffset, filterX + filterOffset];
//total rgb values for this pixel
bt = Math.Sqrt((xb * xb) + (yb * yb));
gt = Math.Sqrt((xg * xg) + (yg * yg));
rt = Math.Sqrt((xr * xr) + (yr * yr));
//set limits, bytes can hold values from 0 up to 255;
if (bt > 255) bt = 255;
else if (bt < 0) bt = 0;
if (gt > 255) gt = 255;
else if (gt < 0) gt = 0;
if (rt > 255) rt = 255;
else if (rt < 0) rt = 0;
//set new data in the other byte array for your image data
bitmap2Buffer[byteOffset] = (byte)(bt);
bitmap2Buffer[byteOffset + 1] = (byte)(gt);
bitmap2Buffer[byteOffset + 2] = (byte)(rt);
bitmap2Buffer[byteOffset + 3] = 255;
//Create new bitmap which will hold the processed data
Bitmap bitmap2 = new Bitmap(width, height);
//Lock bits into system memory
BitmapData bmp2Data = bitmap2.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
//Copy from byte array that holds processed data to bitmap
Marshal.Copy(bitmap2Buffer, 0, bmp2Data.Scan0, bitmap2Buffer.Length);
//Unlock bits from system memory
bitmap2.UnlockBits(bmp2Data);
//Return processed image
return bitmap2;
//Sobel operator kernel for horizontal pixel changes
private static double[,] xSobel
get
return new double[,]
-1, 0, 1 ,
-2, 0, 2 ,
-1, 0, 1
;
//Sobel operator kernel for vertical pixel changes
private static double[,] ySobel
get
return new double[,]
1, 2, 1 ,
0, 0, 0 ,
-1, -2, -1
;
我正在尝试使用 picfilte.Image 从相机获取视图。这是我无法填充的部分:
private void btnapply_Click(object sender, EventArgs e)
//How should I fill this part?
编辑:如果我编写此代码,则代码正在编译:
private void btnapply_Click(object sender, EventArgs e)
if (picoriginal.Image is Bitmap image)
picfilter.Image = ConvolutionFilter(image, new double[3, 3] -1, -2, -1 , 0, 0, 0 , 1, 2, 1 , new double[3, 3] -1, 0, 1 , -2, 0, 2 , -1, 0, 1 );
【问题讨论】:
花点时间格式化代码,使其可读 你的意思是我应该在代码之间留一些空间吗? 代码完全不对齐并且相当难以阅读。我不是挑剔,尽管当您竭尽全力使您的问题易于消化和阅读时,您会得到更好的回答 感谢您的评论,但我为索贝尔苦苦挣扎了一段时间,我还无法解决这个问题。所以我希望有人能回答这个问题。用指针做这件事的来源非常有限,或者我找不到。 【参考方案1】:假设卷积方法是正确的,你应该简单地调用它,类似
private void btnapply_Click(object sender, EventArgs e)
if(picoriginal.Image is Bitmap bitmap)
picfilte.Image = ConvolutionFilter(bitmap, xSobel, ySobel)
【讨论】:
非常感谢您的回答。它奏效了。我用您的方法修复了代码。我将编辑问题。以上是关于如何在 C# 中调用 Sobel 过滤器、图像处理的函数的主要内容,如果未能解决你的问题,请参考以下文章
如何绘制 tf.image.sobel_edges 返回的图像张量