再び
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の部分がいったい何をやってるのかわからないのがあれですが。
何かヒントをいただけるとありがたいなぁー。
しかし、毎回質の高い記事には感謝しています。ありがとうございます。