我正在尝试制作一个程序,使用指针检测图像中的线条并删除这些线条。目前,检测线部分工作得非常好,并且在大多数情况下,移除线部分也是有效的。但是,在大约150-200个图像之后,程序将在与代码的不安全位无关的位置抛出随机的AccessViolationExceptions。
这是删除行的位:
static unsafe Bitmap RemoveLines(Bitmap input, int[] horizontalLines, int[] verticalLines)
{
Bitmap output;
if (input.PixelFormat == PixelFormat.Format24bppRgb)
{
output = (Bitmap) input.Clone();
}
else
{
output = ConvertTo24bpp((Bitmap)input.Clone());
}
BitmapData bitmapData = output.LockBits(new Rectangle(0, 0, output.Width, output.Height), ImageLockMode.ReadWrite, output.PixelFormat);
int w = output.Width;
int h = output.Height;
int bpp = 3;
int s = bitmapData.Stride;
byte* p = (byte*) bitmapData.Scan0;
for (int r = 0; r < h; r++)
{
for (int c = 0; c < h; c++)
{
if (horizontalLines.Contains(r) || verticalLines.Contains(c))
{
int i = (r * s) + c * bpp;
p[i + 0] = 255;
p[i + 1] = 255;
p[i + 2] = 255;
}
}
}
output.UnlockBits(bitmapData);
return output;
}
在此代码之后,我保存了生成的Bitmap,并将其嵌入另一个Bitmap中以进行比较:
// ... Detect lines and such
Bitmap export = new Bitmap(bitmap.Width * 3, bitmap.Height, PixelFormat.Format24bppRgb);
Graphics fg = Graphics.FromImage(export);
fg.DrawImage(bitmap, 0, 0); // Draw the original input bitmap
fg.DrawImage(edited, bitmap.Width, 0); // Draw the input after processing (Line Detection)
try
{
Bitmap lineRemoved = RemoveLines(bitmap, horizontalLines.ToArray(), verticalLines.ToArray()); // Remove lines based on earlier detection
lineRemoved.Save(cellDirectory + "\\Lines\\cell_lr_" + i.ToString("D2") + j.ToString("D2") + ".gif", ImageFormat.Gif); // Save image after removal
fg.DrawImage(lineRemoved, bitmap.Width * 2, 0); // Add image to composite for comparison; This line is what throws the error most of the time
lineRemoved.Dispose();
export.Save(cellDirectory + "\\Lines\\cell" + i.ToString("D2") + j.ToString("D2") + ".gif", ImageFormat.Gif);
}
catch (Exception ex)
{ }
DrawImage调用是抛出错误的,它始终是一个AccessViolationException,后跟一个InvalidOperationException。在错误期间查看lineRemoved显示其大多数成员“抛出了'InvalidOperationException'类型的异常而不是实际值,即使同一个Bitmap之前的一行保存得很好。输入位图在整个代码中保持不变,并且当我需要以任何方式更改它时,始终克隆或绘制到不同的位图。
我在保存lineRemoved之后尝试将这些行注释掉,但之后会在代码中弹出相同的错误。更重要的是,try / catch实际上并没有捕获异常 - 它总是说未处理。它必须与指针有关,但除此之外我完全迷失了造成这种情况的原因。
答案 0 :(得分:3)
您的代码包含一个微妙的单字符错误。读取的行
for (int c = 0; c < h; c++)
应该是
for (int c = 0; c < w; c++)
如果图像处于横向,则您的错误会导致图像的右侧部分无法处理。
如果图像处于protrait方向,则会导致缓冲区溢出,导致访问冲突异常(如果幸运)或内存损坏(如果不是)。
话虽这么说,你的算法效率不高。例如,您正在进行计算
int i = (r * s) + c * bpp;
对于你正在绘制的每个像素,而显然(r * s)在内部循环中没有变化,而c * bpp可以被像currentPixel + = bpp这样的东西替换。
实际上,循环horizontalLines和verticalLines可能更有效。