0

イメージを含む WPF ウィンドウに、USB カメラでキャプチャされたフレームを継続的に表示しようとしています。

私のコードでは、ViewModel はそのフィールドをパラメーターとしてCameraServiceClass渡すインスタンスを作成します。次に、イベントがトリガーされるとフィールドが設定されますが、イベントが発生して内部で処理されるため、プロパティの変更を通知する方法がわかりません。_framerefNewFrameCameraViewModel.Frame_camera_service

質問は次のとおりです。

  1. refこのようなパラメーターを使用する必要がありますか?
  2. CameraServiceClassにイベントを追加し、クラスでリッスンし、changed プロパティCameraViewModelを上げて処理するのは良い考えでしょうか? Frameはいの場合、どうすればよいですか?
  3. CameraServiceClassそれ自体がカスタム FrameReceived イベントを通知し、ビットマップ自体をイベント引数に渡す必要がありますか? はいの場合、どうすればよいですか?

私のクラスは次のとおりです。

<Window x:Class="CameraGUI.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:ap="clr-namespace:CameraGUI"
        Title="MainWindow" Height="350" Width="525">

    <Window.DataContext>
        <ap:CameraViewModel/>
    </Window.DataContext>

    <Grid>
        <Viewbox Stretch="Uniform">
            <Image Source="{Binding Frame, Mode=OneWay}" />     
        </Viewbox>
    </Grid>
</Window>

カメラ ビューモデル:

class CameraViewModel : ViewModelBase {

    System.Drawing.Bitmap _frame_camera;

    public System.Windows.Media.Imaging.BitmapImage Frame {
        get {
            if (_frame_camera != null) {
                using(MemoryStream ms = new MemoryStream())
                {
                    _frame_camera.Save(ms, ImageFormat.Bmp);
                    ms.Position = 0;
                    BitmapImage bitmapImage = new BitmapImage();
                    bitmapImage.BeginInit();
                    bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
                    bitmapImage.StreamSource = ms;
                    bitmapImage.EndInit();

                    bitmapImage.Freeze();

                    return bitmapImage;
                }
            } else return null;
        }
    }



    CameraServiceClass _camera_service;

    // CONSTRUTOR
    public CameraViewModel() {
        _camera_service = new CameraServiceClass(ref _frame_camera);         
    }
}

そして CameraServiceClass:

public class CameraServiceClass
{

    System.Drawing.Bitmap _frame;
    VideoCaptureDevice videoSource;

    // CONSTRUTOR
    public CameraServiceClass(ref System.Drawing.Bitmap bitmap) {
        _frame = bitmap;

        var videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
        videoSource = new VideoCaptureDevice(videoDevices[0].MonikerString);

        videoSource.NewFrame += new NewFrameEventHandler(video_NewFrame);

        videoSource.Start();
    }


    private void video_NewFrame (object sender, NewFrameEventArgs eventArgs) {
        System.Drawing.Bitmap bmp = (System.Drawing.Bitmap)eventArgs.Frame.Clone();
        _frame = bmp;
    }
}
4

3 に答える 3

0

MSDNの「方法: クラスにイベントを実装する」チュートリアルに従い、2 番目の手順 (カスタム データを使用してイベントを実装する) に従って、これが機能するようになりました。

原則は、データを含むカスタム EventArgs を作成し、適切なハンドラー (デリゲート) も作成することでした。これまでイベント、デリゲート、ハンドラーを扱ったことがなかったので、ここで物事が進まなかった理由の 1 つがそれでした...

別の方法としては、Peter Davidsen の提案を使用して、サービス クラスにパブリック プロパティを持ち、リスナーにそれ自体を取得させることもできますが、この詳細は好みの問題だと思います (おそらく、最初の手順を使用すると実装が簡単になります)。リンクされた MSDN チュートリアル)。

新しい作業コード:

MainWindow.xaml (コード ビハインドに valueconverter が追加されました (表示されていません)):

<Window x:Class="CameraGUI.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:ap="clr-namespace:CameraGUI"
        Title="MainWindow" Height="350" Width="525">

    <Window.DataContext>
        <ap:CameraViewModel/>
    </Window.DataContext>

    <Window.Resources>
        <ap:BitmapToSource x:Key="BitmapToSource"/>
    </Window.Resources>

    <Grid>
        <Viewbox Stretch="Uniform">
            <Image Source="{Binding Frame, Mode=OneWay, Converter={StaticResource BitmapToSource}}" />     
        </Viewbox>
    </Grid>
</Window>

CameraService.cs ファイル (デリゲート、ハンドラー、およびカスタム "EventArgs" クラスを含む)

public class CameraServiceClass
{

    VideoCaptureDevice videoSource;

    // CONSTRUTOR
    public void Start() {

        var videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
        videoSource = new VideoCaptureDevice(videoDevices[0].MonikerString);

        videoSource.NewFrame += new NewFrameEventHandler(video_NewFrame);

        videoSource.Start();
    }


    private void video_NewFrame (object sender, NewFrameEventArgs eventArgs) {
        System.Drawing.Bitmap bmp = (System.Drawing.Bitmap)eventArgs.Frame.Clone();
        OnNovoFrame(new NovoFrameArgs(bmp));
    }


    public event NovoFrameEventHandler NovoFrame;

    protected void OnNovoFrame(NovoFrameArgs e) {
        if (NovoFrame != null)
            NovoFrame(this, e);
    }
}

public delegate void NovoFrameEventHandler(object sender, NovoFrameArgs e);

public class NovoFrameArgs : EventArgs {

    System.Drawing.Bitmap _frame;

    public NovoFrameArgs(System.Drawing.Bitmap fr) {
        this._frame = fr;
    }

    public System.Drawing.Bitmap Frame {
        get { return _frame; }
        set { _frame = value; }
    }
}

ビューモデル:

class CameraViewModel : ViewModelBase {

    CameraServiceClass _camera_service;

    public System.Drawing.Bitmap Frame {
        get { return _frame; }
        set {
            _frame = value;
            RaisePropertyChanged(() => Frame);
        }
    }
    System.Drawing.Bitmap _frame;


    // CONSTRUTOR
    public CameraViewModel() {
        _camera_service = new CameraServiceClass();
        _camera_service.NovoFrame += new NovoFrameEventHandler(_camera_service_NovoFrame);
        _camera_service.Start();          
    }

    void _camera_service_NovoFrame(object sender, NovoFrameArgs e) {
        Frame = e.Frame;
    }

}
于 2013-10-24T18:52:30.953 に答える