九州ドットネット倶楽部別館

facebook 九州ドットネット倶楽部の別館となります。https://www.facebook.com/groups/301814289891768/ ...現在ほぼ管理人の開発備忘録化しています。

再び

Windows Phoneアプリケーション開発入門:第37回 Mangoで追加されたカメラ機能を使ってみよう!(3)|gihyo.jp … 技術評論社
まずは、
「プレビューしながらリアルタイムエフェクト処理」
をば。

とりあえず、サンプル動きました。なんかすごいですね。


で、バーコードの読み取り精度高めるためにちょっとした案が浮かんだ。
とりあえず、このサンプルにちょっと手を入れてみたらうまいことできそうだ。



ということで最後にバーコード読み取り。


VBへのコンバート

Imports System.IO
Imports System.IO.IsolatedStorage
Imports System.Collections.Generic
Imports System.Linq
Imports System.Windows.Media
Imports System.Windows.Media.Imaging
Imports System.Windows.Navigation
Imports Microsoft.Devices
Imports Microsoft.Phone.Controls
Imports Microsoft.Xna.Framework.Media
Imports System.Diagnostics
Imports com.google.zxing.qrcode
Imports com.google.zxing.common
Imports com.google.zxing


Partial Public Class BarCode
    Inherits PhoneApplicationPage

    ' コンストラクター
    Public Sub New()
        InitializeComponent()
    End Sub

    Private camera As PhotoCamera = Nothing

    ' ページがフレームでアクティブになったら呼び出される
    Protected Overrides Sub OnNavigatedTo(e As NavigationEventArgs)
        camera = New PhotoCamera()
        AddHandler camera.Initialized, AddressOf camera_Initialized
        PreviewBrush.SetSource(camera)
    End Sub

    ' ページがフレームでアクティブでなくなったら呼び出される
    Protected Overrides Sub OnNavigatedFrom(e As NavigationEventArgs)
        If camera IsNot Nothing Then
            camera.Dispose()
            camera = Nothing
        End If
    End Sub

    ' プレビューフレームの解析を行うタイマー
    Private readTimer As System.Windows.Threading.DispatcherTimer = Nothing

    ' カメラの初期化処理の完了
    Private Sub camera_Initialized(sender As Object, e As CameraOperationCompletedEventArgs)
        ' 初期化処理に失敗した場合は何もしない
        If Not e.Succeeded Then
            Return
        End If




        ' カメラの回転角度に合わせてプレビュー表示も回転させる
        Dispatcher.BeginInvoke(Sub()
                                   PreviewBrush.RelativeTransform = New CompositeTransform() With { _
                                     .CenterX = 0.5, _
                                     .CenterY = 0.5, _
                                     .Rotation = camera.Orientation _
                                   }

                                   ' 100ミリ秒毎に満了する様にタイマーを開始
                                   readTimer = New System.Windows.Threading.DispatcherTimer()
                                   AddHandler readTimer.Tick, AddressOf readTimer_Tick
                                   readTimer.Interval = TimeSpan.FromMilliseconds(100)
                                   readTimer.Start()

                               End Sub)
    End Sub

    ' タイマー満了時にプレビューフレームにバーコードが含まれているか解析
    Private Sub readTimer_Tick(sender As Object, e As EventArgs)

        ' プレビューフレームの取得
        Dim luminanceSource = New PreviewFrameLuminanceSource(CInt(camera.PreviewResolution.Width), CInt(camera.PreviewResolution.Height))
        camera.GetPreviewBufferY(luminanceSource.Buffer)

        ' リーダーインスタンス生成
        Dim reader = New QRCodeReader()

        ' 
        Dim binarizer = New HybridBinarizer(luminanceSource)
        Dim binBitmap = New BinaryBitmap(binarizer)

        Dim result As Result = Nothing
        Try
            ' バーコードの解析(デコード)を行う
            result = reader.decode(binBitmap)
        Catch generatedExceptionName As ReaderException
            ' プレビューフレーム内にバーコードが見つからなかった場合
            ' 読み取り例外のReaderExceptionが発行されてしまう
            Return
        Catch ex As Exception
            Throw ex
        End Try

        ' コントロールへのアクセスを行うのでUIスレッドにて非同期で実行
        Dispatcher.BeginInvoke(Sub()
                                   ' 既にテキストが含まれていれば追加しない
                                   If Not BarcodeListBox.Items.Contains(result.Text) Then
                                       BarcodeListBox.Items.Add(result.Text)
                                   End If

                               End Sub)
    End Sub

    ' 表示領域がタップされるとオートフォーカス処理を開始する
    Private Sub PreviewRectangle_Tap(sender As Object, e As System.Windows.Input.GestureEventArgs)
        If camera Is Nothing Then
            Return
        End If

        System.Diagnostics.Debug.WriteLine("AutoFocus Start: " & DateTime.Now.ToString("HH:mm:ss.fff"))
        AddHandler camera.AutoFocusCompleted, AddressOf camera_AutoFocusCompleted
        ' オートフォーカス処理を開始する
        camera.Focus()
    End Sub

    ' オートフォーカスの完了
    Private Sub camera_AutoFocusCompleted(sender As Object, e As CameraOperationCompletedEventArgs)
        RemoveHandler camera.AutoFocusCompleted, AddressOf camera_AutoFocusCompleted
        System.Diagnostics.Debug.WriteLine("AutoFocus End  : " & DateTime.Now.ToString("HH:mm:ss.fff"))
    End Sub

    Private Sub menuItemTakePicture_Click(sender As Object, e As EventArgs)

        ' フラッシュモードの設定を行う
        ' カメラが赤目補正モードに対応しているか判定する
        If camera.IsFlashModeSupported(FlashMode.RedEyeReduction) Then
            camera.FlashMode = FlashMode.RedEyeReduction
        End If

        ' 静止画撮影可能な解像度を取得する
        Dim sizes = camera.AvailableResolutions
        ' 撮影可能な解像度のうち一番大きなものを設定
        camera.Resolution = sizes.Last()

        ' 撮影シーケンス時に発行されるイベントにハンドラを設定
        AddHandler camera.CaptureStarted, AddressOf camera_CaptureStarted
        AddHandler camera.CaptureImageAvailable, AddressOf camera_CaptureImageAvailable
        AddHandler camera.CaptureThumbnailAvailable, AddressOf camera_CaptureThumbnailAvailable
        AddHandler camera.CaptureCompleted, AddressOf camera_CaptureCompleted

        'camera.CaptureStarted += New EventHandler(AddressOf camera_CaptureStarted)
        'camera.CaptureImageAvailable += New EventHandler(Of ContentReadyEventArgs)(AddressOf camera_CaptureImageAvailable)
        'camera.CaptureThumbnailAvailable += New EventHandler(Of ContentReadyEventArgs)(AddressOf camera_CaptureThumbnailAvailable)
        'camera.CaptureCompleted += New EventHandler(Of CameraOperationCompletedEventArgs)(AddressOf camera_CaptureCompleted)

        ' 静止画撮影の開始要求
        camera.CaptureImage()
    End Sub

    ' 静止画撮影の開始
    Private Sub camera_CaptureStarted(sender As Object, e As EventArgs)
        Debug.WriteLine("camera_CaptureStarted")
    End Sub

    ' カメラからの静止画取り込み終了し画像が使用可能になった
    Private Sub camera_CaptureImageAvailable(sender As Object, e As ContentReadyEventArgs)
        Debug.WriteLine("camera_CaptureImageAvailable")

        Try
            ' 分離ストレージへキャプチャーデータへ保存する
            Using store = IsolatedStorageFile.GetUserStoreForApplication()
                Using strm = store.CreateFile("capture_image.jpg")
                    Dim bytes = New Byte(256 * 1024 - 1) {}
                    While True
                        Dim read As Integer = e.ImageStream.Read(bytes, 0, bytes.Length)
                        If read <= 0 Then
                            Exit While
                        End If
                        strm.Write(bytes, 0, read)
                    End While
                End Using
            End Using
            ' ここでエラー処理
        Catch ex As Exception
        Finally
            e.ImageStream.Close()
        End Try
    End Sub

    ' カメラからの静止画取り込み終了しサムネイル画像が使用可能になった
    Private Sub camera_CaptureThumbnailAvailable(sender As Object, e As ContentReadyEventArgs)
        Debug.WriteLine("camera_CaptureThumbnailAvailable")

        Try
            ' 分離ストレージへサムネイルデータへ保存する
            Using store = IsolatedStorageFile.GetUserStoreForApplication()
                Using strm = store.CreateFile("thumbnail.jpg")
                    Dim bytes = New Byte(256 * 1024 - 1) {}
                    While True
                        Dim read As Integer = e.ImageStream.Read(bytes, 0, bytes.Length)
                        If read <= 0 Then
                            Exit While
                        End If
                        strm.Write(bytes, 0, read)
                    End While
                End Using
            End Using
            ' ここでエラー処理
        Catch ex As Exception
        Finally
            e.ImageStream.Close()
        End Try
    End Sub

    ' 静止画撮影の完了
    Private Sub camera_CaptureCompleted(sender As Object, e As CameraOperationCompletedEventArgs)
        Debug.WriteLine("camera_CaptureCompleted")

        ' 静止画撮影が成功した時の処理
        If e.Succeeded Then
            ' 静止画撮影が失敗した時の処理 
        Else
        End If
    End Sub
