F#でWPF --- OpenCV連携

下記記事にてOpenCVを.netから利用できるようC++/CLIでラップする方法を紹介しました。
OpenCVをC++/CLIでラップ - 何でもプログラミング

今回はWPFと連携させて画像を表示してみたいと思います。

作成するアプリケーション

ファイルダイアログで画像を選び、表示するアプリケーションを作成します。折角なのでエッジ化した画像も表示してみます。

f:id:any-programming:20170304182456p:plain

Canny追加

C++/CLI側のコードは上記記事のものを利用します。

追加してCanny関数を定義します。

[ExtensionAttribute]
static Mat8UC1^ Canny(Mat8UC1^ src, double threshold1, double threshold2)
{
    auto dst = gcnew Mat8UC1(src->Cols, src->Rows);
    cv::Canny(*src->_mat, *dst->_mat, threshold1, threshold2);
    return dst;
}


アプリケーションコード

WPFのImageコントロールはImageSourceクラスを受け取ります。

そのため、BitmapSource.Createを利用してMat8UC1クラスからBitmapSourceを作成しています。

Xaml内のOpenFileDialogActionは下記記事を参照してください。
F#でWPF --- ファイルダイアログCommand - 何でもプログラミング

F#内のDataContextは下記記事を参照してください。
F#でWPF --- Elm Architectureを利用したMVVM - 何でもプログラミング

Xaml

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 
        xmlns:local="clr-namespace:Actions;assembly=OpenCVSample"
        Title="MainWindow" Height="250" Width="400">
    <Grid>
        <Button Content="画像を開く" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="100">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <local:OpenFileDialogAction Command="{Binding LoadImage}" />
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>
        <UniformGrid Margin="10,40,10,10" Columns="2">
            <Image Source="{Binding SrcImage}" />
            <Image Source="{Binding DstImage}" />
        </UniformGrid>
    </Grid>
</Window>

F#

open System
open System.Windows
open System.Windows.Media
open System.Windows.Media.Imaging
open CV

type Model = 
    { SrcImage : BitmapSource 
      DstImage : BitmapSource }

let initialModel = 
    { SrcImage = null 
      DstImage = null }

type Msg = LoadImage of string

let updateModel model msg =
    match msg with
    | LoadImage x -> 
        let mat = Processor.Load(x)
        let toBitmapSource (x : Mat8UC1) = 
            BitmapSource.Create(x.Cols, x.Rows, 96.0, 96.0, PixelFormats.Gray8, null, x.Data, x.Cols * x.Rows, x.Cols)
        { model with SrcImage = toBitmapSource mat
                     DstImage = toBitmapSource <| mat.Canny(50.0, 200.0) }

[<STAThread>]
[<EntryPoint>]
let main argv = 
    let window = Application.LoadComponent(Uri("MainWindow.xaml", UriKind.Relative)) :?> Window
    window.DataContext <- DataContext(initialModel, updateModel, id)
    Application().Run(window) |> ignore   
    0