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を見ると、同じビットマップの前の1行がそれ自体で問題なく保存されていても、ほとんどのメンバーが実際の値ではなく「タイプ'InvalidOperationException'の例外をスローした」ことがわかります。入力ビットマップはコード全体で変更されないままであり、何らかの方法で変更する必要がある場合は、常に別のビットマップに複製または描画されます。

lineRemovedを保存​​した後、行をコメントアウトしようとしましたが、同じエラーがコードの後半に表示されます。さらに、そのtry /catchは実際には例外をキャッチしません-それは常に未処理と言います。それはポインタと関係があるはずですが、そうでなければ私はこれを引き起こしているものについて完全に迷っています。

4

1 に答える 1

3

コードに微妙な1文字のバグが含まれています。読む行

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のようなものに置き換えることができます。

実際、horizo​​ntalLinesとverticalLinesをループする方がおそらく効率的です。

于 2012-06-18T20:28:56.917 に答える