/// <summary> /// Constructor /// </summary> /// <param name="parent"></param> internal MatIndexer(Mat parent) { this.parent = parent; int dims = parent.Dims(); steps = new long[dims]; for (int i = 0; i < dims; i++) { steps[i] = (long)parent.Step(i); } }
/// <summary> /// System.Drawing.BitmapからOpenCVのMatへ変換して返す. /// </summary> /// <param name="src">変換するSystem.Drawing.Bitmap</param> /// <param name="dst">変換結果を格納するMat</param> #else /// <summary> /// Converts System.Drawing.Bitmap to Mat /// </summary> /// <param name="src">System.Drawing.Bitmap object to be converted</param> /// <param name="dst">A Mat object which is converted from System.Drawing.Bitmap</param> #endif public static unsafe void ToMat(Bitmap src, Mat dst) { if (src == null) { throw new ArgumentNullException("src"); } if (dst == null) { throw new ArgumentNullException("dst"); } if (dst.IsDisposed) { throw new ArgumentException("The specified dst is disposed.", "dst"); } if (dst.Depth() != MatType.CV_8U) { throw new NotSupportedException("Mat depth != CV_8U"); } if (dst.Dims() != 2) { throw new NotSupportedException("Mat dims != 2"); } //if (dst.IsSubmatrix()) // throw new NotSupportedException("Submatrix is not supported"); if (src.Width != dst.Width || src.Height != dst.Height) { throw new ArgumentException("src.Size != dst.Size"); } int w = src.Width; int h = src.Height; Rectangle rect = new Rectangle(0, 0, w, h); BitmapData bd = null; try { bd = src.LockBits(rect, ImageLockMode.ReadOnly, src.PixelFormat); byte *p = (byte *)bd.Scan0.ToPointer(); int sstep = bd.Stride; int offset = sstep - (w / 8); uint dstep = (uint)dst.Step(); byte *dstData = (byte *)dst.Data.ToPointer(); switch (src.PixelFormat) { case PixelFormat.Format1bppIndexed: { if (dst.Channels() != 1) { throw new ArgumentException("Invalid nChannels"); } int x = 0; int y; int bytePos; byte b; int i; for (y = 0; y < h; y++) { // 横は必ず4byte幅に切り上げられる。 // この行の各バイトを調べていく for (bytePos = 0; bytePos < sstep; bytePos++) { if (x < w) { // 現在の位置のバイトからそれぞれのビット8つを取り出す b = p[bytePos]; for (i = 0; i < 8; i++) { if (x >= w) { break; } // IplImageは8bit/pixel dstData[dstep * y + x] = ((b & 0x80) == 0x80) ? (byte)255 : (byte)0; b <<= 1; x++; } } } // 次の行へ x = 0; p += sstep; } } break; case PixelFormat.Format8bppIndexed: case PixelFormat.Format24bppRgb: { if (dst.Channels() != 1) { throw new ArgumentException("Invalid nChannels"); } // Mat幅が4の倍数なら一気にコピー if (dstep % 4 == 0) { uint length = (uint)(dst.DataEnd.ToInt64() - dst.DataStart.ToInt64()); Util.CopyMemory(dst.DataStart, bd.Scan0, length); } else { // 各行ごとにdstの行バイト幅コピー byte *sp = (byte *)bd.Scan0; byte *dp = (byte *)dst.DataStart; for (int y = 0; y < h; y++) { Util.CopyMemory(dp, sp, dstep); sp += sstep; dp += dstep; } } } break; case PixelFormat.Format32bppRgb: case PixelFormat.Format32bppArgb: case PixelFormat.Format32bppPArgb: { // 4チャネルならアラインメント調整いらない(はず) switch (dst.Channels()) { case 4: uint length = (uint)(dst.DataEnd.ToInt64() - dst.DataStart.ToInt64()); Util.CopyMemory(dst.DataStart, bd.Scan0, length); break; case 3: for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { dstData[y * dstep + x * 3 + 0] = p[y * sstep + x * 4 + 0]; dstData[y * dstep + x * 3 + 1] = p[y * sstep + x * 4 + 1]; dstData[y * dstep + x * 3 + 2] = p[y * sstep + x * 4 + 2]; } } break; default: throw new ArgumentException("Invalid nChannels"); } } break; } } finally { if (bd != null) { src.UnlockBits(bd); } } }
/// <summary> /// System.Drawing.BitmapからOpenCVのMatへ変換して返す. /// </summary> /// <param name="src">変換するSystem.Drawing.Bitmap</param> /// <param name="dst">変換結果を格納するMat</param> #else /// <summary> /// Converts System.Drawing.Bitmap to Mat /// </summary> /// <param name="src">System.Drawing.Bitmap object to be converted</param> /// <param name="dst">A Mat object which is converted from System.Drawing.Bitmap</param> #endif public static unsafe void ToMat(this Bitmap src, Mat dst) { if (src == null) throw new ArgumentNullException("src"); if (dst == null) throw new ArgumentNullException("dst"); if (dst.IsDisposed) throw new ArgumentException("The specified dst is disposed.", "dst"); if (dst.Depth() != MatType.CV_8U) throw new NotSupportedException("Mat depth != CV_8U"); if (dst.Dims() != 2) throw new NotSupportedException("Mat dims != 2"); if (src.Width != dst.Width || src.Height != dst.Height) throw new ArgumentException("src.Size != dst.Size"); int w = src.Width; int h = src.Height; Rectangle rect = new Rectangle(0, 0, w, h); BitmapData bd = null; try { bd = src.LockBits(rect, ImageLockMode.ReadOnly, src.PixelFormat); byte* p = (byte*)bd.Scan0.ToPointer(); int sstep = bd.Stride; int offset = sstep - (w / 8); uint dstep = (uint)dst.Step(); IntPtr dstData = dst.Data; byte* dstPtr = (byte*)dstData.ToPointer(); bool submat = dst.IsSubmatrix(); bool continuous = dst.IsContinuous(); switch (src.PixelFormat) { case PixelFormat.Format1bppIndexed: { if (dst.Channels() != 1) throw new ArgumentException("Invalid nChannels"); if (submat) throw new NotImplementedException("submatrix not supported"); int x = 0; int y; int bytePos; byte b; int i; for (y = 0; y < h; y++) { // 横は必ず4byte幅に切り上げられる。 // この行の各バイトを調べていく for (bytePos = 0; bytePos < sstep; bytePos++) { if (x < w) { // 現在の位置のバイトからそれぞれのビット8つを取り出す b = p[bytePos]; for (i = 0; i < 8; i++) { if (x >= w) { break; } // IplImageは8bit/pixel dstPtr[dstep * y + x] = ((b & 0x80) == 0x80) ? (byte)255 : (byte)0; b <<= 1; x++; } } } // 次の行へ x = 0; p += sstep; } } break; case PixelFormat.Format8bppIndexed: case PixelFormat.Format24bppRgb: { if (src.PixelFormat == PixelFormat.Format8bppIndexed) if (dst.Channels() != 1) throw new ArgumentException("Invalid nChannels"); if (src.PixelFormat == PixelFormat.Format24bppRgb) if (dst.Channels() != 3) throw new ArgumentException("Invalid nChannels"); // ステップが同じで連続なら、一気にコピー if (dstep == sstep && !submat && continuous) { uint length = (uint)(dst.DataEnd.ToInt64() - dstData.ToInt64()); Util.CopyMemory(dstData, bd.Scan0, length); } else { // 各行ごとにdstの行バイト幅コピー byte* sp = (byte*)bd.Scan0; byte* dp = (byte*)dst.Data; for (int y = 0; y < h; y++) { Util.CopyMemory(dp, sp, dstep); sp += sstep; dp += dstep; } } } break; case PixelFormat.Format32bppRgb: case PixelFormat.Format32bppArgb: case PixelFormat.Format32bppPArgb: { switch (dst.Channels()) { case 4: if (!submat && continuous) { uint length = (uint)(dst.DataEnd.ToInt64() - dstData.ToInt64()); Util.CopyMemory(dstData, bd.Scan0, length); } else { byte* sp = (byte*)bd.Scan0; byte* dp = (byte*)dst.Data; for (int y = 0; y < h; y++) { Util.CopyMemory(dp, sp, dstep); sp += sstep; dp += dstep; } } break; case 3: for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { dstPtr[y * dstep + x * 3 + 0] = p[y * sstep + x * 4 + 0]; dstPtr[y * dstep + x * 3 + 1] = p[y * sstep + x * 4 + 1]; dstPtr[y * dstep + x * 3 + 2] = p[y * sstep + x * 4 + 2]; } } break; default: throw new ArgumentException("Invalid nChannels"); } } break; } } finally { if(bd != null) src.UnlockBits(bd); } }
/// <summary> /// WriteableBitmapをMatに変換する. /// </summary> /// <param name="src">変換するWriteableBitmap</param> /// <param name="dst">出力先のMat</param> #else /// <summary> /// Converts WriteableBitmap to Mat /// </summary> /// <param name="src">Input WriteableBitmap</param> /// <param name="dst">Output Mat</param> #endif public static void ToMat(this WriteableBitmap src, Mat dst) { if (src == null) throw new ArgumentNullException("src"); if (dst == null) throw new ArgumentNullException("dst"); if (src.PixelWidth != dst.Width || src.PixelHeight != dst.Height) throw new ArgumentException("size of src must be equal to size of dst"); if (dst.Dims() > 2) throw new ArgumentException("Mat dimensions must be 2"); int w = src.PixelWidth; int h = src.PixelHeight; int bpp = src.Format.BitsPerPixel; int channels = GetOptimumChannels(src.Format); if (dst.Channels() != channels) { throw new ArgumentException("nChannels of dst is invalid", "dst"); } unsafe { byte* p = (byte*)(dst.Data); long step = dst.Step(); // 1bppは手作業でコピー if (bpp == 1) { // BitmapImageのデータを配列にコピー // 要素1つに横8ピクセル分のデータが入っている。 int stride = (w / 8) + 1; byte[] pixels = new byte[h * stride]; src.CopyPixels(pixels, stride, 0); int x = 0; for (int y = 0; y < h; y++) { int offset = y * stride; // この行の各バイトを調べていく for (int bytePos = 0; bytePos < stride; bytePos++) { if (x < w) { // 現在の位置のバイトからそれぞれのビット8つを取り出す byte b = pixels[offset + bytePos]; for (int i = 0; i < 8; i++) { if (x >= w) { break; } p[step * y + x] = ((b & 0x80) == 0x80) ? (byte)255 : (byte)0; b <<= 1; x++; } } } // 次の行へ x = 0; } } // 8bpp /*else if (bpp == 8) { int stride = w; byte[] pixels = new byte[h * stride]; src.CopyPixels(pixels, stride, 0); for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { p[step * y + x] = pixels[y * stride + x]; } } }*/ // 24bpp, 32bpp, ... else { int stride = w * ((bpp + 7) / 8); long imageSize = dst.DataEnd.ToInt64() - dst.DataStart.ToInt64(); if (imageSize < 0) throw new OpenCvSharpException("The mat has invalid data pointer"); if (imageSize > Int32.MaxValue) throw new OpenCvSharpException("Too big mat data"); src.CopyPixels(Int32Rect.Empty, dst.Data, (int)imageSize, stride); } } }
/// <summary> /// MatをWriteableBitmapに変換する. /// 返却値を新たに生成せず引数で指定したWriteableBitmapに格納するので、メモリ効率が良い。 /// </summary> /// <param name="src">変換するMat</param> /// <param name="dst">変換結果を設定するWriteableBitmap</param> #else /// <summary> /// Converts Mat to WriteableBitmap. /// This method is more efficient because new instance of WriteableBitmap is not allocated. /// </summary> /// <param name="src">Input Mat</param> /// <param name="dst">Output WriteableBitmap</param> #endif public static void ToWriteableBitmap(Mat src, WriteableBitmap dst) { if (src == null) throw new ArgumentNullException("src"); if (dst == null) throw new ArgumentNullException("dst"); if (src.Width != dst.PixelWidth || src.Height != dst.PixelHeight) throw new ArgumentException("size of src must be equal to size of dst"); //if (src.Depth != BitDepth.U8) //throw new ArgumentException("bit depth of src must be BitDepth.U8", "src"); if (src.Dims() > 2) throw new ArgumentException("Mat dimensions must be 2"); int w = src.Width; int h = src.Height; int bpp = dst.Format.BitsPerPixel; int channels = GetOptimumChannels(dst.Format); if (src.Channels() != channels) { throw new ArgumentException("channels of dst != channels of PixelFormat", "dst"); } if (bpp == 1) { unsafe { // 手作業で移し替える int stride = w / 8 + 1; if (stride < 2) { stride = 2; } byte[] pixels = new byte[h * stride]; byte* p = (byte*)(src.Data); int x = 0; long step = src.Step(); for (int y = 0; y < h; y++) { int offset = y * stride; for (int bytePos = 0; bytePos < stride; bytePos++) { if (x < w) { byte b = 0; // 現在の位置から横8ピクセル分、ビットがそれぞれ立っているか調べ、1つのbyteにまとめる for (int i = 0; i < 8; i++) { b <<= 1; if (x < w && p[step * y + x] != 0) { b |= 1; } x++; } pixels[offset + bytePos] = b; } } x = 0; } dst.WritePixels(new Int32Rect(0, 0, w, h), pixels, stride, 0); } } else { long imageSize = src.DataEnd.ToInt64() - src.DataStart.ToInt64(); if (imageSize < 0) throw new OpenCvSharpException("The mat has invalid data pointer"); if (imageSize > Int32.MaxValue) throw new OpenCvSharpException("Too big mat data"); dst.WritePixels(new Int32Rect(0, 0, w, h), src.Data, (int)imageSize, (int)src.Step()); } }
/// <summary> /// MatをWriteableBitmapに変換する. /// 返却値を新たに生成せず引数で指定したWriteableBitmapに格納するので、メモリ効率が良い。 /// </summary> /// <param name="src">変換するMat</param> /// <param name="dst">変換結果を設定するWriteableBitmap</param> #else /// <summary> /// Converts Mat to WriteableBitmap. /// This method is more efficient because new instance of WriteableBitmap is not allocated. /// </summary> /// <param name="src">Input Mat</param> /// <param name="dst">Output WriteableBitmap</param> #endif public static void ToWriteableBitmap(Mat src, WriteableBitmap dst) { if (src == null) throw new ArgumentNullException("src"); if (dst == null) throw new ArgumentNullException("dst"); if (src.Width != dst.PixelWidth || src.Height != dst.PixelHeight) throw new ArgumentException("size of src must be equal to size of dst"); //if (src.Depth != BitDepth.U8) //throw new ArgumentException("bit depth of src must be BitDepth.U8", "src"); if (src.Dims() > 2) throw new ArgumentException("Mat dimensions must be 2"); int w = src.Width; int h = src.Height; int bpp = dst.Format.BitsPerPixel; int channels = GetOptimumChannels(dst.Format); if (src.Channels() != channels) { throw new ArgumentException("channels of dst != channels of PixelFormat", "dst"); } bool submat = src.IsSubmatrix(); bool continuous = src.IsContinuous(); unsafe { byte* pSrc = (byte*)(src.Data); int sstep = (int)src.Step(); if (bpp == 1) { if (submat) throw new NotImplementedException("submatrix not supported"); // 手作業で移し替える int stride = w / 8 + 1; if (stride < 2) stride = 2; byte[] pixels = new byte[h * stride]; for (int x = 0, y = 0; y < h; y++) { int offset = y * stride; for (int bytePos = 0; bytePos < stride; bytePos++) { if (x < w) { byte b = 0; // 現在の位置から横8ピクセル分、ビットがそれぞれ立っているか調べ、1つのbyteにまとめる for (int i = 0; i < 8; i++) { b <<= 1; if (x < w && pSrc[sstep * y + x] != 0) { b |= 1; } x++; } pixels[offset + bytePos] = b; } } x = 0; } dst.WritePixels(new Int32Rect(0, 0, w, h), pixels, stride, 0); return; } // 一気にコピー if (!submat && continuous) { long imageSize = src.DataEnd.ToInt64() - src.Data.ToInt64(); if (imageSize < 0) throw new OpenCvSharpException("The mat has invalid data pointer"); if (imageSize > Int32.MaxValue) throw new OpenCvSharpException("Too big mat data"); dst.WritePixels(new Int32Rect(0, 0, w, h), src.Data, (int)imageSize, sstep); return; } // 一列ごとにコピー try { dst.Lock(); int dstep = dst.BackBufferStride; byte* pDst = (byte*)dst.BackBuffer; for (int y = 0; y < h; y++) { long offsetSrc = (y * sstep); long offsetDst = (y * dstep); Util.CopyMemory(pDst + offsetDst, pSrc + offsetSrc, w * channels); } } finally { dst.Unlock(); } } }