Deep Insider の Tutor コーナー
>>  Deep Insider は本サイトからスピンオフした姉妹サイトです。よろしく! 
Leap Motion実用サンプル(Visual Basic編)

Leap Motion実用サンプル(Visual Basic編)

オブジェクト(Button)をLeap Motionでタッチして背景色を変化させる

2013年8月28日

Leap Motionの動くサンプルを実際に作ってみる連載スタート。今回はLeap Motionのタッチ操作で背景色を変化させるWPFアプリをVBで開発する。

  • このエントリーをはてなブックマークに追加

はじめに

 この連載は、Leap Motionの現物を持っている方が対象だ。しかし、Leap Motionの現物を持っていなくても、この連載で、Leap Motionを使うと、どのようなことができるのかの参考にはなるだろうと思う。この連載で、Leap Motionに興味を持たれた方は、購入を考えてみられたらいかがだろうか。直販で、1万5百円で入手できる。決して高い買い物ではないだろう(「Buy the Leap Motion Controller」で購入できる)。

Leap Motionを使う前に

 実際にサンプルを作って動かす前に、「環境構築」と言うほどでもないが、「Get started with yourLeap Motion Controller.」から、[Windows Download]ボタンをクリックして、「Leap_Motion_Installer_release_public_win_x86_1.0.7+7648_ah744.exe」ファイルをダウンロードして、Leap Motionの実行環境をインストールしておく必要がある。インストールが完了すると、Leap Motionを接続可能になる。

 次に、「Leap Motion Developer SDK」のページから[v.1.0.8.7665 for Windows](次の画面を参照)を任意のフォルダーにダウンロードして、解凍しておいてほしい*1。この解説はWindowsをメインとするので、Windows版をダウンロードする。

  • *1Leap Motionはしきりにバージョンアップを繰り返しているので、上記のURLに入って時々Leap Motionのバージョンをチェックして、バージョンアップされている場合は、最新のファイルをダウンロードしてほしい。また、更新の連絡も来るので、そのときは更新してほしい。この記事が掲載されるころには、また新しいバージョンになっている可能性もある。その点をご了承願いたい。
[v.1.0.8.7665 for Windows]ボタンをクリックしてダウンロードする

 任意のフォルダーに解凍すると、「<解凍したフォルダー>\LeapDeveloperKit\LeapSDK\lib」フォルダー内に「LeapCSharp.NET4.0.dll」ファイルが展開されている。このDLLファイルへの参照を、Visual Studio 2012(以下、VS 2012)の[参照の追加]で追加する必要がある。

 また、先ほどのlibフォルダーの中にあるx86フォルダー内には、「LeapCSharp.dll」と「Leap.dll」というファイルが存在している。これら2つのDLLファイルを、[ソリューション エクスプローラー]でプロジェクトのルートに追加して、[プロパティ]ウィンドウで「常にコピーする」と指定しておく。VS 2012のメニューバーから[ビルド]-[構成マネージャ]と選択して、[アクティブ ソリューション プラットホーム]が「Any CPU」または「x86」の場合は、x86フォルダー内のDLLファイル、「x64」ならx64フォルダー内のDLLファイルを選択する必要がある。これを間違わないでほしい。筆者の環境では[構成マネージャ]が「Any CPU」になっているので、x86フォルダー内のファイルを指定している。各自の[構成マネージャ]の値に対応して読み込むフォルダーを指定してほしい。

 これらの参照設定の手順については、実際のサンプル作成時に、必要に応じて解説していく予定だ。

まずWPFプロジェクトを作成しよう

 Leap MotionのアプリはWPFで作成する。VS 2012のIDEを起動して、メニューバーから[ファイル]-[新規作成]-[プロジェクト]と選択して、その後に表示される[新しいプロジェクト]ダイアログで「Visual Basic」の「WPF アプリケーション」テンプレートを選択する(Leap Motionは.NET Framework 3.5と4.0に対応している。しかし、.NET Framework 4.5でも動作する。今回のアプリは全て.NET Framework 4.5で作成している。しかし、あくまでも対応しているのは、.NET Framework 3.5と4.0だ。心配な方は、.NET Framework 4.0で作成すると安心だろう)。[名前]欄には、今回は「ChangeBackgroundLeapMotion」と指定する。

