【发布时间】:2018-10-17 08:46:22
【问题描述】:
我正在尝试在 WPF 程序中实现图像边缘检测。 我已经让它工作了,但是图像的转换很慢。 该代码没有使用缓慢的 GetPixel 和 SetPixel 函数。但相反,我在一些不安全的代码中循环遍历图像,以便我可以使用指针直接访问该值。 在开始边缘检测之前,我还将图像转换为灰度图像以提高边缘检测速度。
但程序仍然需要大约 1600 毫秒来转换大小为 1920x1440 像素的图像,我认为这可能会快得多。
这就是我转换图像的方式,我想知道我可以做些什么来获得其他一些速度改进?
加载图像并创建灰度可写位图:
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
【问题讨论】:
-
我会使用 StopWatch 来获得更准确的测量结果 - 但这并不能解决您的问题。
-
您是否尝试过使用简单的字节数组而不是 WriteableBitmaps 来运行该代码?使用 BitmapSource.CopyPixels 一次从 BitmapSource 获取字节数组,然后使用 BitmapSource.Create 转换回 BitmapSource。
-
@Clemens 我看到你刚刚发布了一个答案,我没有尝试简单的咬合数组。于是开始实施。这只是给了我巨大的时间改进,并在 343 毫秒内完成了转换。感谢您提供有用的提示。现在让我看看你的回答,看看我是否可以改进我的代码。
-
不那么重要,但根据 VS 分析器:writeableBitmap.BackBufferStride 和 writeableOriginalBitmap.PixelHeight,writeableOriginalBitmap.PixelWidth,一遍又一遍地访问未更改的变量是性能的 5%。
标签: c# wpf image-processing