1

我正在尝试制作一个程序,该程序使用指针检测图像中的线条并删除这些线条。目前,检测线部分工作得非常好,大部分情况下,删除线部分也工作得很好。但是,在大约 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;
}

在此代码之后,我保存生成的位图并将其嵌入到另一个位图中以进行比较:

// ... 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'的异常”而不是实际值,即使在同一个位图之前的一行保存得很好。输入位图在整个代码中保持不变,并且当我需要以任何方式更改它时,它总是被克隆或绘制到不同的位图。

我尝试在保存 lineRemoved 后注释掉这些行,但是稍后在代码中会弹出相同的错误。更重要的是,try/catch 实际上并没有捕捉到异常——它总是说未处理。它必须与指针有关,但否则我完全不知道是什么原因造成的。

4

1 回答 1

3

您的代码包含一个微妙的单字符错误。读取的行

for (int c = 0; c < h; c++) 

应该

for (int c = 0; c < w; c++) 

如果图像是横向的,您的错误将导致图像的右侧部分未被处理。

如果图像是纵向的,它会导致缓冲区溢出,导致访问冲突异常(如果你幸运的话)或内存损坏(如果你不是)。

话虽如此,您的算法效率不高。例如,您正在计算

int i = (r * s) + c * bpp; 

对于您正在绘制的每个像素,显然 (r * s) 在内循环中不会改变,并且 c * bpp 可以替换为 currentPixel += bpp 之类的东西。

事实上,在水平线和垂直线上循环可能会更有效。

于 2012-06-18T20:28:56.917 回答