参照の追加

 プロジェクトが作成されたら、[ソリューション エクスプローラー]の上部にある[すべてのファイルを表示]アイコンをクリックして、[参照設定]を表示させる。その[参照設定]の右クリック・メニューで[参照の追加]を選択する。次の画面が表示されるので、「最近使用したファイル」内に、「LeapCSharp.NET4.0.dll」が見当たらない場合は、[参照]ボタンから、「<解凍したフォルダー>\LeapDeveloperKit\LeapSDK\lib」フォルダー内の「LeapCSharp.NET4.0.dll」ファイルを指定して[OK]ボタンをクリックする。

[参照]ボタンをクリックして「LeapCSharp.NET4.0.dll」を指定する

プロジェクトのルートに「LeapCSharp.dll」と「Leap.dll」を追加する

 [ソリューション エクスプローラー]内のプロジェクト項目の右クリック・メニューから[追加]-[既存の項目]を選択して(次の画面)、「<解凍したフォルダー>\LeapDeveloperKit\LeapSDK\lib\x86」フォルダー内の「LeapCSharp.dll」と「Leap.dll」の2つのファイルを追加する。

[ソリューション エクスプローラー]内のプロジェクト項目の右クリック・メニューから[追加]-[既存の項目]を選択

 [ソリューション エクスプローラー]内に次の画面のように「LeapCSharp.dll」と「Leap.dll」が追加される。

[ソリューション エクスプローラー]内に「LeapCSharp.dll」と「Leap.dll」が追加された

プロパティを設定する

 「LeapCSharp.dll」と「Leap.dll」のプロパティから、[出力ディレクトリーにコピー]を「常にコピー」するに変更しておく。これは、2つのDLLファイル共にしておく必要がある(次の画面を参照)。

「LeapCSharp.dll」と「Leap.dll」のプロパティを「常にコピーする」にしておく
「LeapCSharp.dll」と「Leap.dll」のプロパティを「常にコピーする」にしておく

今回のLeap Motionアプリについて

 今回のアプリは、画面上に配置したボタンを、Leap Motionで作成した円(=タッチ・ポイント)でタップすることで、画面の背景色を、ボタンの表面に書かれている文字の背景色に変化させるものだ(次の画面を参照)。

Leap Motionでタップした背景色に変わった

 ボタン上に黒い円(=「●」のような塗りつぶされた丸)を乗せ、画面を突くような動作をすると、円が赤に変化する(=タッチ状態になる)。すると背景色が変化する。円が黒のままでは、タッチした動作にはならないので、背景色は変化しないので注意してほしい。5本の指をかざして、5個の円の色を赤にすると、デフォルトの白の背景色に戻る。

画面のレイアウト(MainWindow.xaml)

 デフォルトでGridコントロールが配置されているのをCanvasコントロールに変更する。その理由は、座標値が取得しやすいからだ。

 XAMLデザイナー画面上に、先ほどのCanvasコントロール上に、さらに「ShowArea」という名前のCanvasコントロールを配置し、その子要素として5つのButtonコントロールを配置する。Buttonコントロールの名前には、左から順に「redButton」「blueButton」「greenButton」「yellowButton」「blackButton」としておく。

 また、Leap Motionのタッチ・ポイントを表示させるために、「paintCanvas」という名前のInkPresenterコントロールをルートのCanvasコントロール上に配置する。このInkPresenterコントロールは、どのコントロールよりも一番手前に配置しておく必要がある。最終的なレイアウトは次のようになる。

各コントロールをレイアウトした結果

Buttonコントロールは「ShowArea」というCanvasコントロールの子要素として配置している。
全てのコントロールの一番前面にpaintCanvas」という名前のInkPresenterコントロールを配置する。この領域にタッチポイントが表示される。

 XAMLデザイナーで上記のレイアウトを行うと、書き出されるXAMLコードはリスト1のようになる。

