如何在 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 过滤器、图像处理的函数的主要内容,如果未能解决你的问题,请参考以下文章

在 C# 中处理纯虚函数调用

大尺寸 Sobel 滤波器核

如何绘制 tf.image.sobel_edges 返回的图像张量

如何将第一个处理图像(例如 Canny 过滤器)的输出作为另一个处理过滤器的输入?

OpenCV图像梯度(Sobel和Scharr)

OpenCV中不用库函数实现sobel算子