.NET Gadgeteer : デジカメを作ってみた Part 2 (プレビュー高速版)

「.NET Gadgeteer で簡単にデジカメが作れます」という記事 を書きました。

が、ちょっと問題がありました。プレビューが遅い (毎秒2回程度 orz)
悔しいじゃないですか。

ということで、プレビュー高速版を作ってみました。
このあたりまで来るといよいよ情報量の少なさがハードルになってきますね。ちょっと苦労しました。それと高速化との引き替えに少し低レベルなコーディングが必要になります。


Visual Studio のオブジェクトブラウザとか Intellisence とかでライブラリを覗いてみると、気になるメソッドが見つかります。

Camera.StartStreamingBitmaps

いかにもカメラの映像を連続して送り込んでくれそうな名前です。今回のプレビュー高速版はこのメソッドを生かす構造に変えていくことで実現しましょう。


WPFWindow の利用

.NET Micro Framework では画面(を持つデバイス)に WPF を使用します。ただし XAML には対応していないので、C# で既述していきます。

image_thumb4
image_thumb3

display クラスは WPFWindow プロパティを持っています。これがルートになります。
レイアウトが複雑になるようであれば、Canvas 型の変数(layout とでも名前を付けると分かりやすいですね) を WPFWindow.Child に入れてあげるといいですが、今回は画像が表示できればいいだけなので Image クラスを直接使ってしまいます。

streamBitmap は、先ほどの StartStreamBitmaps でカメラの画像を流し込む場所です。Bitmap 型の変数であればいいので capturedImage.Bitmap を引数として渡してもいいのですが、あとのコーディングの都合で streamBitmap を用意しました。
この streamBitmap は画像を流し込むバッファとしてだけ用意したもので、コード中では他に一切使いません。随時内容が書き換えられているためか、他の部分で読み出そうとすると例外が発生してしまいます。
(タイミングを注意すればいいのかもしれませんが、今回は深追いは止めました)


StartStreamBitmaps / StopStreamBitmaps の利用とキャプチャーデータの表示

前回の実装では、Button_Pressed イベントハンドラ内で、TakePicture メソッドを繰り返し呼び出すことで、プレビューと撮影とを行いました。これを StartStreamBitmaps / StopStreamBitmaps の呼び出しに変更します。
なお前回は TakePicture を繰り返し呼ぶためにタイマーを使っていましたが、今回はタイマーは不要、StartStreamBitmaps は一度呼ぶと繰り返し BitmapStreamed イベントを発行してくれます。

image11_thumb

image_thumb9

streamBitmap でカメラ画像を受け取っていますが、BitmapStreamded イベントハンドラでも bitmap 引数でキャプチャしたデータを受け取っています。これを capturedImage.Bitmap に入れます。画面の更新は自動的に行われるので、明示的に Invalidate を呼び出す必要はありません。


写真の保存

SavePicture メソッドの中味も今回の変更にあわせます。

image_thumb14

BitmapStreamed で取得できる Bitmap は、画像ファイルフォーマットの BMP 形式とは違っているようです。そこでファイルに保存する前に BMP 形式に変換しなければなりません。
幸い GHIElectronics が作ったライブラリ内に変換に使えるメソッドがあります。これを利用しましょう。

C:\Program Files (x86)\GHI Electronics\GHI NETMF v4.1 SDK\Assemblies\GHIElectronics.NETMF.System.dll

を参照設定に加えることで利用できるようになります。


ちょっとしたトリック

今回の高速版を作るにあたり、本筋とは関係のないところで少しハマりました。それも紹介しておきます。

WPFWindow を使うと、アプリケーションの起動時に SDCard の SDCardMounted イベントが呼ばれないという現象に遭遇しました。原因は不明ですが、取りあえず暫定でこんな風にしてみました。今のところ問題なく動作しているようです。

image_thumb5
image_thumb4[1]


全ソースコード

今回の全てのソースコードは以下の通りです。今回は不要な using 句は削除しておきました。
※前回は自分の都合で残していただけだったりしてw

using System;
using Microsoft.SPOT;
using Microsoft.SPOT.Presentation;
using Microsoft.SPOT.Presentation.Controls;

using GT = Gadgeteer;
using Gadgeteer.Modules.GHIElectronics;

using GHIElectronics.NETMF.System;

namespace GadgeteerApp1
{
    public partial class Program
    {
        bool previewing = false;
        GT.StorageDevice storage;

        Window mainWindow;
        Image capturedImage;

        Bitmap streamBitmap;

        // This method is run when the mainboard is powered up or reset.   
        void ProgramStarted()
        {
            button.ButtonPressed += new Button.ButtonEventHandler(button_ButtonPressed);
            camera.BitmapStreamed += new Camera.BitmapStreamedEventHandler(camera_BitmapStreamed);

            sdCard.SDCardMounted += new SDCard.SDCardMountedEventHandler(sdCard_SDCardMounted);
            sdCard.SDCardUnmounted += new SDCard.SDCardUnmountedEventHandler(sdCard_SDCardUnmounted);

            if (!sdCard.IsCardInserted)
                InitializeWindow();

            // Use Debug.Print to show messages in Visual Studio's "Output" window during debugging.
            Debug.Print("Program Started");
        }

        private void InitializeWindow()
        {
            mainWindow = display.WPFWindow;
            capturedImage = new Image() { Bitmap = new Bitmap(320, 240) };
            mainWindow.Child = capturedImage;

            streamBitmap = new Bitmap(320, 240);

            Debug.Print("Window Initialized");
        }

        void camera_BitmapStreamed(Camera sender, Bitmap bitmap)
        {
            capturedImage.Bitmap = bitmap;
        }

        void button_ButtonPressed(Button sender, Button.ButtonState state)
        {
            if (previewing)
            {
                camera.StopStreamingBitmaps();
                button.TurnLEDOff();
                SavePicture();
            }
            else
            {
                button.TurnLEDOn();
                camera.StartStreamingBitmaps(streamBitmap);

                Debug.Print("Previewing");
            }

            previewing = !previewing;
        }

        private void SavePicture()
        {
            if (storage == null)
                return;

            string filename = "pict_" + DateTime.Now.ToString("yyyyMMdd-HHmmss") + ".bmp";

            byte[] saveImage = new byte[320 * 240 * 3 + 54];
            Util.BitmapToBMPFile(capturedImage.Bitmap.GetBitmap(), 320, 240, saveImage);
            storage.WriteFile(filename, saveImage);

            Debug.Print("Save a Picture");
        }

        void sdCard_SDCardMounted(SDCard sender, GT.StorageDevice SDCard)
        {
            storage = SDCard;
            Debug.Print("Mounted SDCard");

            if (mainWindow == null)
                InitializeWindow();
        }

        void sdCard_SDCardUnmounted(SDCard sender)
        {
            storage = null;
        }
    }
}

 

持ち運びにはかなり不便そうですがw、デジカメの完成です。

WP_000483

広告
カテゴリー: .NET Micro Framework タグ: , パーマリンク

.NET Gadgeteer : デジカメを作ってみた Part 2 (プレビュー高速版) への3件のフィードバック

  1. ピンバック: .NET Gadgeteer : デジカメを作ってみた (低機能だけど一応完成版) « 技術との戯れ

  2. ピンバック: .NET Gadgeteer : コード 4行でデジカメ(もどき) « 技術との戯れ

  3. ピンバック: Visual Studio で Arduino 開発 « 技術との戯れ

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中