XAML
<Window x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="1080" Width="1920" WindowState="Maximized">
  <Canvas>
    <Canvas x:Name="ShowArea" Width="1920" Height="1080">
      <Button x:Name="redButton" Content="赤" Height="80" Canvas.Left="59" Canvas.Top="49" Width="131" FontSize="36" FontWeight="Bold" Foreground="Red"/>
      <Button x:Name="blueButton" Content="青" Height="80" Canvas.Left="212" Canvas.Top="49" Width="131" FontSize="36" FontWeight="Bold" Foreground="Blue"/>
      <Button x:Name="greenButton" Content="緑" Height="80" Canvas.Left="368" Canvas.Top="49" Width="131" FontSize="36" FontWeight="Bold" Foreground="Green"/>
      <Button x:Name="yellowButton" Content="黄" Height="80" Canvas.Left="525" Canvas.Top="49" Width="131" FontSize="36" FontWeight="Bold" Foreground="Yellow"/>
      <Button x:Name="blackButton" Content="黒" Height="80" Canvas.Left="677" Canvas.Top="49" Width="131" FontSize="36" FontWeight="Bold" Foreground="Black"/>
    </Canvas>
    <TextBlock x:Name="TextBlock1" Height="63" Canvas.Left="284" TextWrapping="Wrap" Canvas.Top="341" Width="885" FontSize="48" FontWeight="Bold"/>
    <InkPresenter Name="paintCanvas"/>
  </Canvas>
</Window>
リスト1 書き出されたXAMLコード(MainWindows.xaml)

 Buttonコントロールを4個配置し、Contentプロパティに各色名を指定し、Foregroundプロパティに色名にあった色を指定している。

 ルートのCanvasコントロールの最後に<InkPresenter>要素が記載されているが、これによりInkPresenterコントロールが最前面に表示されるようになる。このInkPresenterコントロールをButtonコントロールよりも先に配置すると、表示されるタッチ・ポイントがButtonコントロールの背後に表示されてしまうので、注意してほしい。

プログラム・コード(MainWindow.xaml.vb)

 では、次にプログラム・コード(MainWindows.xaml.vbファイル)を見ていこう。

名前空間の読み込み

 まず、Leap Motionを扱うため、「Imports Leap」でLeap名前空間を読み込む。次に、インクの操作を行うクラスを提供するSystem.Windows.Ink名前空間を読み込む(次のリストを参照)。

Visual Basic
Imports Leap
Imports System.Windows.Ink
リスト2 名前空間の読み込み(MainWindow.xaml.vb)

メンバー変数の宣言

 次にメンバー変数を宣言する。

 新しいControllerクラスのインスタンスであるleapメンバー変数を宣言する。次に、インク・ストローク(=System.Windows.Ink名前空間のStrokeクラスで表現される、WPF上でのインクの線)の外観を指定するDrawingAttributesクラス(System.Windows.Ink名前空間)のインスタンスである「touchIndicatorメンバー変数」を宣言する。デジタイザーとスタイラスから収集された単一のデータ・ポイントを表すStylusPoint構造体の「touchPointメンバー変数」を宣言する。

 具体的には以下のようなコードになる。このコード例では、そのほかの必要なメンバー変数も宣言している。

Visual Basic
……省略……
Class MainWindow
  Private leap As New Controller
  Private touchIndicator As New DrawingAttributes
  Private touchPoint As StylusPoint

  Private windowWidth As Double = 1920
  Private windowHeight As Double = 1080
  Private x As Integer
  Private y As Integer
  Private tx As Double
  Private ty As Double

  Private FingersCount As Integer
  Private Message As String
  Private Index As Integer
End Class
リスト3 各種メンバー変数の宣言(MainWindow.xaml.vb)

MainWindow_Loadedメソッドの処理

 MainWindow_Loadedメソッド(=メイン・ウィンドウのLoadedイベントのハンドラー)では、MainWindowが読み込まれたときの処理を実装する。

 AddHandlerステートメントを使って、構成ツリーのオブジェクトがレンダリングされる直前に発生する「CompositionTarget.Renderingイベント」に対するイベント・ハンドラーとしてUpdateメソッドを指定する(Updateメソッドの実装内容は後述)。

 インク・ストロークの外観を表す、DrawingAttributesオブジェクトのインスタンス「touchIndicator」のWidthプロパティとHeightプロパティにそれぞれ「20」を指定する。スタイラスの形状を指定するStylusTipプロパティに「StylusTip.Ellipse」を指定して円形とする。Leap Motionの上で指をかざすと、かざした指の本数に応じて20px(px=ピクセル)の円が表示されるようになる。

 具体的には次のようなコードになる。

