縦画面でも最大解像度でカメラキャプチャ

#win8dev_jp

Windows 8 でカメラキャプチャをして、それをプレビューするには、CaptureElement を画面に置いて、そのソースにMediaCaptuire をセットします。

これ、横画面の場合はいいんですが、縦画面にしても回転せずに小さくなってしまいます。で、困ったという相談を数か所からいただきました。

考察

まず、前提としてこれがあると思いこみましょう。

  • MediaCaptuire は基本的に画面の方向にかかわらず 横方向である。
    → だから縦画面でも横長で表示される
  • CaptureElement はMediaCapture をデフォルトでUniformを使って表示する。
    → だから小さく表示される

そのほか各UIElement的な特性もあるので扱いが難しい。

  • CaptureElement をセンタリングしても一番左上が中心に着てしまう。
    → 回転したら右上などに移動して表示された
  • Grid ははみ出たものはそれを回転しても表示しない
    → 回転すると小さくカットされていることがある
  • 小さく縮小されたものをさらに回転すると余白ができる
    → だからレターボックス(黒い領域)ができる

方法

さて、以上を踏まえて、縦画面でのカメラの縦方向キャプチャをするには、以下のような手順を踏みます。

  1. 最大サイズのCaptureElementを用意し
  2. それをカットされないように保護して
  3. CaptureElementを回転し
  4. 画面の中心に置く

絵にかくとこんな感じ。

image

この時ポイントは、保護してセンタリングするのに最適なコンテナを探すこと。そしてそれに最適なコンテナが Border です。

ということで、以上の処理を実装モデルにすると(768x1366 の解像度なら)

  1. CaptureElementを 1366x768 に設定し
  2. 1366x1366 の Border でグループ化して
  3. CaptureElement を90°回転し
  4. Border を Grid に対して HorizontalAlignment / VerticalAlignment =Center とする

こんな感じですね。

コード

XAML

ということで、XAMLはそれをそのまま実装した形。解像度によってその大きさが変わるので、要素は名前をつけて後でサイズ設定をします。

<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
       
    <Border x:Name="border" VerticalAlignment="Center"   HorizontalAlignment="Center" >
           
        <CaptureElement x:Name="captureElement"   RenderTransformOrigin="0.5,0.5">
            <CaptureElement.RenderTransform>
                 <CompositeTransform Rotation="90"/>
            </CaptureElement.RenderTransform>
         </CaptureElement>

    </Border>
       
</Grid>

 

コードビハインド側

画面ロード時に、解像度に合わせて描く画面要素の大きさを設定する処理を追加します。

public MainPage()
{
this.InitializeComponent();
    this.SizeChanged += MainPage_SizeChanged;
}

public MainPage()
{
this.InitializeComponent();
    this.SizeChanged += MainPage_SizeChanged;
}

void MainPage_SizeChanged(object sender, SizeChangedEventArgs e)
{
    border.Width = this.ActualHeight;
    border.Height = this.ActualHeight;
    captureElement.Width = this.ActualHeight;
    captureElement.Height = this.ActualWidth;
}

 

あとのキャプチャ処理は通常のものと同じです。

MediaCapture capture = null;

protected override async void OnNavigatedTo(NavigationEventArgs e)
{
    capture = new MediaCapture();
    await capture.InitializeAsync();
    captureElement.Source = capture;
    await capture.StartPreviewAsync();
}

マニフェストの設定

Appxmanifest で縦固定にしておきます。

image

おなじく、appxmanifestでマイクとWebカメラを使うことをちゃんと設定します。

image

 

多分これで、やりたいこと(キャプチャ解像度で縦画面で縦方向いっぱいにプレビューする)はできると思います。

おまけ

添付のサンプルは縦横どちらにも対応したサンプルです。横画面の時は余計なことをしなくてもいいですからね。

App38.zip