我正在尝试在WPF程序中实现图像边缘检测。 我已经可以使用它了,但是图像的转换非常慢。 该代码未使用慢速的GetPixel和SetPixel函数。但是,相反,我使用一些不安全的代码遍历了图像,以便可以使用指针直接访问该值。 在开始边缘检测之前,我还将图像转换为灰度图像,以提高边缘检测速度。
但是程序仍然需要大约1600ms的时间来转换大小为1920x1440像素的图像,我认为这可能会更快。
这就是我转换图像的方式,我想知道如何才能实现其他一些速度改进?
加载图像并创建一个灰度WriteableBitmap:
private void imageData_Loaded(object sender, RoutedEventArgs e)
{
if (imageData.Source != null)
{
BitmapSource BitmapSrc = new FormatConvertedBitmap(imageData.Source as BitmapSource, PixelFormats.Gray8 /* Convert to greyscale image */, null, 0);
writeableOriginalBitmap = new WriteableBitmap(BitmapSrc);
writeableBitmap = writeableOriginalBitmap.Clone();
imageData.Source = writeableBitmap;
EdgeDetection();
}
}
转换图像:
private const int TOLERANCE = 20;
private void EdgeDetection()
{
DateTime startTime = DateTime.Now; //Save starting time
writeableOriginalBitmap.Lock();
writeableBitmap.Lock();
unsafe
{
byte* pBuffer = (byte*)writeableBitmap.BackBuffer.ToPointer();
byte* pOriginalBuffer = (byte*)writeableOriginalBitmap.BackBuffer.ToPointer();
for (int row = 0; row < writeableOriginalBitmap.PixelHeight; row++)
{
for (int column = 0; column < writeableOriginalBitmap.PixelWidth; column++)
{
byte edgeColor = getEdgeColor(column, row, pOriginalBuffer); //Get pixel color based on edge value
pBuffer[column + (row * writeableBitmap.BackBufferStride)] = (byte)(255 - edgeColor);
}
}
}
//Refresh image
writeableBitmap.AddDirtyRect(new Int32Rect(0, 0, writeableBitmap.PixelWidth, writeableBitmap.PixelHeight));
writeableBitmap.Unlock();
writeableOriginalBitmap.Unlock();
//Calculate converting time
TimeSpan diff = DateTime.Now - startTime;
Debug.WriteLine("Loading Time: " + (int)diff.TotalMilliseconds);
}
private unsafe byte getEdgeColor(int xPos, int yPos, byte* pOriginalBuffer)
{
byte Color;
byte maxColor = 0;
byte minColor = 255;
int difference;
//Calculate max and min value of surrounding pixels
for (int y = yPos - 1; y <= yPos + 1; y++)
{
for (int x = xPos - 1; x <= xPos + 1; x++)
{
if (x >= 0 && x < writeableOriginalBitmap.PixelWidth && y >= 0 && y < writeableOriginalBitmap.PixelHeight)
{
Color = pOriginalBuffer[x + (y * writeableOriginalBitmap.BackBufferStride)];
if (Color > maxColor) //If current pixel has higher value as previous max pixel
maxColor = Color; //Save current pixel value as max
if (Color < minColor) //If current pixel has lower value as previous min pixel
minColor = Color; //Save current pixel value as min
}
}
}
//Difference of minimum and maximum pixel with tollerance
difference = maxColor - minColor - TOLERANCE;
if (difference < 0)
difference = 0;
return (byte)difference;
}
控制台输出:
Loading Time: 1599
答案 0 :(得分:4)
以下代码在字节数组而不是WriteableBitmap的BackBuffer上运行算法。它可以在不到300毫秒的时间内完成,并在我的PC上显示为1900x1200的图像。
private static BitmapSource EdgeDetection(BitmapSource source)
{
var stopwatch = Stopwatch.StartNew();
var bitmap = new FormatConvertedBitmap(source, PixelFormats.Gray8, null, 0);
var width = bitmap.PixelWidth;
var height = bitmap.PixelHeight;
var originalBuffer = new byte[width * height];
var buffer = new byte[width * height];
bitmap.CopyPixels(originalBuffer, width, 0);
for (var y = 0; y < height; y++)
{
for (var x = 0; x < width; x++)
{
byte edgeColor = GetEdgeColor(originalBuffer, width, height, x, y);
buffer[width * y + x] = (byte)(255 - edgeColor);
}
}
Debug.WriteLine(stopwatch.ElapsedMilliseconds);
return BitmapSource.Create(
width, height, 96, 96, PixelFormats.Gray8, null, buffer, width);
}
private static byte GetEdgeColor(byte[] buffer, int width, int height, int x, int y)
{
const int tolerance = 20;
byte minColor = 255;
byte maxColor = 0;
var xStart = Math.Max(0, x - 1);
var xEnd = Math.Min(width - 1, x + 1);
var yStart = Math.Max(0, y - 1);
var yEnd = Math.Min(height - 1, y + 1);
for (var j = yStart; j <= yEnd; j++)
{
for (var i = xStart; i <= xEnd; i++)
{
var color = buffer[width * j + i];
minColor = Math.Min(minColor, color);
maxColor = Math.Max(maxColor, color);
}
}
return (byte)Math.Max(0, maxColor - minColor - tolerance);
}