天天看點

C#加載16bit灰階圖像起因OpenCvSharp改進

C#加載16bit灰階圖像

  • 起因
  • OpenCvSharp
  • 改進

起因

用C#寫界面的時候發現Bitmap加載圖像時,對于

Format8bppIndexed

Format16bppGrayScale

類型無法很好地支援,在微軟的官方文檔内也有相關說明

https://docs.microsoft.com/zh-cn/dotnet/api/system.drawing.graphics.fromimage?view=dotnet-plat-ext-5.0

OpenCvSharp

偷懶直接使用了openCv在C#上的封裝,在VS裡直接安裝Nuget包後就能調用OpenCVSharp了。

using OpenCvSharp;
           

Mat轉Bitmap提供了一個方法,但是僅能夠給CV_8U系的圖像使用,對于CV_16UC1的圖像會報錯:

src = new Mat(filename, ImreadModes.Unchanged);
Bitmap dst = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(src);
           

最後通過抽出Mat裡的資料,作為圖像資料給到Bitmap的建構函數。Bitmap的類型也需要同時指定:

src = new Mat(filename, ImreadModes.Unchanged);
Mat dst = null;

if (depth == MatType.CV_8UC1)
	dst = new Bitmap(MATSrc.Width, MATSrc.Height, (int)(MATSrc.Step()), PixelFormat.Format8bppIndexed, MATSrc.Data);
else if (depth == MatType.CV_16UC1)
	dst = new Bitmap(MATSrc.Width, MATSrc.Height, (int)(MATSrc.Step()), PixelFormat.Format16bppGrayScale, MATSrc.Data);
...
src.Dispose();
dst.Dispose();
           

雖然Bitmap和Mat都屬于非托管型資源,需要手動釋放。但是src釋放資源後,圖像資料可能被一并回收,此時調用dst時會報

嘗試通路被保護的記憶體

的錯誤。

最後沒有探究Marshal.Copy将資料備份出來的方法,而是索性在運作過程中不再釋放,每次加載前先檢查并釋放src和dst變量。

最後結束前回收一下垃圾:

GC.Collect();
           

改進

上述方法在測試時遇到了某些圖像加載不了的情況,排查後發現是由于沒有考慮到windows系統對圖像資料的4位元組整數倍對齊的影響。

是以,上述方法隻适合于圖像寬度所占位元組數是4的整數倍的情況下使用。對于16bit位深圖像,圖像寬度需要是偶數才行。