End Class





Imports System.Net
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Documents
Imports System.Windows.Ink
Imports System.Windows.Input
Imports System.Windows.Media
Imports System.Windows.Media.Animation
Imports System.Windows.Shapes
Imports com.google.zxing


Public Class PreviewFrameLuminanceSource
    Inherits LuminanceSource

    ' プレビューフレームを格納するバッファ
    Public Property Buffer() As Byte()
        Get
            Return m_Buffer
        End Get
        Set(value As Byte())
            m_Buffer = value
        End Set
    End Property
    Private m_Buffer As Byte()

    Public Sub New(width As Integer, height As Integer)
        MyBase.New(width, height)
        Buffer = New Byte(width * height - 1) {}
    End Sub

    ''' <summary>
    ''' バッファをsbyte[]型で取得する
    ''' </summary>
    Public Overrides ReadOnly Property Matrix() As SByte()
        Get
            ' Bufferをbyte[]からsbyte[]へキャスト
            Return TryCast(TryCast(Buffer, Array), SByte())
        End Get
    End Property

    ''' <summary>
    '''  1ラインずつデータを取得
    ''' </summary>
    Public Overrides Function getRow(y As Integer, row As SByte()) As SByte()
        ' 前回確保したrowとサイズが異なる場合、再度確保しなおす
        If row Is Nothing OrElse row.Length < Width Then
            row = New SByte(Width - 1) {}
        End If

        For i As Integer = 0 To Height - 1
            row(i) = Convert.ToSByte(Buffer(i * Width + y))
        Next

        Return row
    End Function
End Class



これで、一応動きました。
PreviewFrameLuminanceSourceの部分がいったい何をやってるのかわからないのがあれですが。
何かヒントをいただけるとありがたいなぁー。

しかし、毎回質の高い記事には感謝しています。ありがとうございます。