Visual Basic
Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
  AddHandler CompositionTarget.Rendering, AddressOf Update
  touchIndicator.Width = 20
  touchIndicator.Height = 20
  touchIndicator.StylusTip = StylusTip.Ellipse スタイラスの形状を20pxの円形に指定する
  TextBlock1.Foreground = New SolidColorBrush(Colors.White)
End Sub
リスト4 MainWindowが読み込まれたときの処理を行うMainWindow_Loadedメソッドの実装内容(MainWindow.xaml.vb)

Updateメソッドの処理

 次は、CompositionTarget.Renderingイベント・ハンドラーであるUpdateメソッドの処理だ。

 まず、上記のコードを実装した段階で、「Update」の位置に[エラー修正のオプション]というスマート・タグが表示されるので、そのタグのメニューから['ChangeBackgroundLeapMotion.MainWindow' に 'Update' のメソッド スタブを生成]をクリックすると、Updateメソッドのひな型が追加される。次に、そのメソッド内を実装していく。

 「paintCanvas」という名前のInkPresenter内をクリアする。この処理を行っていないと、Updateメソッドは常に呼び出されているため、円を画面上で動かすと、円の軌跡が残ったまま表示されてしまう。そのため、InkPresenter内をクリアする必要があるのだ。

 Leap Motionのフレームを表すFrame型(Leap名前空間)の変数「frame」を宣言する。InteractionBox型(Leap名前空間)の変数「interactionBox」を宣言し、そこにleap.Frame.InteractionBoxプロパティからInteractionBoxオブジェクトを取得する。InteractionBoxオブジェクトは、Leap Motionで認識できる稼働範囲となる。InteractionBoxオブジェクトを使用することで、指やツール(=ペンなど)の位置を実際のディスプレイの座標系に変換できる(次のリストを参照)。詳細な図については、「Leap Motionでのタッチ操作はどう開発するのか?」を参照してほしい。

 具体的なコードは次のとおり。

Visual Basic
Private Sub Update(sender As Object, e As EventArgs)
  paintCanvas.Strokes.Clear()
  windowWidth = Me.Width
  windowHeight = Me.Height

  Dim frame As Frame = leap.Frame

  ' Leap Motionで認識できる稼働範囲を取得する
  Dim interactionBox As InteractionBox = leap.Frame.InteractionBox
End Sub
リスト5 指やツールの位置を実際のディスプレイの座標系に変換する(MainWindow.xaml.vb)

 Leap.Frame.Pointablesプロパティで得られるPointableListオブジェクト内を変数「Pointable」で反復処理しながら、1つずつPointableオブジェクトを処理し、それぞれのタッチ位置を取得していく。

 interactionBoxオブジェクトのNormalizePointメソッドに引数としてPointable.StabilizedTipPositionプロパティ値を渡し、ポインター上の位置を取得する。

 変数「windowWidth」と「windowHeight」で表されたクライアント領域のウィンドウがある場合、以下のコードで示す計算式を使用してこのウィンドウ内のタッチ・ポイントの2D座標を得ることができる。

Visual Basic
Private Sub Update(sender As Object, e As EventArgs)
  ……コード略……

  For Each Pointable As Pointable In leap.Frame.Pointables
    Dim normalizedPosition As Leap.Vector = interactionBox.NormalizePoint(Pointable.StabilizedTipPosition)
    tx = normalizedPosition.x * windowWidth
    ty = windowHeight - normalizedPosition.y * windowHeight
    touchPoint = New StylusPoint(tx, ty)  ' ウィンドウ内のタッチ・ポイントの位置を取得する

  ……コード略(後述)……
  Next
End Sub
リスト6 ウィンドウ内のタッチ・ポイントの2D座標を得るコード(MainWindow.xaml.vb)

 さらに、上記のFor Eachステートメントの一番下に次のコードを追記して、ディスプレイ上に円形のタッチ・ポイントを表示する。

Visual Basic
For Each Pointable As Pointable In leap.Frame.Pointables
  ……コード略(前述)……

  Dim tips As New StylusPointCollection(New StylusPoint() {touchPoint})
  Dim touchStroke As New Stroke(tips, touchIndicator)
  paintCanvas.Strokes.Add(touchStroke)
