2012-06-18 20 views
0

我想使一個程序,使用指針,檢測圖像中的行並刪除這些行。目前,檢測線部分工作得很好,大部分去除線部分也是如此。但是,在大約150-200張圖像之後,該程序將在隨機代碼的不安全位無關的地方隨機引入AccessViolationException。隨機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實際上並沒有捕捉到異常 - 它總是說未處理。這與指針有關,但除此之外,我完全喪失了什麼導致了這一點。

+2

for(int c = 0; c

+0

@KrisVandermotten這是一種遲鈍的尷尬。有一個問題,刪除行並沒有覆蓋整個圖像,但我把這個問題放在了較低的優先級上來找出那個問題。當然解決方案對於這兩個問題都是一樣的...... – Abion47

+0

「遲鈍地尷尬」:-)「當然兩種問題的解決方案都是一樣的。」您是否確認訪問違規行爲已經消失? –

回答

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。

事實上,它可能會更有效地循環horizo​​ntalLines和verticalLines。

+0

感謝您的回答。代碼的效率增強改變的好處也一樣。 – Abion47