如何在 C# 中调用 Sobel 滤波器和图像处理函数
How can I call the function for Sobel filter,Image processing in C#
我正在尝试写一个 sobel filter.In 简而言之,我应该将图像转换为灰度滤镜然后我应该将 sobel 滤镜应用于 image.I 找到了一个代码,但我不擅长面向对象 programming.How 我可以在按下按钮时调用函数吗?
代码如下:
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.This 是我无法填充的部分:
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 } });
}
}
假设卷积方法是正确的,你应该简单地调用它,比如
private void btnapply_Click(object sender, EventArgs e)
{
if(picoriginal.Image is Bitmap bitmap){
picfilte.Image = ConvolutionFilter(bitmap, xSobel, ySobel)
}
}
我正在尝试写一个 sobel filter.In 简而言之,我应该将图像转换为灰度滤镜然后我应该将 sobel 滤镜应用于 image.I 找到了一个代码,但我不擅长面向对象 programming.How 我可以在按下按钮时调用函数吗?
代码如下:
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.This 是我无法填充的部分:
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 } });
}
}
假设卷积方法是正确的,你应该简单地调用它,比如
private void btnapply_Click(object sender, EventArgs e)
{
if(picoriginal.Image is Bitmap bitmap){
picfilte.Image = ConvolutionFilter(bitmap, xSobel, ySobel)
}
}