Next
リスト7 ディスプレイ上にタッチ・ポイントを表示する処理(MainWindow.xaml.vb)

 次にLeap Motionのタッチ処理になる。タッチのイメージは次の図のようなイメージだ。

 手前側が「ホバー状態(hovering)」、奥側が「タッチ状態(touching)」を表す。空間の範囲は前後「1」~「-1」となっている。

Leap Motionのタッチ検出イメージ(Leap Motion SDKのAPIドキュメントから引用)
Leap Motionのタッチ検出イメージ(Leap Motion SDKのAPIドキュメントから引用)

 まずホバーの場合は、表示されている円がNavyの色になる。タッチ・ポイントの位置をメンバー変数「x」と「y」に格納する。

 画面に表示されている指の数をleap.Frame.Fingers.Countプロパティで取得して、メンバー変数「FingersCount」に格納しておく。

Visual Basic
For Each Pointable As Pointable In leap.Frame.Pointables
  ……コード略(前述)……

  If Pointable.TouchDistance > 0 AndAlso Pointable.TouchZone <> Global.Leap.Pointable.Zone.ZONENONE Then
    touchIndicator.Color = Colors.Navy
    x = touchPoint.X
    y = touchPoint.Y
    FingersCount = leap.Frame.Fingers.Count  ' 表示されている指の本数を取得して、メンバー変数FingersCountに格納しておく

    ……コード略(続きは後述)……
  End If
Next
リスト8 ホバー時の処理(MainWindow.xaml.vb)

 次にタッチした処理になる。タッチした場合は、表示されている円が赤に変わる。

 それと同時に、タッチしたButtonコントロールの座標を取得して、どのButtonがタッチされたかを判別する。タッチされたButtonによって、メンバー変数「Index」に値を格納する。

具体的には次のコードのようになる。

Visual Basic
If Pointable.TouchDistance > 0 AndAlso Pointable.TouchZone <> Global.Leap.Pointable.Zone.ZONENONE Then
  ……コード略(前述)……
ElseIf Pointable.TouchDistance <= 0 Then
  touchIndicator.Color = Colors.Red
  ' redButtonの座標を取得し、タッチ状態ならメンバー変数「Index」を「1」で初期化する
  If x > redButton.GetValue(Canvas.LeftProperty) And x < redButton.GetValue(Canvas.LeftProperty) + redButton.Width AndAlso y > redButton.GetValue(Canvas.TopProperty) And y < redButton.GetValue(Canvas.TopProperty) + redButton.Height Then
    Index = 1
  End If

  ' blueButtonの座標を取得し、タッチ状態ならメンバー変数「Index」を「2」で初期化する
  If x > blueButton.GetValue(Canvas.LeftProperty) And x < blueButton.GetValue(Canvas.LeftProperty) + blueButton.Width AndAlso y > blueButton.GetValue(Canvas.TopProperty) And y < blueButton.GetValue(Canvas.TopProperty) + blueButton.Height Then
    Index = 2
  End If

  ' greenButtonの座標を取得し、タッチ状態ならメンバー変数「Index」を「3」で初期化する
  If x > greenButton.GetValue(Canvas.LeftProperty) And x < greenButton.GetValue(Canvas.LeftProperty) + greenButton.Width AndAlso y > greenButton.GetValue(Canvas.TopProperty) And y < greenButton.GetValue(Canvas.TopProperty) + greenButton.Height Then
    Index = 3
  End If

  ' yellowButtonの座標を取得し、タッチ状態ならメンバー変数「Index」を「4」で初期化する
  If x > yellowButton.GetValue(Canvas.LeftProperty) And x < yellowButton.GetValue(Canvas.LeftProperty) + yellowButton.Width AndAlso y > yellowButton.GetValue(Canvas.TopProperty) And y < yellowButton.GetValue(Canvas.TopProperty) + yellowButton.Height Then
    Index = 4
  End If

  ' blackButtonの座標を取得し、タッチ状態ならメンバー変数「Index」を「5」で初期化する
  If x > blackButton.GetValue(Canvas.LeftProperty) And x < blackButton.GetValue(Canvas.LeftProperty) + blackButton.Width AndAlso y > blackButton.GetValue(Canvas.TopProperty) And y < blackButton.GetValue(Canvas.TopProperty) + blackButton.Height Then
    Index = 5
  End If

  ' 画面上に表示されている指が1本の場合は、メンバー変数「Index」の値で条件分岐を行う。
  ' Indexの値で、「ShowArea」という名前のCanvasの背景色を、タッチしたボタンの色に変化させる。
  If FingersCount = 1 Then
    Select Case Index
      Case 1
        ShowArea.Background = New SolidColorBrush(Colors.Red)
        Message = "背景色は赤です。"
        Exit Select

      Case 2
        ShowArea.Background = New SolidColorBrush(Colors.Blue)
        Message = "背景色は青です。"
        Exit Select

      Case 3
        ShowArea.Background = New SolidColorBrush(Colors.Green)
        Message = "背景色は緑です。"
        Exit Select

      Case 4
        ShowArea.Background = New SolidColorBrush(Colors.Gold)
        Message = "背景色は黄です。"
        Exit Select

      Case 5
        ShowArea.Background = New SolidColorBrush(Colors.Black)
        Message = "背景色は黒です。"
        Exit Select
    End Select
  ElseIf FingersCount = 5 Then
    ShowArea.Background = New SolidColorBrush(Colors.White)
  End If
