Захват камеры в Emgu проект на WPF

356
22 сентября 2017, 16:58

Пробую Emgu. А именно захват видео с веб камеры. Приложение на Windows Forms нормально работает. Решил перейти на WPF и столкнулся с тем, что там нет контрола ImageBox. Я сделал через Windowsformshost. Все работает. Но я бы хотел использовать родной контрол Image. И тут у меня не получается, картинки нет. Разметка:

<Image Name="imageBox" Height="500" Width="500"/>
<Button x:Name="captureButton" Content="Start" Click="captureButton_Click" 
          Margin="33,36,25,473" FontFamily="Arial" Grid.Column="1" 
          Width="60" Height="60"/>

MainWindow.xaml.cs:

 public partial class MainWindow : Window
{
    private VideoCapture _capture = null;
    private bool _captureInProgress;
    private Mat _frame;
    public MainWindow()
    {
        InitializeComponent();
        // Инит EMGUU 
        CvInvoke.UseOpenCL = false;
        try
        {
            _capture = new VideoCapture();
            // Подписываемся на событие
            _capture.ImageGrabbed += ProcessFrame;
        }
        catch (NullReferenceException excpt)
        {
            MessageBox.Show(excpt.Message);
        }

        _frame = new Mat();
    }
    private void ProcessFrame(object sender, EventArgs arg)
    {
        if (_capture != null && _capture.Ptr != IntPtr.Zero)
        {
            _capture.Retrieve(_frame, 0);
            var temp = _frame.ToImage<Bgr, byte>().Bitmap;
            using (Image<Bgr, byte> frame = _capture.QueryFrame().ToImage<Bgr, Byte>())
            {
                //Вот тут что-то не то =((((
                imageBox.Source = BitmapSourceConvert.ToBitmapSource(frame);
                //  imageBox.Source = BitmapSourceConvert.ToBitmapSource(temp as Image);
            }
        }
    }
    private void captureButton_Click(object sender, RoutedEventArgs e)
    {
        if (_capture != null)
        {
            if (_captureInProgress)
            {  //stop the capture
                captureButton.Content = "Start Capture";
                _capture.Pause();
            }
            else
            {
                //start the capture
                captureButton.Content = "Stop";
                _capture.Start();
            }
            _captureInProgress = !_captureInProgress;
        }
    }
    private void ReleaseData()
    {
        if (_capture != null)
            _capture.Dispose();
    }

}

Класс конвертер

 public static class BitmapSourceConvert
{
    [DllImport("gdi32")]
    private static extern int DeleteObject(IntPtr o);
    public static BitmapSource ToBitmapSource(IImage image)
    {
        using (System.Drawing.Bitmap source = image.Bitmap)
        {
            IntPtr ptr = source.GetHbitmap();
            BitmapSource bs = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                ptr,
                IntPtr.Zero,
                Int32Rect.Empty,
                System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
            DeleteObject(ptr);
            return bs;
        }
    }
}

В общем приложение компилируется, запускается, зажигается индикатор на веб камере, а изображения нет.

ПС: Если использовать

<WindowsFormsHost Width="550px" Height="550px" HorizontalAlignment="Left" VerticalAlignment="Top">
                        <emui:ImageBox x:Name="imageBox"></emui:ImageBox>
                    </WindowsFormsHost>

И в MainWindow.xaml.cs писать в контрол, подтянутый из WinForms:

 imageBox.Image = _frame;

Все работает.

Answer 1

Сделал рабочий тестовый проект, обработчик у меня получился следующего вида:

  private void ProcessFrame(object sender, EventArgs arg)
    {
        if (System.Threading.Monitor.TryEnter(lockObj))
        {
            if (_capture != null && _capture.Ptr != IntPtr.Zero)
            {
                Dispatcher.BeginInvoke(new Action(() =>
                {
                    using (Image<Bgr, byte> emguFrame = _capture.QueryFrame().ToImage<Bgr, Byte>())
                    {
                        imageBox.Source = Convert(emguFrame.Bitmap);
                    }
                }));
            }
            System.Threading.Thread.Sleep(50);
            System.Threading.Monitor.Exit(lockObj);
        }
    }

Код конвертации Bitmap в BitmapSource:

 public BitmapSource Convert(System.Drawing.Bitmap bitmap)
    {
        var bitmapData = bitmap.LockBits(
            new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height),
            System.Drawing.Imaging.ImageLockMode.ReadOnly, bitmap.PixelFormat);
        PixelFormatConverter convert = new PixelFormatConverter();
        var bitmapSource = BitmapSource.Create(
            bitmapData.Width, bitmapData.Height, 96, 96, ConvertPixelFormat(bitmap.PixelFormat), null,
            bitmapData.Scan0, bitmapData.Stride * bitmapData.Height, bitmapData.Stride);
        bitmap.UnlockBits(bitmapData);
        return bitmapSource;
    }
    private static System.Windows.Media.PixelFormat ConvertPixelFormat(System.Drawing.Imaging.PixelFormat sourceFormat)
    {
        switch (sourceFormat)
        {
            case System.Drawing.Imaging.PixelFormat.Format24bppRgb:
                return PixelFormats.Bgr24;
            case System.Drawing.Imaging.PixelFormat.Format32bppArgb:
                return PixelFormats.Bgra32;
            case System.Drawing.Imaging.PixelFormat.Format32bppRgb:
                return PixelFormats.Bgr32;
            case System.Drawing.Imaging.PixelFormat.Format16bppGrayScale:
                return PixelFormats.Gray16;
            default:
                return PixelFormats.Bgr24;
        }
    }

P.S. Возможно Вам пригодится. Я в своем проекте делал захват видео с помощью Accord Framework .NET ссылка, отображение делал на WPF при помощи Image контрола и класса WritableBitmap. Небольшая модификация кода Accord Framework .NET, позволила получить не Bitmap, а указатель на массив байт, который с дополнительными параметрами передавал методу WritePixels объекта класса WriteablreBitmap, это работало быстрее и избавляло от необходимости конвертации Bitmap.

READ ALSO
Создание файла c#

Создание файла c#

Есть проблемаСоздаю файл

316
Unity3d - Управление персонажем с помощью touch (C#)

Unity3d - Управление персонажем с помощью touch (C#)

Подскажите пожалуйста каким способом можно сделать управление выбранным персонажем (например кораблем в космосе), через touch (без использования...

272
c# await class.methodAsync1().methodAsync2()

c# await class.methodAsync1().methodAsync2()

Возможно ли использовать асинхронные методы в цепочке?

172
С#Afforge VideoPlayer проигрывание картинки

С#Afforge VideoPlayer проигрывание картинки

Можно ли используя Afforge проигрывать в его плеере одну картинку, взятую из jpeg-файла без формирования видеофайлов с помощью класса VideoFileWriter...

208