【WPF+OpenCV(C++)】バインディングで画像表示をしてみる(1)
はじめに
今回から二回に分けてVisual Studio 2019でC# WPFアプリの画面上にOpenCVで生成した画像を表示させてみようと思います。
最終的に画像を2ファイル指定すると1つ目の画像の上に透明な画像を重ねた画像をOpenCVで生成させて、それをC# WPFアプリ上で表示させるようにしたいと思います!
それぞれ以下の予定としています。
- C# WPFアプリでバインディングの仕組みを利用して画像ファイルから読み込んだ画像を表示する ※【今回】※
- ウィンドウサイズが変わると連動して画像サイズも変わるようにする ※【今回】※
- C# WPFアプリでバインディングの仕組みを利用してメニューから特定のActionを実行する
- OpenCV Wrapperプロジェクト(C++/CLI)でベース画像の上に透明な別画像を重ねた画像データ(Overlay画像)をC# WPFアプリで表示する
今回はWPFアプリのバインディングを使用して固定ファイルの画像表示とウィンドウサイズ変更すると、表示している画像サイズも連動して縮小拡大を行うようにしてみようと思います。
環境
以下をすべて用意していることを前提とします。
- Visual Studio Community 2019
.NETデスクトップ開発とC++によるデスクトップ開発の機能を使用します。
もし、インストール時にこれらの機能を入れていなければVisual Studio InstallerからVisual Studio Community 2019の変更でこれらの機能をインストールしておいて下さい。
1. C# WPFアプリでバインディングの仕組みを利用して画像ファイルから読み込んだ画像を表示する
プロジェクト名はWpfShowImageにします。
フレームワークは「.NET Framework 4.7.2」にします。
次にXAMLファイル(ウィンドウをどう表示させるかの制御ファイル)を編集します。
MainWindow.xamlを以下のように編集しましょう。
<Window x:Class="WpfShowImage.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfShowImage" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Grid> <Image Source="{Binding Img}" Height="450" Width="800" /> </Grid> </Window>
次にBindingするため、ViewModelを用意します。
ViewModel.csを新規作成し、以下のように編集します。
using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; using System.Windows.Media.Imaging; namespace WpfShowImage { class ViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged([CallerMemberName] String propertyName = "") { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } private WriteableBitmap img; public WriteableBitmap Img { get { return img; } set { img = value; NotifyPropertyChanged(); } } } }
次にMainWindow.xaml.csを以下のように編集しましょう。
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace WpfShowImage { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { private ViewModel vm; public MainWindow() { InitializeComponent(); vm = new ViewModel(); DataContext = vm; using (var ms = new MemoryStream(File.ReadAllBytes("baseImage.jpg"))) { vm.Img = new WriteableBitmap(BitmapFrame.Create(ms)); ms.Close(); } } } }
実行すると以下の画面のように読み込んだ画像ファイルの画像を表示してくれましたね^^
2. ウィンドウサイズが変わると連動して画像サイズも変わるようにする
このままだと、ImageのWidthとHeightが固定なのでウィンドウサイズを変えても連動してサイズが変わってくれません
ウィンドウサイズを大きくしてもこんな風に画像は固定サイズのまま余白ができたり、
ウィンドウサイズを小さくしてもこんな風に画像の一部だけ表示されちゃいます。
ウィンドウサイズが変わると連動して画像サイズも変わるようにしましょう。
MainWindow.xamlのImageのHeightとWidthを以下のように修正します。
<Image ・ ・ ・ Height="{Binding ImgHeight}" Width="{Binding ImgWidth}" />
ViewModelにBindするプロパティを追加するべくViewModel.csに以下のコードを追加します。
private double imgHeight; public double ImgHeight { get { return imgHeight; } set { imgHeight = value; NotifyPropertyChanged(); } } private double imgWidth; public double ImgWidth { get { return imgWidth; } set { imgWidth = value; NotifyPropertyChanged(); } }
ウィンドウサイズを変更したときに連動させるにはウィンドウサイズの変更時にImgWidthとImgHeightの変更を行わせるようにします。
MainWindow.xamlのWindowにSizeChangedを追加します。
<Window x:Class="WpfShowImage.MainWindow" ・ ・ ・ Title="MainWindow" Height="450" Width="800" SizeChanged="Window_SizeChanged">
Window_SizeChangedの処理を実装します。
MainWindow.xaml.csに以下のコードを追加します。
private void Window_SizeChanged(object sender, SizeChangedEventArgs e) { FrameworkElement frameworkElement = Content as FrameworkElement; vm.ImgHeight = frameworkElement.ActualHeight; vm.ImgWidth = frameworkElement.ActualWidth; }
それでは実行してみましょう。
これでウィンドウサイズを小さくしても画像が縮小され全部表示されるようになりました^^
ImageのStretchはデフォルトで"Uniform"なのでアスペクト比は維持したまま画像の縮小拡大を行います。
おわりに
今回はWPFアプリのバインディングを使用して固定ファイルの画像表示とウィンドウサイズ変更すると、表示している画像サイズも連動して縮小拡大を行うようにしてみました。
次回は固定ファイルではなくファイルを選択させて画像を切り替えられるようにしてOpenCV Wrapperプロジェクト(C++/CLI)で生成した画像を表示させてみるということをしてみようと思います。
madai21.hatenablog.com