End If
リスト9 タッチしたButtonの座標を取得し、メンバー変数「Index」の値を初期化し、そのIndexの値で条件分岐を行う(MainWindow.xaml.vb)

 Indexの値によって処理を分岐する。背景色を変化させる。ただし、この場合は、指が1本認識されている場合に限られる。

 指を5本表示してタッチ処理を行うと、背景色がデフォルトの白に戻る。

 このサンプルのコードは、下記のリンク先よりダウンロードできる*2

  • *2サンプルをダウンロードして動かす場合は、「LeapCSharp.NET4.0.dll」や「LeapCSharp.dll」、「Leap.dll」を読者自身のフォルダー内にあるDLLファイルに指定し直さなければ動かない可能性があるので、動かない場合は再指定していただきたい。

 今回はこれで終わりだ。Leap Motionに関する情報はWebを検索すると、ある程度見つけられるが、実際に動くサンプルで、コードまで掲載されているサイトはない。今回のサンプルは、ごく基本のサンプルであるが、Leap Motionで実際に動かすと、簡単なサンプルでも、感動するものである。このサンプルと、これ以降に紹介するサンプルが、読者の皆さまに感動をもたらすものであることを願う。

 では、また次回にお会いしよう。

※以下では、本稿の前後を合わせて5回分(第1回~第5回)のみ表示しています。
 連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。

Leap Motion実用サンプル(Visual Basic編)
1. 【現在、表示中】≫ オブジェクト(Button)をLeap Motionでタッチして背景色を変化させる

Leap Motionの動くサンプルを実際に作ってみる連載スタート。今回はLeap Motionのタッチ操作で背景色を変化させるWPFアプリをVBで開発する。

Leap Motion実用サンプル(Visual Basic編)
2. Leap MotionによるWPFアプリ上のオブジェクトの移動

Leap Motionの動くサンプルを実際に作ってみる。今回はWPFの画面上に配置したオブジェクトを、Leap Motionによる操作で移動させるアプリを作成。

Leap Motion実用サンプル(Visual Basic編)
3. Leap Motionによる、WPFアプリ上に動的に作成したオブジェクトのイベント処理

Leap Motionの動くサンプルを実際に作ってみる。今回はWPFの画面上に動的に作成したオブジェクトを、Leap Motionによる操作でアニメーションさせるアプリを作成。

Leap Motion実用サンプル(Visual Basic編)
4. Leap Motionでパーティクルを使用して軌跡に無数の円や画像を表示する

さまざまな色の粒子(パーティクル)が、Leap Motionによる手の指の動きに合わせて飛び散りながら追従するサンプル・アプリを作ってみよう。

Leap Motion実用サンプル(Visual Basic編)
5. Leap MotionでBing Mapsを扱う

リスト内に表示された住所項目をLeap Motionによりタッチすることで、Web上のサービス「Bing Maps」での地図検索を行うサンプル・アプリを作ってみよう。

サイトからのお知らせ

Twitterでつぶやこう!