123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252 |
- #if WINDOWS && (NET48 || NETCOREAPP3_1_OR_GREATER)
- using System.Drawing;
- using System.Drawing.Imaging;
- using System.IO;
- using System.Windows;
- using System.Windows.Media.Imaging;
- using System.Windows.Threading;
- using PixelFormat = System.Windows.Media.PixelFormat;
- namespace OpenCvSharp.WpfExtensions;
- /// <summary>
- /// Static class which provides conversion between System.Windows.Media.Imaging.BitmapSource and IplImage
- /// </summary>
- public static class BitmapSourceConverter
- {
- /// <summary>
- /// Converts Mat to BitmapSource.
- /// </summary>
- /// <param name="src">Input IplImage</param>
- /// <returns>BitmapSource</returns>
- public static BitmapSource ToBitmapSource(
- this Mat src) =>
- src.ToWriteableBitmap();
- /// <summary>
- /// Converts Mat to BitmapSource.
- /// </summary>
- /// <param name="src">Input IplImage</param>
- /// <param name="horizontalResolution"></param>
- /// <param name="verticalResolution"></param>
- /// <param name="pixelFormat"></param>
- /// <param name="palette"></param>
- /// <returns>BitmapSource</returns>
- public static BitmapSource ToBitmapSource(
- this Mat src,
- int horizontalResolution,
- int verticalResolution,
- PixelFormat pixelFormat,
- BitmapPalette palette) =>
- src.ToWriteableBitmap(horizontalResolution, verticalResolution, pixelFormat, palette);
- /// <summary>
- /// Converts System.Drawing.Bitmap to BitmapSource.
- /// </summary>
- /// <param name="src">Input System.Drawing.Bitmap</param>
- /// <remarks>http://www.codeproject.com/Articles/104929/Bitmap-to-BitmapSource</remarks>
- /// <returns>BitmapSource</returns>
- public static BitmapSource ToBitmapSource(this Bitmap src)
- {
- if (src is null)
- throw new ArgumentNullException(nameof(src));
- if (Application.Current?.Dispatcher is null)
- {
- using var memoryStream = new MemoryStream();
- src.Save(memoryStream, ImageFormat.Png);
- return CreateBitmapSourceFromBitmap(memoryStream);
- }
- using (var memoryStream = new MemoryStream())
- {
- // You need to specify the image format to fill the stream.
- // I'm assuming it is PNG
- src.Save(memoryStream, ImageFormat.Png);
- memoryStream.Seek(0, SeekOrigin.Begin);
- // Make sure to create the bitmap in the UI thread
- if (IsInvokeRequired())
- return (BitmapSource) Application.Current.Dispatcher.Invoke(
- new Func<Stream, BitmapSource>(CreateBitmapSourceFromBitmap),
- DispatcherPriority.Normal,
- memoryStream);
- return CreateBitmapSourceFromBitmap(memoryStream);
- }
- }
- // http://www.codeproject.com/Articles/104929/Bitmap-to-BitmapSource
- private static bool IsInvokeRequired()
- => Dispatcher.CurrentDispatcher != Application.Current.Dispatcher;
- // http://www.codeproject.com/Articles/104929/Bitmap-to-BitmapSource
- private static BitmapSource CreateBitmapSourceFromBitmap(Stream stream)
- {
- var bitmapDecoder = BitmapDecoder.Create(
- stream,
- BitmapCreateOptions.PreservePixelFormat,
- BitmapCacheOption.OnLoad);
- // This will disconnect the stream from the image completely...
- var writable = new WriteableBitmap(bitmapDecoder.Frames.Single());
- writable.Freeze();
- return writable;
- }
- #region ToMat
- /// <summary>
- /// Converts BitmapSource to Mat
- /// </summary>
- /// <param name="src">Input BitmapSource</param>
- /// <returns>IplImage</returns>
- public static Mat ToMat(this BitmapSource src)
- {
- if (src is null)
- {
- throw new ArgumentNullException(nameof(src));
- }
- int w = src.PixelWidth;
- int h = src.PixelHeight;
- MatType type = WriteableBitmapConverter.GetOptimumType(src.Format);
- Mat dst = new Mat(h, w, type);
- ToMat(src, dst);
- return dst;
- }
- /// <summary>
- /// Converts BitmapSource to Mat
- /// </summary>
- /// <param name="src">Input BitmapSource</param>
- /// <param name="dst">Output Mat</param>
- public static void ToMat(this BitmapSource src, Mat dst)
- {
- if (src is null)
- throw new ArgumentNullException(nameof(src));
- if (dst is null)
- throw new ArgumentNullException(nameof(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 = WriteableBitmapConverter.GetOptimumChannels(src.Format);
- if (dst.Channels() != channels)
- {
- throw new ArgumentException("nChannels of dst is invalid", nameof(dst));
- }
- bool submat = dst.IsSubmatrix();
- bool continuous = dst.IsContinuous();
- unsafe
- {
- byte* p = (byte*)(dst.Data);
- long step = dst.Step();
- // 1bppは手作業でコピー
- if (bpp == 1)
- {
- if (submat)
- throw new NotImplementedException("submatrix not supported");
- // 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);
- if (!submat && continuous)
- {
- long imageSize = dst.DataEnd.ToInt64() - dst.Data.ToInt64();
- if (imageSize < 0)
- throw new OpenCvSharpException("The mat has invalid data pointer");
- if (imageSize > int.MaxValue)
- throw new OpenCvSharpException("Too big mat data");
- src.CopyPixels(Int32Rect.Empty, dst.Data, (int)imageSize, stride);
- }
- else
- {
- // 高さ1pxの矩形ごと(≒1行ごと)にコピー
- var roi = new Int32Rect { X = 0, Y = 0, Width = w, Height = 1 };
- IntPtr dstData = dst.Data;
- for (int y = 0; y < h; y++)
- {
- roi.Y = y;
- src.CopyPixels(roi, dstData, stride, stride);
- dstData = new IntPtr(dstData.ToInt64() + stride);
- }
- }
- }
- }
- }
- /// <summary>
- /// Copies pixel data from System.Windows.Media.Imaging.BitmapSource to IplImage instance
- /// </summary>
- /// <param name="mat"></param>
- /// <param name="wb"></param>
- /// <returns></returns>
- public static void CopyFrom(this Mat mat, BitmapSource wb)
- {
- if (wb is null)
- throw new ArgumentNullException(nameof(wb));
- ToMat(wb, mat);
- }
- #endregion
- }
- #endif
|