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位深圖像,圖像寬度需要是偶數才行。