Android and iPhone

Want to be friends with people from all over the world.
Trying to study together and iPhone, Android. Regards, The Cancer tail.
<< November 2019 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 >>

スポンサーサイト

0

    一定期間更新がないため広告を表示しています

    - | permalink | - | - |

    iPhone6s と Xperia Z5 比較 「iPhone6s」から替える?  1週間使ってわかった「Xperia Z5」の気になる実力

    0
      iPhone6s  と Xperia Z5 比較
      「iPhone6s」から替える? 1週間使ってわかった「Xperia Z5」の気になる実力

      NTTドコモ、au、ソフトバンクの3キャリアから2015年10月29日に発売されたソニーモバイルコミュニケーションズ製のスマートフォン「Xperia Z5」。今回はNTTドコモ版の「SO-01H」を1週間使用したので、ユーザーの関心が高いバッテリーや発熱などを中心にレビューしたい。

      国内ではAndroidスマホの定番となっているXperiaシリーズ。10月29日に発売されたばかりの最新モデル、Xperia Z 5の実力に迫っていきたい

      基本となるCPUは前機種と共通

      まずはXperia Z5の概要から見ていこう。1080×1920のフルHD表示に対応する約5.2インチ液晶ディスプレイ「トリルミナスディスプレイ for mobile」を備えたボディは、サイズが約72(幅)×146(高さ)×7.3(厚さ)mmで、重量は約154g。このボディに、オクタコアCPUの「Snapdragon 8994 MSM8994(2GHz×4+1.5GHz×4)」と3GBのRAM、32GBのストレージ、200GBまで動作確認済みのmicroSDXCメモリーカードスロットを備える。OSは、「Android 5.1(Lollipop)」だ。

      こうした最も基本となるハードウェア部分は、従来機種の「Xperia Z4」から大きな変更はない。変わったのはディスプレイの画質で、名称はそのままだが、液晶パネルの仕様が変更され、視野角が広がり暗部の表現力が向上している。

      液晶パネルの仕様が変更され、暗部の表現力が増している


      重量はカタログ値で154g。SIMカードやmicroSDメモリーカードを装着した状態で重量を測定したところ155gだった


       デザインは、シルエットや金属フレームなど基本的にはキープコンセプトだが、背面のガラスには感触のよい擦りガラスを採用。円形だった電源ボタンは、指紋認証センサーを内蔵した幅の広いデザインに変更されているなど、新しい要素を取り入れている。

      擦りガラスの背面は、柔らかな感触で今までのスマートフォンにはない新鮮さがある。擦りガラスは汚れがつきやすいイメージだが、指紋は思ったより目立ちにくく、拭けば簡単に取り除けた。

      通信機能を見てみると、LTEでは、2.1GHz帯(バンド1)、1.7GHz帯(バンド3)、800MHz帯(バンド19)、1.5GHz帯(バンド21)、700MHz帯(バンド28)の、NTTドコモのLTEの5バンドいずれにも対応している。複数の電波を束ねて高速化するLTE-Advanced(サービス名「PREMIUM 4G」)にも対応しており、ダウンロード時で最大225Mbpsの通信が可能だ。また、TDD-LTEの2.6GHz帯(バンド38)と1.9GHz帯(バンド39)にも対応しており、海外でのローミングサービスなどで利用できる。


       付加機能も、Xperia Z4から大きな変更はないが、対応のヘッドホンを使えば、ハイレゾ音源の再生時でもノイズキャンセリング機能が併用できるようになった。カメラ機能では、メインカメラの画素数が約2070万画素から約2300万画素にアップし、レンズの焦点距離も25mmから24mmに1mmほど広角化された。オートフォーカスの合焦速度が0.03秒に向上しているという。


      こちらは5倍まで拡大表示したところ。やや暗めの屋内という条件だがレリーフの細部が保たれていることがわかる

      広角レンズは、風景を撮影するのにも便利。入間航空祭で空いっぱいに描かれたハートマークも全体が余裕を持って収まった

      懸案のバッテリーの持ちと発熱はそれぞれ改善したのか?

      本機で気になる、バッテリーの持続性を見てみよう。

      搭載するバッテリーは2900mAhで、Xperia Z4の2930mAhとほとんど変わりはない。スペック表を見ると、連続待ち受け時間は、約480時間→440時間(3G)/約470時間→約410時間に(LTE)。連続通話時間は、約810分→740分(3G)/約 1180分→約1160分(LTE)という具合に時間はそれぞれ短くなっている。だが、NTTドコモ独自の指標で、実際の使用パターンに近い「実使用時間」は、約67.8時間→約77.4時間に向上している。(いずれもXperia Z4との比較)。メーカーでは“バッテリー3日持ち”をうたっている。

      今回は、プリインストールアプリに「Twitter」の公式アプリを追加して1週間ほど使用したが、その間に充電は4回行った。大体1日半〜2日でバッテリーがほぼゼロになるペースで、バッテリー3日持ちを実現するには使い方や利用時間を限定する必要がありそうだ。本機のバッテリー持続性は、最近のスマートフォンとしては特にすぐれたものとは言いがたいが、Xperia Z4よりは幾分よくなっているようである。

      もう1つの課題である発熱について見てみよう。最大の熱源であるCPUは、Xperia Z4と同じだが、Xperia Z5では放熱パイプを増やすなどボディ側の熱対策が強化されている。その結果、前機種のように、ボディの一部が極端に高温になることはなくなり、熱がボディに広く分散しているようだ。なお、前機種で指摘が多かった熱によるカメラの強制終了は、1週間の検証期間中で1回もなかった。

      検証期間中の発熱をグラフ化したものを見ると、「ARエフェクト」を使い続けた際に44.7度を記録したが、Webページを閲覧する程度なら温度上昇は比較的ゆっくりしている。

      約1時間30分ほどWebページの閲覧を中心に断続的に使い続けた際のバッテリー消費のグラフ。93%→70%という23%消費された。筆者の常用しているスマホが35%程度の消費なので、悪い値ではない

      検証中のCPUの発熱をグラフ化したもの。最高で44.7度を記録したが、これは処理負荷の高いARエフェクトを長時間使用したときのもの。特筆するほどの高熱が続くことはなかった

      1時間半ほどの、Webページ閲覧を中心に断続的に遣い続けたときの温度の変化。使い続けても発熱は徐々に進行し、40度手前あたりが上限で、極端な高温にはならない

      3%から100%までの急速充電にかかった時間は2時間15分だった。「QuickCharge 2.0」対応のACアダプターを使えばもう少し短縮できる


      32GBのROMは少々手狭になりつつあるが、復活した安定感が魅力

      安定感が復活したXperia Z5だが、気になる点が1つだけあった。それは、搭載されるROMの容量が32GBにとどまっている点だ。以前のように、ROMの使い道がアプリのインストールや撮影した写真データの保存に限られている時代は過ぎ、ファイルサイズの肥大化が続くゲームアプリやハイレゾ音源など、ROMの容量を消費するコンテンツが増加している。また、本機の場合はこれに加えて、画素数の向上したメインカメラの撮影データもあり、ROMの消費という面では不利だ。

      対策としてmicroSDメモリーカードを使用できるが、アプリのインストール先や著作権保護のかかったコンテンツなどは、ROMにしか保存できないことも多く、万能ではない。本機のように映像や音楽などAV性能にこだわったスマホではなおのこと、32GBのROMでは心もとなく感じる。

      こうした懸念点はあるものの、発熱やバッテリー消費の激しさといった問題を抱えた夏モデルのXperia Z4の問題が大筋で改善されたXperia Z5は、ユーザーの期待を裏切らない1台だ。夏モデルを買い控えていたユーザーなら、検討の価値は大いにあると言えよう。
      //////
      iPhone 6s と Xperia Z5 比較

      iPhone 6 と Xperia Z3 Compact 比較
      //////
       
      iPhone6s と Xperia Z5 比較 「iPhone6s」から替える?  1週間使ってわかった「Xperia Z5」の気になる実力 | permalink | comments(0) | - |

      アプリ開発のメモ 一目でわかるiPhone・Androidアプリ開発の違い

      0
        アプリ開発のメモ  一目でわかるiPhone・Androidアプリ開発の違い

        合宿で 「iPhone・Androidアプリ」開発 L

        スマートフォンを代表する iPhone が発売されてから間もなく10年になります。現在 iPhone と Android のアプリ総数は200万を超え、年々アプリの開発数も増えてきています。
        app date

        2014年には新言語Swiftが登場したことにより、 iPhoneアプリ等の開発もしやすい環境となっています。AndroidとiPhone 向けアプリの開発環境を比較して、アプリ開発の参考にして頂ければ幸いです。

        1 AndroidアプリとiPhoneアプリの開発比較まとめ1.1 比較した結果
        1.2 プログラミング言語について
        1.3 開発OSについて
        1.4 ソフトウェアについて
        1.5 アプリ申請・公開について
        1.6 リリースについて
        1.7 アプリからの広告収入

        2 まとめ

        AndroidアプリとiPhoneアプリの開発比較まとめ

        比較した結果
        開発比較
                                           Android                                                  iPhone
        プログラミング言語            Java                                             Swift もしくは Objective-C
        開発OS                   Windows ,Mac OS X ,Linux                     Mac OS X
        ソフトウェア(SDK)AndroidStudio もしくは Eclipse                Xcode
        アプリ申請先       Google Play Developer                                 iOS Developer Program
        アプリ公開費用 $25(初回のみ、年会費0)                               11,800円/年(価格変動有)
        手数料
         (有料アプリの場合)        30%                                           30%
        リリース                        数時間後                            一週間前後※1

        2015年3月22日時点


        プログラミング言語について
        java s
        Java   VS  Swift

        Java

        1990年ごろに登場した世界で最も使われている伝統的なプログラミング言語です。アプリ以外にもサーバー、ブラウザ、デスクトップなど利用範囲は非常に広く、プログラマーなら知っておくべきプログラミング言語と言えます。

        Swift

        2014年6月にApple発表した新しいプログラミング言語になります。まだ登場して間もないため未完成な部分もありますが、これまで使用されていたObjective-cと比べるとより簡単にアプリ開発を行うことができます。現状のiPhoneアプリ開発においては、いまだObjective-cが広く使われている印象はありますが、AppleがSwiftでのアプリ開発を推奨していることもあり、今後Swiftでの開発がさらに増えると予想されます。そのため、未経験からアプリ開発をしたいと考えている方は、Swiftを学ぶことをおすすめします。

        Objectie-c

        1983年頃に登場したプログラミング言語。1997年頃からMac OS Xシリーズの主要な開発言語となり、現在でもiPod/iPhone/iPad向けのソフトウェア開発でもよく用いられてます。数あるプログラミング言語の中でも特殊な部類に入り、初心者が学ぶには難しい言語とされています。

        開発OSについて

        表に示すように、Androidは様々なOSに対応していますが、iPhoneの場合はMac OS Xのみとなります。


        元々Androidアプリ開発には、Eclipseという開発環境にいつくかのプラグインなどをインストールする必要があり、Xcodeだけで開発ができるiPhoneアプリと比べると環境構築が面倒でした。しかし、2014年12月にAndroid StudioというAndroidプラットフォームに対応した統合開発環境が公開されたことで、現在はそれらの手間は軽減されてきています。一方、Xcodeには、EclipseやAndroid Staddioと違い日本語化が難しいなどの相違点があります。

        初心者のためのXcodeインストールと環境構築方法

        Androidアプリ開発の必需品!Android Studioの環境構築方法

        【Mac版】初心者のためのAndroid Studioインストール方法まとめ

        アプリ申請・公開について

        アプリの開発が進むと出来上がったアプリ・ファイルをインストールし、アプリ公開に向けて Google Play Developer や iOS Developer Program へファイルをアップロードする必要があります。この時に Google Play Developer や iOS Developer Program へ事前にユーザー登録しておく必要があり、登録料も必要になります。

        Google の場合は、$25 支払えば当面アプリをアップロードすることができますが、iOS の場合はアプリを公開している以上、年間11,800円(価格変動有)支払い続ける必要があります。

        尚、有料アプリを公開する場合、売上の30%が手数料として Google もしくは Apple へ支払われます。Android の場合、Google Checkout、iPhone の場合はiTunes connect に所定の手続きをすることで、アプリの売上金を日本円で受け取ることができます。

        リリースについて

        審査

        Android の場合は、作成したアプリを Google Play Developer にアップロードし、使用言語やアイコンなど各種設定を済ませると数時間後で Google Play に公開されます。ただし、差別や犯罪など反社会的な要素を含むアプリは非公開もしくは削除されるなど、Google Play のガイドラインに沿ったアプリである必要があります。

        iPhone の場合は、iOS Developer Program へアプリ・ファイルをアップロードするのですが、手続きを行う画面も英語表記で、中にはコンプライアンスの合意に関するような重要な選択肢もあるため、Androidと比べると少し複雑に感じるかもしれません。また、審査期間が一週間前後と比較的長いことも大きな違いと言えます。アプリ申請から結果発表にかかる平均日数はこちらのサイトから確認できます。
        アプリをリリースした後は、Google Play Developer もしくは iOS Developer Program にてダウンロード状況などアプリの管理を行うことができます。

        アプリからの広告収入

        自分の公開しているアプリに広告を貼り付け、そこから収入を得ることができます。

        代表的な広告サービスは AdMob になりますが、それ以外にも10以上の広告サービスがあります。バナー式、アイコン型、全面型など利用したい広告によってサービス会社も違ってきますし、利用するサービスによって広告数や収入も変わってきます。特にこだわりがなければメジャーなAdMobをお勧めします。AdMobの設定は、Android ・ iPhone アプリのどちらも同じぐらい手間がかかってきます。


        アプリ開発者なら絶対に知っておきたいアプリ内広告まとめ

        アプリ開発で儲けるために絶対欠かせない基礎知識まとめ

        まとめ

        いかがでしたでしょうか?同じアプリを作成、公開するのでも Android と iPhone では仕組みや手続き、費用などが大きく変わってきます。また、アプリ開発は現在発展中の分野なだけあり、古いやり方ではすぐに通用しなくなってしまいますので、最新の情報をキャッチすることが特に重要になります。WEB上や書籍だけでは、情報が陳腐化している可能性がありますので、未経験から始めたいという方は、指導者や自分に合ったスクールに頼ることが上達の近道と言えるでしょう。
        それではオリジナルアプリを開発して、アプリデビューしましょう!

        ゼロから始めるiPhoneアプリ開発!公開までに必要な6つの道具

        ゼロからのアプリ開発!Androidアプリ開発に必要な7つのもの

        /////
        F
        合宿で 「iPhone・Androidアプリ」開発
        /////
         
        アプリ開発のメモ 一目でわかるiPhone・Androidアプリ開発の違い | permalink | comments(0) | - |

        iPhone/iPad Apple Watch の開発メモ (Swift言語) 7月7日

        0
          iPhone/iPad Apple Watch の開発メモ (Swift言語)  7月7日
          C女子
          画像研究

          Swift学習のおススメの本  ライト

          Amazonでどの本がいいか検索していました。いくつか候補もあったのですが感想の部分に「ios8.1になってから動かない」という書き込みがいくつかありました。
          そこでios8.1に対応していることと 絶対に挫折しない という文言に惹かれてこの本を購入することになりました。
          (ios8.1 に対応していないものも含む)
          /////

          iPhone/iPadプログラミングバイブル Swift/iOS8/Xcode6対応 (smart phone programming bible) 単行本  - 2014/10/22

          布留川 英一 (著)
          ////
          Swiftスタートアップガイド 単行本  - 2014/11/12

          掌田 津耶乃   (著)

          ////
          XcodeではじめるSwiftプログラミング 単行本(ソフトカバー)  - 2014/12/18

          大津 真   (著)
          ////
          親切すぎるiPhoneアプリ開発の本 単行本  - 2015/7/2

          國居 貴浩 (著)
          ////
          詳解 Swift 大型本  - 2014/12/10

          荻原 剛志   (著)
          ////
          Android開発者のためのSwift入門 単行本(ソフトカバー)  - 2015/5/27

          中西 良明,日高 正博(著)
          ////
          開発のプロが教える Swift標準ガイドブック 単行本(ソフトカバー)  - 2014/12/25
          渡辺 龍司   (著),
          富家 将己   (著),
          鈴木 晃   (著),   
           & 2 その他
          ////
          No.1スクール講師陣による 世界一受けたいiPhoneアプリ開発の授業 [iOS 8 & Xcode 6 & Swift対応] 大型本  - 2015/4/10
          世界一受けたいiPhoneアプリ開発の授業

          No.1スクール講師陣による 世界一受けたいiPhoneアプリ開発の授業 [iOS 8 & Xcode 6 & Swift対応]
          著者RainbowApps講師,桑村 治良,我妻 幸長,高橋 良輔,七島 偉之
          //// 初
          絶対に挫折しない iPhoneアプリ開発「超」入門【Swift & iOS8.1以降 完全対応】 大型本  - 2014/12/20
          高橋 京介   (著)

          //// 中
          プロの力が身につく iPhone/iPadアプリケーション開発の教科書 Swift対応版 大型本  - 2015/1/17

          藤田 泰介 (著)
          //// 上
          詳細! Swift iPhoneアプリ開発 入門ノート Swift 1.1+Xcode 6.1+iOS 8.1対応 単行本  - 2014/12/13
          大重美幸   (著)

          詳細!Apple Watchアプリ開発入門ノート
          詳細!Apple Watch アプリ開発入門ノート Swift1.2 + Xcode6.3対応 (Oshige introduction note) 単行本  - 2015/6/6
          大重美幸 著
          ////
          iPhone/iPad Apple Watch の開発メモ (Swift言語) 7月7日 | permalink | comments(0) | - |

          iPhone開発メモ OpenCVで写真を漫画風に加工しよう ?実装編?

          0
            iPhone用開発 OpenCVで写真を漫画風に加工しよう ?実装編?
            http://dev.classmethod.jp/smartphone/opencv-manga-2/

            IT モバイル アプリ 研究 メモ
            http://rikezyo00sumaho.blog.jp/archives/21476508.html

            C女子
            /////
            研究 写真 を スケッチ・マンガ・版画風に!

            画像加工 (WEB)
            http://www.bannerkoubou.com/
            /////
            /////
            写真を無料で漫画化 : オンラインで簡単に自分の写真を漫画風 ...
            http://japan.kusocartoon.com/photo-to-cartoon.php
            /////
            /////
            漫画風 | 画像加工の無料サイト:写真加工.com
            http://www.photo-kako.com/comic.cgi
            /////
            /////
            画像スケッチ - バナー工房
            写真が「版画」風+α
            http://www.bannerkoubou.com/photoeditor/woodcut
            /////
            グローカルとグローバルのアプリ開発 ニュース
            http://rikezyo00sumaho.blog.jp/archives/20236698.html
            /////
            アプリ開発 メモ (アプリ開発 に役立つかも?)
            http://itcbio.seesaa.net/article/408067048.html

            IT関連のニュース (最近・最新)
            http://itcbio.seesaa.net/article/404512063.html
            /////
            アプリ開発 メモ (写真 を 漫画スケッチ・版画風に!)
            http://rikezyo00sumaho.blog.jp/archives/17232985.html

            jQuery(JavaScript)でグラフ系アプリ? メモ
            http://rikezyo00sumaho.blog.jp/archives/16071520.html

            アプリ開発 メモ (アプリ開発 に役立つかも?)
            http://rikezyo00sumaho.blog.jp/archives/15898378.html

            地域・地方のアプリ開発をめざして
            http://rikezyo00sumaho.blog.jp/archives/15313647.html

            経済・ビジネス・IT 注目のニュース メモ
            http://news00math.blog.fc2.com/blog-category-36.html
            /////
            前回のおさらい
            前回は漫画カメラで撮影した写真から、以下のように画像処理の工程を計画しました。
            輪郭
            エッジ検出する
            エッジ検出した画像の色を反転する
            白い部分を透過する
            白黒の部分
            画像を三値化する
            灰色の部分を透過する
            スクリーントーンの部分
            スクリーントーン画像を輪郭画像と白黒部分の画像の最背面に配置する


            今回は実際に手を動かして、写真を漫画風に加工するサンプルアプリを作成してみましょう。尚、今回は以下のような開発環境で実装を行います。
            Mac OS X 10.8.2
            Xcode 4.5.1
            iOS SDK 6.0
            OpenCVを使えるようにする
            いきなりですが、今回の画像処理を行うにあたってOpenCVを使用します。OpenCVは画像処理に関してとても実績のあるライブラリです。OpenCVはインテルが開発したオープンソースのC/C++、Java、Python用ライブラリで、iOS以外にもMac OS Xはもちろん、Linux、Windows、Androidなど様々なプラットフォームで動作します。iOSに関してはむしろ最近標準でサポートされたばかりです。
            今回OpenCVを使う理由はエッジ検出を使用するからです。このエッジ検出は他のアルゴリズムと比べると比較的簡単なので、自前で実装してもそんなに苦ではないのですが、そうは言ってもそれなりの行数を記述する必要があります。OpenCVではエッジ検出処理を行う関数が用意されています。また、前回少しだけ紹介したOS X/iOS標準のフレームワークであるCoreImage.frameworkでもエッジ検出がありますが、iOSアプリでは動作しないようになっています(対応していればCoreImage.frameworkを使用したいところですが)。というわけで、今回はOpenCVにあやかっちゃいましょう。どうしても自前で実装したいという方は画像のグレースケール/ネガティブ/エッジ検出処理で、C言語でのエッジ検出処理の実装方法をわかりやすく解説しているのでそちらを参照してください。
            OpenCVのダウンロード
            SourceForgeからOpenCVのフレームワークをダウンロードします。ダウンロードするバージョンは2.4.3です。OpenCV - Browse /opencv-ios/2.4.3 at SourceForge.netを開き、opencv2.framework.zipをクリックします。ダウンロードしたら、ZIPファイルを解凍しておいてください。
            opencv2.frameworkのダウンロード
            Xcodeプロジェクトの作成
            Xcodeプロジェクトを作成します。テンプレートはSingle View Applicationを選択します。プロジェクトの情報に以下のように入力して任意の場所に保存してください。尚、今回はサンプルですので、保存するときにSource ControlのCreate local git repository for this projectのチェックは外しておいてください。
            項目    設定値
            Product Name    MangaFilterTest
            Organization Name    任意
            Company Identifier    任意
            Class Prefix    なし
            Devices    iPhone
            Use Storyboards    チェックする
            Use Automatic Reference Counting    チェックする
            Include Unit Tests    チェックしない
            opencv2.frameworkの導入
            作成したXcodeプロジェクトにopencv2.frameworkを追加
            Xcodeプロジェクトを作成したら、ファイルツリービューのFrameworksを右クリックしてAdd Files to "MangaFilterTest"...をクリックします。ファイル選択画面が表示されるので、先ほどダウンロード・解凍して先ほどダウンロード・解凍したopencv2.frameworkを選択し、Copy items into destination group's folder (if needed)にチェック、Create groups for any added foldersを選択し、Addボタンをクリックしてプロジェクトに追加します。
            opencv2.frameworkのインポート
            これで、XcodeプロジェクトでOpenCVを使用する準備が整いました。
            注意:OpenCV 2.4.2を使用する場合
            OpenCV 2.4.2はiOS6(armv7s)に対応していないため、使用する際は注意が必要です。 どうしてもOpenCV 2.4.2を使用したい場合は、以下のサイトで導入方法をわかりやすく解説していますので、ぜひ参考にしてください。 iOSでOpenCVを使えるようにしてみる - FuturesVision
            必要なファイルを作成しよう
            早速実装作業に入っていきましょう。漫画風のフィルタ処理を実現するため、以下のような工程で画像処理を行います。
            今回の目標
            上記のように、今回は元画像から輪郭画像と白黒部分の画像をそれぞれ生成し最後に合成するようにします。これらの処理を実現するために、以下のようなクラスを作成します。
            クラス    親クラス    ファイル    説明
            FilterBase    NSObject    FilterBase.h
            FilterBase.mm    フィルタクラスの抽象クラスです。CGImageとOpenCV画像データ間の変換処理を実装します。
            LineFilter    FilterBase    LineFilter.h
            LineFilter.mm    輪郭を黒いペンでなぞったような画像を生成します。
            MonochromeFilter    FilterBase    MonochromeFilter.h
            MonochromeFilter.mm    白黒部分の画像を生成します。
            上記ファイルを作成しましょう。ファイルを作成したら、実装ファイルの拡張子を.mから.mmに変更します。実装ファイルの拡張子を.mmにすると、ファイル中にObjective-CとC++のソースコードを混在させることができます。
            FilterBaseクラス
            FilterBaseクラスはフィルタクラスの抽象クラスです。CGImageからOpenCV画像データに変換したり、OpenCV画像データからCGImageに変換したりするメソッドを定義しておきます。また、このクラスを継承したサブクラスにてフィルタ処理をかけるときに使用するメソッド- doFilter:も定義しておきます。


            FilterBase.h

            #import <Foundation/Foundation.h>
            #import <opencv2/opencv.hpp>
             
            @interface FilterBase : NSObject
             
            /*!
             @method
             @abstract フィルタ処理を実行するメソッド
             @discussion 引数imageにフィルタ処理したCGImageを返す。
             @param image CGImageRef フィルタ処理をかけるCGImage
             @return CGImageRef フィルタ処理したCGImage
             */
            - (CGImageRef)doFilter:(CGImageRef)image;
             
            /*!
             @method
             @abstract CGImageをOpenCV画像データに変換するメソッド
             @param image CGImageRef CGImage
             @return IplImage OpenCV画像データ
             */
            - (IplImage *)newIplImageFromCGImage:(CGImageRef)image;
             
            /*!
             @method
             @abstract OpenCV画像データをCGImageに変換するメソッド
             @param image IplImage OpenCV画像データ
             @return CGImageRef CGImage
             */
            - (CGImageRef)newCGImageFromIplImage:(IplImage *)image;
             
            @end


            FilterBase.mm



            #import "FilterBase.h"
             
            @implementation FilterBase
             
            - (CGImageRef)doFilter:(CGImageRef)image
            {
                CGImageRetain(image);
                 
                // 必要なら呼び出し側でCGImageReleaseによりメモリを解放すること
                return image;
            }
             
            - (IplImage *)newIplImageFromCGImage:(CGImageRef)image
            {
                CGContextRef context;
                CGColorSpaceRef colorSpace;
                IplImage *iplImageTemp, *iplImage;
                 
                // RGB色空間を作成
                colorSpace = CGColorSpaceCreateDeviceRGB();
                 
                // 一時的なIplImageを作成
                iplImageTemp = cvCreateImage(cvSize(CGImageGetWidth(image), CGImageGetHeight(image)), IPL_DEPTH_8U, 4);
                 
                // CGBitmapContextをIplImageのビットマップデータのポインタから作成
                context = CGBitmapContextCreate(iplImageTemp->imageData,
                                                iplImageTemp->width,
                                                iplImageTemp->height,
                                                iplImageTemp->depth,
                                                iplImageTemp->widthStep,
                                                colorSpace,
                                                kCGImageAlphaPremultipliedLast | kCGBitmapByteOrderDefault);
                 
                // CGImageをCGBitmapContextに描画
                CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, CGImageGetWidth(image), CGImageGetHeight(image)), image);
                 
                // ビットマップコンテキストと色空間を解放
                CGContextRelease(context);
                CGColorSpaceRelease(colorSpace);
                 
                // 最終的なIplImageを作成
                iplImage = cvCreateImage(cvGetSize(iplImageTemp), IPL_DEPTH_8U, 3);
                cvCvtColor(iplImageTemp, iplImage, CV_RGBA2RGB);
                 
                // 一時的なIplImageを解放
                cvReleaseImage(&iplImageTemp);
                 
                // 必要なら呼び出し側でcvReleaseImageよりメモリを解放すること
                return iplImage;
            }
             
            - (CGImageRef)newCGImageFromIplImage:(IplImage *)image
            {
                CGColorSpaceRef colorSpace;
                NSData *data;
                CGDataProviderRef provider;
                CGImageRef cgImage;
                 
                // RGB色空間
                colorSpace = CGColorSpaceCreateDeviceRGB();
                 
                // IplImageのビットマップデータのポインタアドレスからNSDataを作成
                data = [NSData dataWithBytes:image->imageData length:image->imageSize];
                provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data);
                 
                // CGImageを作成
                cgImage = CGImageCreate(image->width,
                                        image->height,
                                        image->depth,
                                        image->depth * image->nChannels,
                                        image->widthStep,
                                        colorSpace,
                                        kCGImageAlphaNone | kCGBitmapByteOrderDefault,
                                        provider,
                                        NULL,
                                        false,
                                        kCGRenderingIntentDefault);
                 
                CGColorSpaceRelease(colorSpace);
                CGDataProviderRelease(provider);
                 
                // 必要なら呼び出し側でCGImageReleaseによりメモリを解放すること
                return cgImage;
            }
             
            @end

            LineFilterクラス
            元画像の輪郭を抽出し、黒いペンでなぞったような画像を生成します。この画像を生成するには前回紹介したエッジ検出を使用します。まずは実際のソースコードを見てみましょう。


            LineFilter.h

            #import "FilterBase.h"
             
            @interface LineFilter : FilterBase
             
            @end


            LineFilter.mm

            #import "LineFilter.h"
             
            @implementation LineFilter
             
            - (CGImageRef)doFilter:(CGImageRef)image
            {
                // 1.CGImageからIplImageを作成
                IplImage *srcImage       = [self newIplImageFromCGImage:image];
                 
                IplImage *grayscaleImage = cvCreateImage(cvGetSize(srcImage), IPL_DEPTH_8U, 1);
                IplImage *edgeImage      = cvCreateImage(cvGetSize(srcImage), IPL_DEPTH_8U, 1);
                IplImage *dstImage       = cvCreateImage(cvGetSize(srcImage), IPL_DEPTH_8U, 3);
                 
                // 2.グレースケール画像に変換
                cvCvtColor(srcImage, grayscaleImage, CV_BGR2GRAY);
                 
                // 3.グレースケール画像を平滑化
                cvSmooth(grayscaleImage, grayscaleImage, CV_GAUSSIAN, 3, 0, 0);
                 
                // 4.エッジ検出画像を作成
                cvCanny(grayscaleImage, edgeImage, 20, 120);
                 
                // 5.エッジ検出画像色を反転
                cvNot(edgeImage, edgeImage);
                 
                // 6.CGImage用にBGRに変換
                cvCvtColor(edgeImage, dstImage, CV_GRAY2BGR);
                 
                // 7.IplImageからCGImageを作成
                CGImageRef effectedImage = [self newCGImageFromIplImage:dstImage];
                 
                cvReleaseImage(&srcImage);
                cvReleaseImage(&grayscaleImage);
                cvReleaseImage(&edgeImage);
                cvReleaseImage(&dstImage);
                 
                // 8.白色の部分を透過する
                const float colorMasking[6] = {255, 255, 255, 255, 255, 255};
                effectedImage = CGImageCreateWithMaskingColors(effectedImage, colorMasking);
                 
                return effectedImage;
            }
             
            @end
            1.CGImageからIplImageを作成
            FilterBaseで定義した- newIplImageFromCGImage:メソッドを使用してCGImageをIplImage(OpenCVで扱う画像データ)に変換します。
            2.グレースケール画像に変換
            エッジ検出をする場合、カラー画像ではノイズが多くうまく検出できない場合があるため、グレースケール画像や二値化した画像を使用することが多いです。今回はグレースケール画像を使用します。元画像からグレースケール画像を生成するには、void cvCvtColor(const CvArr* src, CvArr* dst, int code)関数を使用します。この関数は主に画像の色空間を変換するために使用します。第1引数srcに対して第3引数codeで指定した色空間に変換したものを第2引数dstに生成します。この段階での画像は以下のようになります。
            グレースケールを適用した画像
            3.グレースケール画像を平滑化
            エッジ検出を行う前にガウシアンフィルタで平滑化を行います。平滑化を行うことによって、画像のノイズを減少させ、安定したエッジ検出を行うことができます。 void cvSmooth(const CvArr* src, CvArr* dst, int smoothtype=CV_GAUSSIAN, int param1=3, int param2=0, double param3=0, double param4=0)関数を使用します。この段階での画像は以下のようになります。
            グレースケールに平滑化を適用した画像
            4.エッジ検出画像を生成
            生成したグレースケール画像を使用してエッジ検出処理を施します。エッジ検出処理はvoid cvCanny(const CvArr* image, CvArr* edges, double threshold1, double threshold2, int aperture_size=3)関数を使用します。cvCanny関数ではCanny法というアルゴリズムを使用してエッジ検出を行います。第3引数threshold1と第4引数threshold2は、小さいほうがエッジ同士を接続するために用いられ,大きいほうが強いエッジの初期検出に用いられます。threshold1、threshold2を変更することで、検出の度合を変更できます。今回はそれぞれ20、120を指定していますが、生成したい画像にあわせて設定しましょう。 この段階での画像は以下のようになります。
            エッジ検出を適用した画像
            5.エッジ検出画像色を反転
            エッジ検出しただけでは今回生成したい画像とは白黒逆になっているので、色を反転させましょう。色を反転するには、void cvNot(const CvArr* src, CvArr* dst)関数を使用します。この段階での画像は以下のようになります。
            エッジ検出画像の色を反転した画像
            6.CGImage用にBGRに変換
            ここまでで生成した画像をCGImage用にBGRに変換します。これを忘れてしまうと大変なことになってしまいます。この処理は先ほど紹介したcvCvtColor関数を使用します。
            7.IplImageからCGImageを作成
            FilterBaseで定義した- newCGImageFromIplImage:メソッドを使用してIplImageをCGImageに変換します。
            .白色の部分を透過する
            今回必要なのは、あくまで輪郭の黒い線なので、生成した画像の白い部分を透過します。指定した色を透過するにはCGImageRef CGImageCreateWithMaskingColors(CGImageRef image, const CGFloat components[])関数を使用します。この関数は第1引数imageで指定した画像に対して第2引数componentsで指定した範囲内の色でマスキングします。この段階での画像は以下のようになります。
            輪郭画像完成
            これで輪郭画像の完成です。
            MonochromeFilterクラス
            白黒でべた塗りしたような画像を生成します。しかし今回作成したい画像は、白黒だけではなく灰色の部分にスクリーントーンを表示しなければなりません。これは前回紹介した2値化のアルゴリズムを少し改良して、白・黒の2色ではなく白・黒・灰色の3値化を実現しましょう。

            MonochromeFilter.h

            #import "FilterBase.h"
             
            @interface MonochromeFilter : FilterBase
             
            @end



            MonochromeFilter.mm

            #import "MonochromeFilter.h"
             
            @implementation MonochromeFilter
             
            - (CGImageRef)doFilter:(CGImageRef)image
            {
                // 1.CGImageからIplImageを作成
                IplImage *srcImage       = [self newIplImageFromCGImage:image];
                IplImage *grayScaleImage = cvCreateImage(cvGetSize(srcImage), IPL_DEPTH_8U, 1);
                IplImage *dstImage       = cvCreateImage(cvGetSize(srcImage), IPL_DEPTH_8U, 3);
                 
                // 2.グレースケール画像に変換
                cvCvtColor(srcImage, grayScaleImage, CV_BGR2GRAY);
                 
                // 3.グレースケール画像を1画素ずつ走査して3値化する
                for(int y = 0; y < grayScaleImage->height; y++) {
                    for(int x = 0; x < grayScaleImage->width; x++) {
                        int a = grayScaleImage->widthStep * y + x;
                        uchar p = grayScaleImage->imageData[a];
                         
                        if (p < 70) {
                            // 70より小さい場合、黒
                            grayScaleImage->imageData[a] = 0;
                        } else if (70 <= p && p < 120) {
                            // 70以上、120未満の場合、灰色
                            grayScaleImage->imageData[a] = 100;
                        } else {
                            // 120以上の場合、白
                            grayScaleImage->imageData[a] = 255;
                        }
                    }
                }
                 
                // 4.CGImage用にBGRに変換
                cvCvtColor(grayScaleImage, dstImage, CV_GRAY2BGR);
                 
                // 5.IplImageからCGImageを作成
                CGImageRef effectedImage = [self newCGImageFromIplImage:dstImage];
                 
                cvReleaseImage(&srcImage);
                cvReleaseImage(&grayScaleImage);
                cvReleaseImage(&dstImage);
                 
                // 6.灰色の部分を透過する
                const float colorMasking[6] = {100, 100, 100, 100, 100, 100};
                effectedImage = CGImageCreateWithMaskingColors(effectedImage, colorMasking);
                 
                return effectedImage;
            }
             
            @end
            1.CGImageからIplImageを作成
            LineFilterと同じです。FilterBaseで定義した- newIplImageFromCGImage:メソッドを使用してCGImageをIplImage(OpenCVで扱う画像データ)に変換します。
            2.グレースケール画像に変換
            エッジ検出と同様、画像に2値化処理を施す場合、グレースケール画像を使用することが多いです。なのでここでもグレースケール画像を使用します。この段階での画像は以下のようになります。
            グレースケールを適用した画像
            3.グレースケール画像を1画素ずつ走査して3値化する
            グレースケール画像を1画素ずつ走査して3値化処理を施します。画像サイズはIplImage構造体に定義されているメンバ変数widthとheightから取得できます。画像データのバイト数はメンバ変数widthStepで取得できます。これらの値を使用して画像データへのポインタであるimageDataより1画素ずつ値を変更します。
            通常、画像に対して2値化を行う場合、任画素の構成要素RGBの平均値を算出し任意のしきい値より大きければ白、小さければ黒にします。今回は3値化なのでしきい値を2つ用意します。これにより、白・黒・灰色の3色だけで構成された画像を生成することができます。この段階での画像は以下のようになります。尚、灰色はとりあえずR:100、G:100、B:100(#646464)としておきます。
            3値化した画像
            4.CGImage用にBGRに変換
            ここまでで生成した画像をCGImage用にBGRに変換します。これを忘れてしまうと大変なことになってしまいます。この処理は先ほど紹介したcvCvtColor関数を使用します。
            5.IplImageからCGImageを作成
            FilterBaseで定義した- newCGImageFromIplImage:メソッドを使用してIplImageをCGImageに変換します。
            6.白色の部分を透過する
            今回は灰色の部分にスクリーントーンを表示するので、生成した画像の灰色の部分を透過します。指定した色を透過するにはCGImageRef CGImageCreateWithMaskingColors(CGImageRef image, const CGFloat components[])関数を使用します。この段階での画像は以下のようになります。
            白黒部分の画像完成
            スクリーントーン
            スクリーントーンの部分は、UIImageViewの背景に以下の画像をタイル状に並べましょう。(スクリーントーン画像のダウンロード)この画像をscreentone.pngとして保存し、Xcodeプロジェクトに追加してください。尚、この画像はStripe Generator - ajax diagonal stripes background designerで生成しました。
            スクリーントーンサンプル
            合成してみよう
            さぁこれでようやく準備が整いました。以下のサンプル画像をsample.jpgとして保存し、Xcodeプロジェクトに追加してください。
            サンプル画像
            保存できたら、Xcodeプロジェクトに予め作成されているViewController.mをViewController.mmに変更して、以下のように記述しましょう。
            ViewController.mm

            #import "ViewController.h"
             
            // 作成したフィルタを読み込む
            #import "LineFilter.h"
            #import "MonochromeFilter.h"
             
            @implementation ViewController
             
            - (void)viewDidLoad
            {
                [super viewDidLoad];
                 
                // 1.漫画風に加工する画像を読み込む
                UIImage *image = [UIImage imageNamed:@"sample.jpg"];
             
                // 2.白黒部分の画像を生成する
                MonochromeFilter *monochromeFilter = [[MonochromeFilter alloc] init];
                CGImageRef monocrhomeCGImage = [monochromeFilter doFilter:image.CGImage];
                UIImage *monocrhomeImage = [UIImage imageWithCGImage:monocrhomeCGImage];
                CGImageRelease(monocrhomeCGImage);
                 
                // 3.輪郭画像を生成する
                LineFilter *lineFilter = [[LineFilter alloc] init];
                CGImageRef lineCGImage  = [lineFilter doFilter:image.CGImage];
                UIImage *lineImage  = [UIImage imageWithCGImage:lineCGImage];
                CGImageRelease(lineCGImage);
             
                UIImage *margedImage;
                CGRect imageRect = CGRectMake(0, 0, image.size.width, image.size.height);
                 
                // 4.画像を合成する
             
                // 4-1.オフスクリーン描画のためのグラフィックスコンテキストを用意
                UIGraphicsBeginImageContext(imageRect.size);
                 
                // 4-2.白黒部分の画像をコンテキストに描画
                [monocrhomeImage drawInRect:imageRect];
             
                // 4-3.輪郭画像をコンテキストに描画
                [lineImage drawInRect:imageRect];
             
                // 4-4.合成画像をコンテキストから取得
                margedImage = UIGraphicsGetImageFromCurrentImageContext();
             
                // 4-5.オフスクリーン描画を終了
                UIGraphicsEndImageContext();
             
                // 表示用のUIImageViewを生成
                UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
                imageView.contentMode = UIViewContentModeScaleAspectFit;
             
                // 合成画像を設定
                imageView.image = margedImage;
                 
                // 5.スクリーントーン画像をUIImageViewの背景パータンとして設定
                imageView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"screentone.png"]];
                 
                // UIImageViewを配置
                [self.view addSubview:imageView];
            }
             
            @end
            1.漫画風に加工する画像を読み込む
            加工対象の画像のCGImageを取得するために、UIImageインスタンスを生成します。
            2.白黒部分の画像を生成する
            先ほど作成したMonochromeFilterクラスを使用して、白黒部分の画像を生成します。
            3.輪郭画像を生成する
            先ほど作成したLineFilterクラスを使用して、白黒部分の画像を生成します。
            4.画像を合成する
            生成した画像を合成します。画像を合成するには、UIGraphicsBeginImageContext(CGSize size)関数でオフスクリーン描画のためのグラフィックスコンテキストを用意して(4-1)、生成した白黒部分の画像と輪郭画像を描画し(4-2、4-3)、できた合成画像をコンテキストから取得します(4-4)。最後にオフスクリーン描画を終了します(4-5)。
            5.スクリーントーン画像をUIImageViewの背景パータンとして設定
            最後にスクリーントーン画像をUIImageViewの背景パータンとして設定します。
            完成!!
            動作を確認してみましょう。
            動作確認
            まとめ
            以上、2回に渡り写真を漫画風に加工するための画像処理をお送りしました。この記事ではOpenCVを使用していますが、自前で実装したりCoreImage.frameworkを利用したりするのもありでしょう。この記事をきっかけに面白いorかっちょいいカメラアプリを作って頂ければ幸いです。

            /////
            iPhone開発メモ OpenCVで写真を漫画風に加工しよう ?実装編? | permalink | comments(0) | - |

            iPhone開発メモ OpenCVで写真を漫画風に加工してみよう ?手法編?

            0
              iPhone開発メモ OpenCVで写真を漫画風に加工してみよう ?手法編?
              http://dev.classmethod.jp/smartphone/opencv-manga-1/

              Cカープ女子
              最近iOS界隈では漫画風に画像を加工するカメラアプリが人気を博しております。写真に何らの加工を施すには、画像処理技術が必要です。画像処理と聞くと敷居が高そうに思われる方も多いかと思いますが、実はそんなに難しくありません。難しくないと言っても、じゃあ作ってみろよと言われると意外とわからないこともありますよね。実際に漫画風に加工するとなるとどのように実装するのか。。。
              というわけで今回から2回に分けて写真を漫画風に加工するための画像処理について、手法と実装の2回に分けて解説していこうと思います。今回は手法の解説だけになるので、すぐにでも手を動かしたい方はこの記事をすっ飛ばして次の記事を読んでください。
              使用する画像処理技術のあたりをつけよう
              まずは加工後の写真をイメージして、使用する画像処理技術のあたりをつけていきましょう。
              画像処理に関するアルゴリズムは既に一般化されているものがたくさんあります。今回のように目標(漫画風にする)がはっきりしている場合は、独自にどうこうするのではなく、まずは既にあるものから使えそうなものを探してみましょう。画像処理に関する情報はWEB、書籍ともに非常に充実しております。ここでは私が実際に読んだものを紹介しますが、とりあえず今の時点ですべて目を通す必要はありません。こんなものがあるんだぐらいに見といてください。
              画像処理におけるアルゴリズム
              http://homepage2.nifty.com/tsugu/sotuken/ronbun/sec3-2.html


              画像処理におけるアルゴリズム 画像処理におけるアルゴリズムの種類や内容を非常に簡単に解説しています。とても参考になりました。

              Core Image Filter Reference(iOS Developer Library)
              https://developer.apple.com/library/ios/documentation/GraphicsImaging/Reference/CoreImageFilterReference/index.html

              Core Image Filter Reference(iOS Developer Library) Mac OS X/iOSアプリで標準で使用できるCoreImage.frameworkを用いた画像処理について解説されています。ここで紹介されている画像処理をすべてiOSアプリ開発で使用できるわけではありませんが、Objecive-Cに慣れている方であれば、こういう切り口から画像処理の世界に入るのもありではないでしょうか。

              opencv.jp - OpenCV: フィルタと色変換(Filters and Color Conversion)サンプルコード -
              http://opencv.jp/sample/filter_and_color_conversion.html


              opencv.jp - OpenCV: フィルタと色変換(Filters and Color Conversion)サンプルコード - OpenCVを使用した画像処理をサンプルコードと一緒に解説しています。OpenCVはインテルが開発したオープンソースのC/C++、Java、Python用ライブラリで、iOS以外にもMac OS Xはもちろん、Linux、Windows、Androidなど様々なプラットフォームで動作します。iOSに関してはむしろ最近標準でサポート(armv7sでは動きませんが)されたばかりです。

              画像処理に関してまだ駆け出しのひよっこの癖に生意気なことを書かせて頂きましたが本題に戻りましょう。私は写真を漫画風に加工する上で、以下の2つのフィルタ処理が近そうだなぁと考えました。
              エッジ検出(輪郭検出)
              Wikipediaによると、エッジ検出とは「画像処理やコンピュータビジョンの用語で、特徴検出や特徴抽出の一種であり、デジタル画像の画像の明るさが鋭敏に(より形式的に言えば不連続に)変化している箇所を特定するアルゴリズムを指す」とのことです(参考:エッジ検出 - Wikipedia)。わかりやすく言うと、画像中にあるモノの境界線を検出する処理です。実際にエッジ検出処理をかけた画像を見てみましょう。
              エッジ検出の実行例
              これは輪郭を線でなぞったような効果を出すのに使えそうですね。
              2値化
              上で紹介した画像処理におけるアルゴリズムによると、「指定画像を白と黒の2階調の画像に変換する処理」とあります。具体的には、RGB各要素の平均値がしきい値より高ければ白、低ければ黒と言った具合に分けて、写真を真っ白と真っ黒の2色だけの画像を生成します。実際に2値化を施した画像を見てみましょう。
              2値化の実行例
              これも写真をモノクロにするために使えそうです。
              この2つのアルゴリズムを使用すれば、写真を漫画風に加工したような効果を演出することができそうです。
              画像処理工程の計画をたてよう
              使えそうなフィルタは出揃いましたが、単体でみるとまだまだ完成にはほど遠いです。これらのフィルタを利用して、どうすれば完成に近づくか模索しながらどういう処理が必要か計画をたてていきましょう。
              私は漫画風の写真を構成する要素として以下の3つに分けて考えました。
              輪郭
              白黒の部分
              スクリーントーンの部分
              この3つの要素を合成させれば写真を漫画風に加工できそうです。それでは実際にどういう工程でこれらの要素を生成するか計画をたてましょう。
              1.輪郭
              撮影した写真から黒いペンで輪郭をなぞったような画像です。これは先ほどあたりをつけたエッジ検出が使えそうですが、エッジ検出処理を施した画像を見ると加工してやる必要がありそうです。そこで私は以下のような工程を考えました。
              エッジ検出する
              エッジ検出した画像の色を反転する
              白い部分を透過する
              2.白黒の部分
              次に白黒の部分です。これは2値化が使えそうです。しかし、2値化してしまうと白黒だけになってしまい、淡い色の部分、すなわちスクリーントーン部分が表現できません。 ここは2値化のアルゴリズムを利用して、白と黒の2値化ではなく白・灰色・黒の3値化することで対応しましょう。工程としては以下の通りです。
              画像を3値化する
              灰色の部分を透過する
              灰色部分を透過するのは、次に紹介するスクリーントーンの部分を表示するためです。
              3.スクリーントーンの部分
              最後のスクリーントーンの部分。こいつは非常に簡単で以下の画像を輪郭画像と白黒部分の画像の最背面に配置するだけです。
              今回の目標
              これで漫画風の写真が生成できそうですね。画像に施す処理の工程がはっきりしました。次回は実際に手を動かして画像を加工してみましょう。


              /////
              フィルタと色変換
              http://opencv.jp/sample/filter_and_color_conversion.html

              作成者: 怡土順一, 最終変更者: 怡土順一, 最終変更リビジョン: 342, 最終変更日時: 2007-10-14 23:39:34 +0900 (日, 14 10月 2007)
              ■ フィルタ

              フィルタという単語は,非常に幅広い意味を持つ. OpenCVのリファレンス マニュアルでは, 主に二次元マトリックス(フィルタ,カーネルなどと呼ばれる)と, 画像の処理対象領域の画素値との畳み込み演算を行うことによって実現される, いわゆる空間フィルタ処理についての関数をフィルタ処理としている. 画像勾配を求める処理(微分フィルタ)もフィルタ処理の一部ではあるが,そ れは別途解説されているので,そちらを参照すること.
              サンプル

              平滑化 cvSmooth
              ブラー,ガウシアン,メディアン,バイラテラル,の各フィルタによる平滑化

              サンプルコード


              #include <cv.h>
              #include <highgui.h>

              int
              main (int argc, char **argv)
              {
                int i;
                IplImage *src_img = 0, *dst_img[4];

                // (1)画像を読み込む
                if (argc >= 2)
                  src_img = cvLoadImage (argv[1], CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR);
                if (src_img == 0)
                  exit (-1);

                for (i = 0; i < 4; i++)
                  dst_img[i] = cvCloneImage (src_img);

                // (2)手法を指定して画像を平滑化
                cvSmooth (src_img, dst_img[0], CV_BLUR, 5, 0, 0, 0);
                cvSmooth (src_img, dst_img[1], CV_GAUSSIAN, 11, 0, 0, 0);
                cvSmooth (src_img, dst_img[2], CV_MEDIAN, 5, 0, 0, 0);
                cvSmooth (src_img, dst_img[3], CV_BILATERAL, 80, 80, 0, 0);

                // (3)処理された画像を実際に表示
                cvNamedWindow ("Blur", CV_WINDOW_AUTOSIZE);
                cvShowImage ("Blur", dst_img[0]);
                cvNamedWindow ("Gaussian", CV_WINDOW_AUTOSIZE);
                cvShowImage ("Gaussian", dst_img[1]);
                cvNamedWindow ("Median", CV_WINDOW_AUTOSIZE);
                cvShowImage ("Median", dst_img[2]);
                cvNamedWindow ("Bilateral", CV_WINDOW_AUTOSIZE);
                cvShowImage ("Bilateral", dst_img[3]);
                cvWaitKey (0);

                cvDestroyWindow ("Blur");
                cvDestroyWindow ("Gaussian");
                cvDestroyWindow ("Median");
                cvDestroyWindow ("Bilateral");
                cvReleaseImage (&src_img);
                for (i = 0; i < 4; i++) {
                  cvReleaseImage (&dst_img[i]);
                }

                return 0;
              }

              // (1)画像を読み込む
              コマンド引数で指定されたファイル名の画像(入力画像)をオープンし,関数 cvLoadImage()で読み込む.2番目の引数にCV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLORを指定することで,元画像のデプス,チャンネルを変 更せずに読み込む.

              // (2)手法を指定して画像を平滑化
              関数cvSmooth()の3番目の引数で, CV_BLUR(ブラーフィルタ),CV_GAUSSIAN(ガウシアンフィルタ),CV_MEDIAN(メディアンフィルタ),CV_BILATERAL(バイラテラルフィルタ) の各手法を指定して平滑化を行う. 4番目以降の引数の意味は,手法毎に異なる.詳しくは,リファレンス マニュアルを参照すること.

              // (3)処理された画像を実際に表示
              各手法で平滑化された画像を実際に表示し,何かキーが押されるまで待つ.

              実行結果例
              下段の画像は,処理画像の一部を拡大したものである. ただし,手法毎にパラメータを変えてあるので,単純に比較できる画像ではない.
              入力画像    Blur    Gaussian    Median    Bilateral
                                   
                                   
              ユーザ定義フィルタ cvFilter2D
              ユーザが定義したカーネルによるフィルタリング

              サンプルコード


              #include <cv.h>
              #include <highgui.h>
              #include <stdio.h>

              int
              main (int argc, char **argv)
              {
                IplImage *src_img = 0, *dst_img;
                float data[] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
                  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
                };
                CvMat kernel = cvMat (1, 21, CV_32F, data);

                // (1)画像の読み込み
                if (argc >= 2)
                  src_img = cvLoadImage (argv[1], CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR);
                if (src_img == 0)
                  exit (-1);

                dst_img = cvCreateImage (cvGetSize (src_img), src_img->depth, src_img->nChannels);

                // (2)カーネルの正規化と,フィルタ処理
                cvNormalize (&kernel, &kernel, 1.0, 0, CV_L1);
                cvFilter2D (src_img, dst_img, &kernel, cvPoint (0, 0));

                // (3)処理画像の表示
                cvNamedWindow ("Filter2D", CV_WINDOW_AUTOSIZE);
                cvShowImage ("Filter2D", dst_img);
                cvWaitKey (0);

                cvDestroyWindow ("Filter2D");
                cvReleaseImage (&src_img);
                cvReleaseImage (&dst_img);

                return 0;
              }

              // (1)画像の読み込み
              コマンド引数で指定されたファイル名の画像(入力画像)をオープンし,関数 cvLoadImage()で読み込む.2番目の引数にCV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLORを指定することで,元画像のデプス,チャンネルを変 更せずに読み込む.

              // (2)カーネルの正規化と,フィルタ処理
              浮動小数点型配列dataの値を各要素とする,1×21;の行列をカーネルとするフィルタ処理を行う. 関数cvNormalize()によって,カーネルを正規化する. つまり,ここでは,絶対値のノルムが"1.0"になるように,配列の値を正規化している. そして,そのカーネルを利用(関数cvFilter2D()の3番目の引数に指定)して,フィルタ処理を行う. 関数cvFilter2D()の4番目の引数は,フィルタ対象ピクセルのカーネル内での相対位置を表しており, デフォルトはcvPoint(-1,-1)でありカーネル中心を指すが, 今回は,cvPoint(0,0)を指定することで,カーネルの左端を指している.

              // (3)処理画像の表示
              処理された画像を実際に表示し,何かキーが押されるまで待つ.

              実行結果例
                 

              ■ 境界線

              画像の境界をどのように扱うかは,多くの画像処理においてしばしば問題になる. 例えば,フィルタ処理において,フィルタが部分的に画像の外にはみだしてし まった場合,どのような画素値を仮定して利用するかによって,処理結果が異なる. OpenCVでは,画像をコピーし、その周りに境界線をつける処理を行う関数が用 意されており,IPL_BORDER_CONSTANT,およびIPL_BORDER_REPLICATをサポートしている. OpenCVで利用される関数は,IPL_BORDER_REPLICAT,つまり複製境界モードを 利用することが多々あるが,ユーザがそのような処理を望んでいない場合には, あらかじめ境界を定数値で埋めてから処理を行い,処理後の画像をクリッピングする事で 境界の扱いをコントロールできる.
              サンプル

              境界線の作成 cvCopyMakeBorder
              画像のコピーと境界の作成

              サンプルコード


              #include <cxcore.h>
              #include <cv.h>
              #include <highgui.h>

              int
              main (int argc, char **argv)
              {
                int i, offset = 30;
                IplImage *src_img = 0, *dst_img[2];

                // (1)画像の読み込み
                if (argc >= 2)
                  src_img = cvLoadImage (argv[1], CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR);
                if (src_img == 0)
                  exit (-1);

                for (i = 0; i < 2; i++)
                  dst_img[i] =
                    cvCreateImage (cvSize (src_img->width + offset * 2, src_img->height + offset * 2), src_img->depth,
                                   src_img->nChannels);

                // (2)境界線の作成
                cvCopyMakeBorder (src_img, dst_img[0], cvPoint (offset, offset), IPL_BORDER_REPLICATE);
                cvCopyMakeBorder (src_img, dst_img[1], cvPoint (offset, offset), IPL_BORDER_CONSTANT, CV_RGB (255, 0, 0));

                // (3)画像の表示
                cvNamedWindow ("Border_replicate", CV_WINDOW_AUTOSIZE);
                cvShowImage ("Border_replicate", dst_img[0]);
                cvNamedWindow ("Border_constant", CV_WINDOW_AUTOSIZE);
                cvShowImage ("Border_constant", dst_img[1]);
                cvWaitKey (0);

                cvDestroyWindow ("Border_replicate");
                cvDestroyWindow ("Border_constant");
                cvReleaseImage (&src_img);
                for (i = 0; i < 2; i++) {
                  cvReleaseImage (&dst_img[i]);
                }

                return 0;
              }

              // (1)画像の読み込み
              コマンド引数で指定されたファイル名の画像(入力画像)をオープンし,関数 cvLoadImage()で読み込む.2番目の引数にCV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLORを指定することで,元画像のデプス,チャンネルを変 更せずに読み込む. また,境界を作成するために,入力画像よりも大きな出力領域を確保する.

              // (2)境界線の作成
              関数cvCopyMakeBorder()によって,入力画像を出力画像にコピーし,さらに境界を作成する. 3番目の引数は,出力画像上にコピーされる入力画像の左上座標を表しており, 画像がコピーされない部分(今回は,上下左右の端から offsetピクセル分)が境界領域となる. 4番目の引数は,境界の種類を表しており,IPL_BORDER_REPLICATEが指定されると, 画像の上/下の端と左/右の端(画像領域の一番外側の値)を用いて境界線を生成する. また,4番目の引数に,IPL_BORDER_CONSTANT が指定されると, 境界はこの関数の最後(5番目)のパラメータとして渡された定数(今回は赤色)で埋められる.

              // (3)画像の表示
              処理された画像を実際に表示し,何かキーが押されるまで待つ.

              実行結果例
                   

              ■ 閾値処理

              画像にある閾値を設けて,画素値がその値よりも大きいか小さいかによって処理を変えたいという事はよくある. 例えば,単純な背景差分では,現画像と背景画像との画素値の差の絶対値がある閾値以下になるか否かで,背景か前景かを判断する. OpenCVでは,このような閾値処理を行うための関数,cvThreshold,および cvAdaptiveThreshold を用意してある.
              サンプル

              画像の二値化 cvThreshold, cvAdaptiveThreshold
              cvThreshold, cvAdaptiveThresholdを利用して,画像の二値化を行う

              サンプルコード


              #include <cv.h>
              #include <highgui.h>

              int
              main (int argc, char **argv)
              {
                IplImage *src_img = 0, *dst_img;
                IplImage *src_img_gray = 0;
                IplImage *tmp_img1, *tmp_img2, *tmp_img3;

                // (1)画像を読み込む
                if (argc >= 2)
                  src_img = cvLoadImage (argv[1], CV_LOAD_IMAGE_COLOR);
                if (src_img == 0)
                  return -1;

                tmp_img1 = cvCreateImage (cvGetSize (src_img), IPL_DEPTH_8U, 1);
                tmp_img2 = cvCreateImage (cvGetSize (src_img), IPL_DEPTH_8U, 1);
                tmp_img3 = cvCreateImage (cvGetSize (src_img), IPL_DEPTH_8U, 1);
                src_img_gray = cvCreateImage (cvGetSize (src_img), IPL_DEPTH_8U, 1);
                cvCvtColor (src_img, src_img_gray, CV_BGR2GRAY);
                dst_img = cvCloneImage (src_img);

                // (2)ガウシアンフィルタで平滑化を行う
                cvSmooth (src_img_gray, src_img_gray, CV_GAUSSIAN, 5);

                // (3)二値化:cvThreshold
                cvThreshold (src_img_gray, tmp_img1, 90, 255, CV_THRESH_BINARY);

                // (4)二値化:cvAdaptiveThreshold
                cvAdaptiveThreshold (src_img_gray, tmp_img2, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, 11, 10);

                // (5)二つの二値化画像の論理積
                cvAnd (tmp_img1, tmp_img2, tmp_img3);
                cvCvtColor (tmp_img3, dst_img, CV_GRAY2BGR);

                // (6)元画像と二値画像の論理積
                cvSmooth (src_img, src_img, CV_GAUSSIAN, 11);
                cvAnd (dst_img, src_img, dst_img);

                // (7)画像を表示する
                cvNamedWindow ("Threshold", CV_WINDOW_AUTOSIZE);
                cvShowImage ("Threshold", tmp_img1);
                cvNamedWindow ("AdaptiveThreshold", CV_WINDOW_AUTOSIZE);
                cvShowImage ("AdaptiveThreshold", tmp_img2);
                cvNamedWindow ("Image", CV_WINDOW_AUTOSIZE);
                cvShowImage ("Image", dst_img);
                cvWaitKey (0);

                cvDestroyWindow ("Threshold");
                cvDestroyWindow ("AdaptiveThreshold");
                cvDestroyWindow ("Image");
                cvReleaseImage (&src_img);
                cvReleaseImage (&dst_img);
                cvReleaseImage (&src_img_gray);
                cvReleaseImage (&tmp_img1);
                cvReleaseImage (&tmp_img2);
                cvReleaseImage (&tmp_img3);

                return 0;
              }

              // (1)画像を読み込む
              コマンド引数で指定されたファイル名の画像(入力画像)をオープンし,関数cvLoadImage()で読み込む. また,二値化を行うために入力画像をグレースケールに変換する.

              // (2)ガウシアンフィルタで平滑化を行う
              二値化を行う前に,ガウシアンフィルタで平滑化を行う.平滑化を行うことによって, 画像のノイズを減少させ,安定した(ノイズの少ない)二値化画像を得ることができる.

              // (3)二値化:cvThreshold
              関数cvThreshold()によって,画像の二値化処理を行う. この関数の最後の引数が,閾値処理の種類を表している. CV_THREASH_BINARYが指定されている場合は,

              src(x,y)>thresholdの場合は、dst(x,y) = max_value
                              それ以外は、           0
              となるように処理を行う.ここで,threshold(閾値)は3番目の引数で, max_value(最大値)は4番目の引数で,それぞれ指定されている. その他の手法を指定した場合の処理については,リファレンス マニュアルを参照のこと.
              // (4)二値化:cvAdaptiveThreshold
              関数cvAdaptiveThreshold()によって,画像の二値化処理を行う. 関数cvThreshold()では,すべてのピクセルにたいして同じ閾値をもって処理を行ったが, 関数cvAdaptiveThreshold()の場合は,ピクセル毎に使用する閾値が異なる. この関数の5番目の引数が,関数cvThresholdと同様に閾値処理の種類を表している. CV_THRESH_BINARYが指定されている場合は,

              src(x,y)>T(x,y)の場合は、dst(x,y) = max_value
                           それ以外は、           0
              となるように処理を行う.ここで,max_value(最大値)は3番目の引数で指定されている. また,T(x,y)は,各ピクセル毎に計算された閾値であり,4番目の引数で,そ の閾値の算出方法が指定される. CV_ADAPTIVE_THRESH_MEAN_C が指定された場合は,注目ピクセルの block_size×block_size 隣接領域の平均から,param1 を引いた値となり, block_sizeは6番目の引数で,param1は7番目の引数で,それぞれ指定される.
              // (5)二つの二値化画像の論理積
              二つの関数によって二値化された画像の論理積を計算する. つまり,二種類の二値化画像を合成し,3チャンネル画像へと変換する.

              // (6)元画像と二値画像の論理積
              (平滑化した)入力画像と二値化画像の要素毎の論理積を計算する. これにより,入力画像上に二値化画像が合成された画像を得る.

              // (7)画像を表示する
              それぞれの二値化画像,および入力画像と重ね合わせた画像を実際に表示し, 何かキーが押されるまで待つ.

              実行結果例
              入力画像    Threshold    AdaptiveThreshold    合成画像
                              
              画像の二値化(大津の手法) cvThreshold
              大津の手法を利用して閾値を決定し,画像の二値化を行う

              サンプルコード


              #include <cv.h>
              #include <highgui.h>

              int
              main (int argc, char **argv)
              {
                IplImage *src_img = 0, *dst_img;

                if (argc >= 2)
                  src_img = cvLoadImage (argv[1], CV_LOAD_IMAGE_GRAYSCALE);
                if (src_img == 0)
                  return -1;

                dst_img = cvCreateImage (cvGetSize (src_img), IPL_DEPTH_8U, 1);

                cvSmooth (src_img, src_img, CV_GAUSSIAN, 5);

                // (1)二値化(大津の手法を利用)
                cvThreshold (src_img, dst_img, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);

                cvNamedWindow ("Threshold", CV_WINDOW_AUTOSIZE);
                cvShowImage ("Threshold", dst_img);
                cvWaitKey (0);

                cvDestroyWindow ("Threshold");
                cvReleaseImage (&src_img);
                cvReleaseImage (&dst_img);

                return 0;
              }

              // (1)二値化(大津の手法を利用)
              前述の二値化と異なるのは,最後の引数(threshold type)に,CV_THRESHOLD_OTSU が加わっている点である. OpencvCV-1.0.0時点でのリファレンス マニュアルには記述がない(CVS版にはある)が, 関数cvThreshold()は,大津の手法と呼ばれる閾値決定手法を実装している. ここで利用される大津の手法とは,ある値の集合を二つクラスに分類する場合の,適切な閾値を決定する手法である. 二つのクラス内の分散とクラス間の分散を考え,これらの比が最小に(つまり,クラス内分散はできるだけ小さく,クラス間分散はできるだけ大きく) なるような閾値を求める. よって,3番目の引数(threshold)に与える値は利用されないので,適当な値を指定して良い.
              詳しくは,以下の文献を参考にすること.

              大津, "判別および最小2乗基準に基づく自動しきい値選定法", 電子通信学会論文誌, Vol.J63-D, No.4, pp.349-356, 1980.
              N. Otsu, "A threshold selection method from gray level histograms",IEEE Trans. Systems, Man and Cybernetics, 1979, Vol.9, pp.62-66


              /////
              iPhone開発メモ OpenCVで写真を漫画風に加工してみよう ?手法編? | permalink | comments(0) | - |

              iPhone 6 と Xperia Z3 Compact 比較

              0
                iPhone 6 と Xperia Z3 Compact 比較


                Xperia Z3 CompactとiPhone 6、どっちがどう優秀か。使い倒して比べてみた
                /////
                Xperia Z3 Compact and iPhone 6, Which is how excellent. I tried than to defeat use

                Awake in alarm smartphone, check today's schedule, the smartphone that ...... Check the timetable of the train beyond the realm of "next to the skin using" become "skin itself" gadgets. You a hard time to get used to the operation, but once you get used same as the hands and feet. With glue that ...... or model I a strange successor machine can be used in the same sense also the time of, you or was co author has also transfer to the "iPhone from the iPhone".

                However, Android smartphone, especially Japanese manufacturers If you are constantly evolving at a gallop in order along the expectations of people such as "Atarashiimonozuki" "multi-function-oriented", and take in hand suddenly the new model, Glatt to transfiguration that beyond recognition would come. Above all, Xperia Z3 Compact screen size (4.6 inches) of Sony, which also appeared in Japan this fall even for iPhone 6, would Sumaho that suggests that intense rivalry.

                Sumaho select will "try to touch it" is fundamental. and if you want to do it on the actual hand and determines Kana ...... in the iPhone 6 "truly" also there "there?" is also there. Point to be may point and mind that it try using Xperia Z3 Compact also what days was found. Compared with the iPhone 6, and what about do me Xperia Z3 Compact? Actually as a user touches the two, I tried to consider from various angles.

                Size Xperia Z3 Compact is that fits comfortably in the hand

                Screen size is also the same in weight also Donpisha, Xperia Z3 Compact and iPhone 6, such as twins. However, it is separate from the impression of when to hand the actual equipment. Before iPhone 6 in which the liquid crystal becomes a 4 → 4.6 from the product of the iPhone 5S is, in large as also proportional to the size of the body. The only feeling is ingrained in the body in the app many years of association, such as Safari and Mail, thumb is difficult to reach in the upper right corner when you single hand? Sense of discomfort There is also little.

                Xperia Z3 Compact remains of body size reminiscent of the iPhone 4, is the feeling that the liquid crystal is spread in 4.6-inch to 3.5-inch iPhone 4. By single hand only can cover every corner of the screen thumb, there is also a grip that it will not come out Suppo.

                When the ruler of "nicely in hand", Xperia Z3 Compact might be one step ahead. Bottom in flat, Ryoyoko soft feel made of resin. Even for small women hand, it is the size of the safe.

                If you say in terms of appearance, iPhone 6 with a reputation for the design, sophisticated form rounded indeed. The color variations Silver without change from iPhone 5S, Gold, in space gray of three different colors, basic and conservative tint tired does not come. And against, Xperia Z3 Compact is white, green, orange, four colors of black. Especially green and orange "water surface that shines refreshing" Each delicate have expressed the "vivid sunset reflected on the water surface" color is beautiful. Color preference is each person, but it is an attractive color tint that can claim the personality is available.

                Camera and high-resolution playback

                Probably Xperia if you choose the Android smartphone, a well-established Xperia Z3 series that at the forefront among you there. Xperia Z3 Compact is equipped with a "premium Random auto" shooting functions, such as a full-fledged digital camera, automatically determine the scene, you can take the time and effort rather than pretty pictures. It also supports camera shake correction.

                In the case of iPhone 6, then you have a reputation in the balanced quality of balance, and I think better of iPhone 6 Some people look beautiful. Just Xperia Z3 Compact can be done also fine manual adjustment. In addition, since the Xperia Z3 Compact is compatible with ISO12800, dark and without a flash even in the room, take a few pictures of bright noise, there are strengths that. This point might be Sony unique is also the "camera manufacturer".
                As the selling of iPhone 6 in camera-related enjoyment of video spread "time-lapse". The unique iPhone 6 be able to enjoy its unique movement with friends by market share in SNS.

                It has become 1 weather, reproducibility of color in photographs taken in the two models. Xperia Z3 Compact to save in the real truth of color but, iPhone 6 seems to be equipped with initial settings to save color darker than the real thing. I am happy for those who contrast prefers a dark image. However you will not be able to return the color to that of the remains real. In terms of reproducibility would be tactics to Xperia Z3 Compact.

                And, indeed cause groan with Walkman Sony Hi-Res (※) corresponding to the playback. On that can be played even without an external amplifier if there is a high-resolution sound source, there is also a function and noise canceling function that boosts the sound quality close to the hi-res even MP3 of Futsu, we Gunto pull the iPhone 6.

                But, still high-resolution / noise-canceling headphones or speakers such as optional equipment is necessary. Since the built-in speakers are also up performance, I can enjoy the music well enough to be alone.
                ※ can be found in high resolution (high resolution) and high-resolution. It becomes granular sound information in a large amount of high-resolution source than CD, it is possible to express the realism with air feeling that can not be played on CD.

                A "multi-functional" Xperia Z3 Compact

                Let's look at the other functional aspects.
                The characteristics of the iPhone 6 There is a fingerprint authentication. It is the wrong place to hit with it or when tracing the point you can hit the number, the lock can not be released at once when you want to open in a hurry, My God than everyone has experienced. In that respect, it is not annoying it is possible to unlock the smart one and only fingerprint.

                For iPhone 6 is a global model, Xperia Z3 Compact is the impression that "the Galapagos in a good way." Yes Seg inherited from successive Xperia, there is also a mobile wallet feature that will not let go and use once, also is equipped to "gloves mode" that can be manipulated, leaving the gloves for the coming cold season. So more "waterproof", perfect to accompany the women of sitz bath. Delicate customization snuggled in Japan of infrastructure and living environment is a place is welcome. This is not parted anymore!

                "Fingerprint authentication", "time-lapse" such as whether iPhone 6 that is installed in the global model, mobile wallet, hi-res music player, high-sensitivity camera, gloves mode such as Japan's Xperia or that we have continued to evolve to suit the user. Only to each attractive terminal, and try to comparison can be taken by the hand by all means, respectively, such as over-the-counter?
                /////
                Xperia Z3 CompactとiPhone 6、どっちがどう優秀か。使い倒して比べてみた

                スマホのアラームで目を覚まし、今日のスケジュールをチェックし、電車の時刻表を調べ……というスマホは「肌身離さず使う」の域を超えて「肌そのもの」になるガジェット。操作に慣れるまでに苦労しますが、慣れてしまえば手足と同じ。機種変のときも同じ感覚で使える後継機でいいか……というノリで、筆者も「iPhoneからiPhone」へ乗り換えてきたクチだったりします。

                しかし、Androidスマホ、特に日本のメーカーは「新しいもの好き」「多機能重視」といった人々の期待に沿うべく駆け足で改良を重ねていて、ふと新機種を手に取ると、見違える変貌にグラっと来てしまう。中でも、この秋に日本でも登場したソニーのXperia Z3 Compactは画面サイズ(4.6インチ)もiPhone 6に対して、強烈なライバル意識がうかがえるスマホでしょう。

                スマホ選びは「触ってみること」が基本です。iPhone 6で決まりかな……と実際に手にしてみれば「さすが」もあり「あれ?」もあり。Xperia Z3 Compactも何日か使ってみることで良い点や気になる点が見つかりました。iPhone 6とくらべて、Xperia Z3 Compactってどうなんだろう? 実際に2つを触ったユーザーとして、様々な角度から検討してみました。

                Xperia Z3 Compactは手にすっぽりと収まるサイズ

                画面サイズも重さもドンピシャに同じで、双子のようなXperia Z3 CompactとiPhone 6。しかし、実機を手にすると別ものの印象です。前製品のiPhone 5Sから液晶が4→4.6となったiPhone 6は、本体のサイズも比例するように大型に。Safariやメールなどのアプリは長年の付き合いで感覚が体に染み付いてるだけに、片手持ちすると親指が右上に届きづらい?的な違和感も少しあり。

                Xperia Z3 CompactはiPhone 4を思わせる本体サイズのまま、液晶がiPhone 4の3.5型から4.6型に広がった感じです。片手持ちして親指だけで画面の隅々までカバーでき、スッポ抜けないグリップ感もあります。

                「手にしっくり」という物差しにすると、Xperia Z3 Compactが一歩リードかもしれません。底面もフラットで、両横はソフトな感触の樹脂製。手の小さい女性にとっても、安心のサイズです。

                見た目の面で言うと、デザインに定評のあるiPhone 6、丸みを帯び洗練されたフォルムはさすが。カラーバリエーションはiPhone 5Sから変更なくシルバー、ゴールド、スペースグレイの3色展開で、飽きが来ないベーシックかつ保守的な色味。対し、Xperia Z3 Compact はホワイト、グリーン、オレンジ、ブラックの4色。特にグリーンとオレンジはそれぞれ「爽やかに光る水面」「鮮やかに水面に映る夕日」を表現していて繊細な色味が美しい。色の好みは人それぞれですが、個性を主張できる色味が用意されていることは魅力です。

                カメラとハイレゾ再生

                Androidスマホを選ぶならXperiaでしょ、と定評のある中でも最先端に位置するXperia Z3シリーズ。Xperia Z3 Compactは「プレミアムおまかせオート」撮影機能を搭載しており、本格的なデジカメのように、自動的にシーンを判別して、手間なくキレイな写真を撮ることができます。手ブレ補正にも対応。

                iPhone 6の場合、バランスの取れた画質には定評がありますし、iPhone 6の方がキレイに見えるひともいるかと思います。ただXperia Z3 Compactはマニュアルで細かな調整も行うことができます。またXperia Z3 Compact はISO12800に対応しているため、暗い室内でもフラッシュを使わず、明るくノイズの少ない写真が撮れる、という強みがあります。この点は「カメラメーカー」でもあるソニーならではかもしれません。
                カメラ関連でのiPhone 6のウリとしては動画の楽しみ方が広がる「タイムラプス」。SNSでシェアして友人同士でその独特な動きを楽しむことができるのはiPhone 6ならでは。

                1点気になるのが、2機種で撮った写真における色味の再現性。Xperia Z3 Compactは実物ありのままの色味で保存しますが、iPhone 6は実物よりも色味濃く保存する初期設定が備わっているようです。コントラストが濃い画像を好む方には嬉しいですね。ただし色味を実物ままのものに戻すことは出来ません。再現性の点ではXperia Z3 Compactに軍配でしょう。

                そして、さすがウォークマンのソニーと唸らせるのがハイレゾ(※)再生への対応。ハイレゾ音源があれば外付けアンプなしでも再生できる上に、フツーのMP3でもハイレゾに近い音質に引き上げる機能やノイズキャンセリング機能もあり、iPhone 6をぐんと引き離しています。

                が、やはりハイレゾ/ノイズキャンセリング対応のヘッドホンやスピーカーといったオプション機器は必要。内蔵のスピーカーも性能が上がっているので、単体でも音楽を十分に楽しめたりはします。
                ※ハイレゾとはハイレゾリューション(高解像度)のこと。 CDよりも情報量の多いハイレゾ音源ではきめ細やかな音になり、CDでは再生できない空気感と臨場感を表現する事ができる。

                「多機能」なXperia Z3 Compact

                その他の機能面をみてみましょう。
                iPhone 6の特徴としては指紋認証があります。番号を打ったり点をなぞったりするとつい打つ場所を間違えて、急いで開きたいときに1回でロックが解除できない、なんてことは誰しもが経験しているのでは。その点、唯一無二の指紋でスマートにロック解除できるので煩わしくありません。

                グローバルモデルであるiPhone 6に対して、Xperia Z3 Compactは「いい意味でガラパゴス」という印象です。歴代Xperiaから受け継いだワンセグあり、一度使うと手放せなくなるおサイフケータイ機能もあり、これからの寒い季節に手袋をしたまま操作できる「手ぶくろモード」までも搭載。さらに「防水」なので、女性の半身浴のお供にも最適。日本のインフラや住環境に寄り添った細やかなカスタマイズが有難いところです。これはもう手放せない!

                グローバルモデルで「指紋認証」「タイムラプス」などが搭載されているiPhone 6か、おサイフケータイ・ハイレゾ音楽プレーヤー・高感度カメラ・手袋モードなど日本のユーザーに合わせて進化を続けてきたXperiaか。それぞれ魅力ある端末だけに、ぜひそれぞれ店頭などで手に取って比較してみては?
                ////
                iPhone 6 と Xperia Z3 Compact 比較 | permalink | comments(0) | - |

                Android用開発メモ  OpenCV for Android入門 ? カメラ編

                0
                  Android用開発メモ OpenCV for Android入門 ? カメラ編

                  OpenCV for Android入門 ? カメラ編

                  ここ最近はAndroidアプリ開発の勉強をしています。今回はOpenCVでデバイスのカメラを利用した動画像処理を試してみました。

                  技術Wikiの方にもAndroid関連のメモを残しています。
                  * Android - Tech Note
                  http://rest-term.com/technote/index.php/Android

                  * OpenCV for Android - Tech Note
                  http://rest-term.com/technote/index.php/OpenCV%20for%20Android



                  Portions of this page are modifications based on work created and shared by Google and used according to terms described in the Creative Commons 3.0 Attribution License.


                  * OpenCV4Android SDK 2.4.4 (今回はJava APIのみ使用)
                  * 検証デバイス: Galaxy S2 LTE(Android 2.3.6), AQUOS PHONE ZETA SH-02E(Android 4.0.4)
                  * 開発機: MacBook Air Mid 2012

                  基本的にAndroid 2.2(API Level 8)でも動作するように確認しながら進めていきたいと思います。

                  環境構築とサンプルアプリのビルドまでの手順は、公式サイトにスクリーンショット付きで丁寧に説明してくれています。Windows 7用のガイドですが、ほぼEclipse上での手順説明なのでMacでもパスを読み替える程度で簡単にできました。僕の場合はSDKを ~/Library/OpenCV2.4.4 以下にインストールしておきました。
                  * OpenCV4Android SDK ? OpenCV 2.4.4 documentation
                  http://docs.opencv.org/doc/tutorials/introduction/android_binary_package/O4A_SDK.html

                  OpenCV Managerについて
                  OpenCV4Android SDK 2.4.2からライブラリ自体はOpenCV Managerというアプリで管理する構成に変更されました。これまでのようにアプリのバイナリにライブラリをコピーするのは無駄だからというのが主な理由とのことです。デバイスのアーキテクチャをOpenCV Managerが判別して適切なライブラリをインストールしてくれます。
                  using OpenCV Manager
                  using OpenCV Manager, feel the difference

                  確かにサイズは大きく減っていますね。ただ、アプリのユーザーにOpenCVを意識させることになるので(OpenCV Managerを別途インストールしてもらう必要がある)その辺りは微妙な気はしますけど。実際にAndroid端末にOpenCV ManagerをGoogle Playからインストール、実行してみました。ライブラリのインストールが成功すると以下のような画像が見られます。
                  opencv_manager_aquosphone
                  カメラアクセスの許可
                  OpenCVの使い方の前に、けっこう忘れがちなカメラアクセスの許可設定を行っておきます。AndroidManifest.xml ファイルを以下のように編集します。

                  XHTML


                  <uses-permission android:name="android.permission.CAMERA"/>
                  <uses-feature android:name="android.hardware.camera" android:required="false"/>
                  <uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>
                  以下、OpenCVでデバイスのカメラを利用した動画像処理を行う際の基本フローを整理していきます。

                  1. レイアウトの定義
                  OpenCVではカメラを扱う2つのクラス JavaCameraView と NativeCameraView が提供されています(両者の違いは後述)。これのどちらかをビューとしてXMLレイアウトファイル(res/layout/*.xml)に配置します。

                  XHTML


                  <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                      xmlns:tools="http://schemas.android.com/tools"
                      xmlns:opencv="http://schemas.android.com/apk/res-auto"
                      android:layout_width="match_parent"
                      android:layout_height="match_parent"
                      android:keepScreenOn="true"
                      tools:context=".MainActivity" >
                      
                    <org.opencv.android.JavaCameraView
                      android:id="@+id/camera_view"
                      android:layout_width="fill_parent"
                      android:layout_height="fill_parent"
                      android:visibility="visible"
                      opencv:camera_id="any"
                      opencv:show_fps="true" />
                   
                  </RelativeLayout>
                  ここでは JavaCameraView を配置しています。利用できる属性は camera_id (any/front/back) と show_fps (true/false) です。camera_id には利用するカメラ(フロント/バックカメラ)を指定するのですが、any を指定しておけば自動的にカメラを判別してくれます。show_fps を true にすると画面左上にFPSと画角が表示されます。デバッグ時は有効にしておくと良いです。

                  2. OpenCVライブラリの読み込みと初期化
                  OpenCV Managerを使う場合、Activityの中でOpenCVライブラリの読み込みを行う OpenCVLoader.initAsync メソッドを呼び出す必要があります。このメソッドは非同期で実行されるので、読み込み完了後にUIスレッドで呼ばれるコールバックメソッドも併せて実装しておきます。

                  Java


                  public class MainActivity extends Activity implements CvCameraViewListener {
                      // カメラビューのインスタンス
                      // CameraBridgeViewBase は JavaCameraView/NativeCameraView のスーパークラス
                      private CameraBridgeViewBase mCameraView;
                   
                      // ライブラリ初期化完了後に呼ばれるコールバック (onManagerConnected)
                      // public abstract class BaseLoaderCallback implements LoaderCallbackInterface
                      private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
                          @Override
                          public void onManagerConnected(int status) {
                              switch (status) {
                              // 読み込みが成功したらカメラプレビューを開始
                              case LoaderCallbackInterface.SUCCESS:
                                  mCameraView.enableView();
                                  break;
                              default:
                                  super.onManagerConnected(status);
                                  break;
                              }
                          }
                      };
                   
                      @Override
                      protected void onCreate(Bundle savedInstanceState) {
                          super.onCreate(savedInstanceState);
                          setContentView(R.layout.activity_main);
                          // カメラビューのインスタンスを変数にバインド
                          mCameraView = (CameraBridgeViewBase) findViewById(R.id.camera_view); 
                          // リスナーの設定 (後述)
                          mCameraView.setCvCameraViewListener(this);
                      }
                   
                      @Override
                      protected void onResume() {
                          super.onResume();
                          // 非同期でライブラリの読み込み/初期化を行う
                          // static boolean initAsync(String Version, Context AppContext, LoaderCallbackInterface Callback)
                          OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_4, this, mLoaderCallback);
                      }
                  JavaCameraViewとNativeCameraViewの違い
                  JavaCameraView と NativeCameraView は両方とも CameraBridgeViewBase のサブクラスです。
                  opencv4android_cameraview
                  JavaCameraView は android.hardware.Camera を利用した実装、NativeCameraView はOpenCVの VideoCapture を利用した実装という違いがあります。安定性という観点ではAndroid SDKの機能を利用した JavaCameraView の方が安定しているかと思われますが、そんなに気にしなくて大丈夫でしょう。

                  CvCameraViewListenerインタフェースの実装
                  CvCameraViewListener または CvCameraViewListener2 インタフェースの以下の3つのメソッドを実装します。
                  * onCameraViewStarted
                  * onCameraViewStopped
                  * onCameraFrame
                  3つめの onCameraFrame メソッドに任意の画像処理を実装することになります。また、CvCameraViewListener と CvCameraViewListener2 の違いは onCameraFrame の引数のみで、onCameraViewStarted および onCameraViewStopped は共通です。

                  Java


                  @Override
                  public void onCameraViewStarted(int width, int height) {
                  // カメラプレビュー開始時に呼ばれる
                  }
                   
                  @Override
                  public void onCameraViewStopped() {
                  // カメラプレビュー終了時に呼ばれる
                  }
                      
                  // CvCameraViewListener の場合
                  @Override
                  public Mat onCameraFrame(Mat inputFrame) {
                  // フレームをキャプチャする毎(30fpsなら毎秒30回)に呼ばれる
                  }
                      
                  // CvCameraViewListener2 の場合
                  @Override
                  public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
                  }
                  CvCameraViewFrame インタフェースは以下のようになっています。CvCameraViewListener2.onCameraFrame ではこのインタフェースを実装した JavaCameraFrame/NativeCameraFrame のインスタンスが渡されます。

                  Java


                  public interface CvCameraViewFrame {
                      // 4チャンネルRGBAカラーのMatインスタンスを返す
                      public Mat rgba();
                   
                      // 1チャンネルグレースケールのMatインスタンスを返す
                      public Mat gray();
                  };
                  キャプチャしたフレーム画像をそのままカメラプレビューに表示させるには、CvCameraViewListener.onCameraFrame の場合は引数の inputFrame をそのまま return し、CvCameraViewListener2.onCameraFrame の場合は inputFrame.rgba() を return します。

                  OpenCVでカメラを利用した動画像処理を行う際の基本フローは以上になります。ここまでのまとめとして、カメラから取得したフレーム画像を線画風に変換する処理のサンプルコードを載せておきます。

                  Java


                  // package, import文は省略
                   
                  public class MainActivity extends Activity implements CvCameraViewListener2 {
                      private CameraBridgeViewBase mCameraView;
                      private Mat mOutputFrame;
                   
                      private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
                          @Override
                          public void onManagerConnected(int status) {
                              switch (status) {
                              case LoaderCallbackInterface.SUCCESS:
                                  mCameraView.enableView();
                                  break;
                              default:
                                  super.onManagerConnected(status);
                                  break;
                              }
                          }
                      };
                   
                      @Override
                      protected void onCreate(Bundle savedInstanceState) {
                          super.onCreate(savedInstanceState);
                          setContentView(R.layout.activity_main);
                          mCameraView = (CameraBridgeViewBase)findViewById(R.id.camera_view);
                          mCameraView.setCvCameraViewListener(this);
                      }
                      
                      @Override
                      public void onPause() {
                          if (mCameraView != null) {
                              mCameraView.disableView();
                          }
                          super.onPause();
                      }
                   
                      @Override
                      protected void onResume() {
                          super.onResume();
                          OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_4, this, mLoaderCallback);
                      }
                      
                      @Override
                      public void onDestroy() {
                          super.onDestroy();
                          if (mCameraView != null) {
                              mCameraView.disableView();
                          }
                      }
                      
                      @Override
                      public void onCameraViewStarted(int width, int height) {
                          // Mat(int rows, int cols, int type)
                          // rows(行): height, cols(列): width
                          mOutputFrame = new Mat(height, width, CvType.CV_8UC1);
                      }
                   
                      @Override
                      public void onCameraViewStopped() {
                          mOutputFrame.release();
                      }
                   
                      @Override
                      public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
                          // Cannyフィルタをかける
                          Imgproc.Canny(inputFrame.gray(), mOutputFrame, 80, 100);
                          // ビット反転
                          Core.bitwise_not(mOutputFrame, mOutputFrame);
                          return mOutputFrame;
                      }
                  }
                  opencv4android_linedraw
                  opencv4android line drawing

                  Galaxy S2 LTEでだいたい15fpsほどで動作しました。スマートフォンでもこの速度が出せるのには驚きました。
                  今回はAndroidでOpenCVを使ったアプリ開発を試してみましたが、特に難しいところもなくスムーズに進めることができました。OpenCVがAndroidをサポートした当初はバグだらけで大変だったらしいですが、現在はとても使いやすくなっているので昔挫折してしまった人はリベンジしてみてください。これからも引き続きいろいろ試していきたいです。

                  * 参考
                  opencv.org - Home > PLATFORMS > ANDROID
                  Android | Blog はじめました
                  Android用開発メモ  OpenCV for Android入門 ? カメラ編 | permalink | comments(0) | - |

                  Android用開発メモ  AndroidでOpenCVを使ってみよう

                  0
                    AndroidでOpenCVを使ってみよう

                    AndroidでOpenCVを使ってみよう


                    第1回 開発ツールの用意
                    OpenCVはオープンソースの画像処理ライブラリです。
                    静止画の処理(イメージングと呼ばれることが多い)だけではなく、OpenCVのCVはComputer Visionの略である通り、画像解析などの処理も豊富で、その応用範囲は多岐にわたっています。 画像処理のコードを一から作成するより、まずはOpenCVに使いたい処理が用意されている場合は、そちらを使った方が効率的でしょう。 ただし、OpenCVはC/C++で記述されているので、利用にはC/C++のプログラミング知識が必要です。
                    ところで、iPhoneやAndroidのアプリ開発も注目されていますね。
                    Androidは搭載デバイス的にも面白いハードウエアだと思います。
                    Androidの開発環境はJavaがベースです。OpenCVを利用するにはNDKと言うC++ネイティブ用のSDKが必要でしたし、その敷居は高いものでした。
                    最近になり、OpenCV for Androidと言うJavaから利用できるOpenCVが登場し、敷居が敷居が下がりました。
                    ここではそのOpenCV for Androidを使ってビデオキャプチャ画像に簡単な処理を行うプログラミングを扱います。
                    必要な開発ツール

                    JDK6.0
                    Eclipse
                    Android SDK
                    Android Development Tool (ADT)
                    OpenCV packege for Android
                    JDK6.0 / Eclipse

                    上記をそれぞれインストールしても良いですが、Eclipseの日本語化プラグインPleiadesをインストールするのがお勧めです。
                    Pleiadesのダウンロード先
                    「Eclipse 3.7 Indigo Pleiades All in One」 or 「Eclipse 3.6 Helios Pleiades All in One」が良いでしょう。
                    All in OneにはJDK6.0も含まれています。
                    またグレードですが「Java」でもOKなのですが、OpenCVを使っていくと将来NDKなどが必要になってくることもあるので、 最初からC/C++(CDT)が含まれているUltimateを選んでおくと良いかもしれません。(HDに余裕がある場合)
                    Full All in One (JRE あり)版とStandard All in One (JRE なし) 版がありますが、「お勧め」となっているFull All in One (JRE あり)の方が無難でしょう。
                    インストールはダウンロードしたZIPを解凍し、作成されたフォルダをお好きな場所に移動するだけです。
                    eclipseフォルダの下にeclipse.exeがあるので、それをダブルクリックするとEclipseが立ち上がります。
                    ショートカットを作成しておくと便利でしょう。
                    Android SDK

                    ここからダウンロードします。
                    Windowsの場合はインストーラータイプの方が便利です。
                    インストールが終わったら、Eclipseを立ち上げます。 
                    「ウィンドウ」メニューの「設定」をクリックして、設定ダイアログの左の一覧から「Android」を選択します。
                    「SDKロケーション」にAndroid SDKをインストールしたパスを指定します。 
                    インストーラータイプでインストールした場合は、 
                    C:¥ProgramFiles¥Android¥android-sdk
                    のようになっているかと思います。(OSが64bitの場合はProgram Files (x86)の下に入ります)
                    次に「ウィンドウ」メニューの「Android SDK Manager」を選択します。
                    ダイアログ上のリストから、基本的にはすべてを選択してインストールすれば良いですが、 OpenCVを扱うには、最低でも Android SDK Tools, revision12 より新しいもの SDK Platform Android 2.2, API 8,revision 2 が必要になります。
                    続けて「ウィンドウ」メニューの「AVD Manager」を選択します。
                    ダイアログ上の「新規」ボタンを押し、PC上で動作するエミュレータを作成します。 OpenCVではAndroid 2.2以降である必要あります。以下の様な例を一つ作っておくと良いでしょう。

                    名前: sdk2.2
                    ターゲット:Android 2.2 - API Level 8
                    SD Card サイズ: 64 MiB
                    Skin ビルトイン: WVGA800
                    ADT

                    Eclipseの「ヘルプ」メニューの「新規ソフトウエアのインストール...」を選択します。
                    インストールダイアログ上の「追加(A)...」ボタンを押します。
                    リポジトリーの追加ダイアログが表示されますので、

                    名前: ADT Plugin
                    ロケーション: https://dl-ssl.google.com/android/eclipse/

                    を入力し、「OK」ボタンを押します。
                    インストールダイアログのリストから「Developer Tools」をチェックして「次へ」ボタンを押します。
                    次の画面も「次へ」ボタンを押します。
                    ライセンスの画面で同意し、「完了」ボタンを押すとプラグインのインストールが始まります。
                    再起動の確認が出たら、Eclipseを再起動してください。
                    OpenCV for Android

                    OpenCV for Androidはここから入手します。
                    ページの中程に「download」があると思います。
                    「アンドロイド上でOpenCVアプリの開発をするには2つの基本的な方法がある」と書かれています。 ここでは「お勧め」となっている、プレビルドのパッケージの方をダウンロードしましょう。
                    「prebuilt OpenCV package」のリンクをクリックするとSourceForgeに飛びます。
                    OpenCV-2.3.1-android-bin.tar.bz2をダウンロードしてください。
                    tar.bz2と言うあまり使わない(?)ようなアーカイブファイルになっていますが、Lhaplusなどで解凍できると思います。 解凍してできたフォルダをお好きなところに移動してください。
                    次に、Eclipsを立ち上げます。
                    ワークスペースは皆さんがお使いのワークスペースでOKです。
                    「ファイル」メニューの「インポート」を選択します。
                    「インポート」ダイアログで「一般」「既存プロジェクトをワークスペースへ」を選択し「次へ」ボタンを押します。
                    ルートディレクトリの選択のラジオボタンを選び、「参照」ボタンを押し、先ほどのOpenCVのフォルダの下にある「OpenCV-2.3.1」フォルダを選択します。
                    プレビルド版を選んでいるので、インストールはこれで完了です。
                    次回の記事でカメラキャプチャーのプログラムを作成します。 



                    ////
                    第2回 カメラキャプチャの作成
                    まずは、Eclipseを立ち上げます。
                    「ファイル」メニューの「新規」「Androidプロジェクト」を選択します。
                    プロジェクト名に「OpenCV_Capture」と入力し「次へ」ボタンを押します。
                    ビルドターゲットは「Android 2.2」にチェックを入れ「次へ」ボタンを押します。
                    パッケージ名に「com.pronowa.android.OpenCV_Capture」と入力し「完了」ボタンを押します。
                    パッケージ・エクスプローラーに「OpenCV_Capture」プロジェクトが追加されます。

                    Androidプロジェクトは初期の状態ですと内蔵カメラが利用できなくなっています。 利用できる様にするには、AndroidManifest.xmlに記述を追加する必要があります。
                    パッケージ・エクスプローラーの「AndroidManifest.xml」をダブルクリックするとAndroid Manifestの編集ができる様になります。 xmlファイルを直接編集しますので、「AndroidManifest.xml」タブを選択してください。 初期の状態は以下になっていると思います。
                    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
                        package="com.pronowa.android.OpenCV_Capture"
                        android:versionCode="1"
                        android:versionName="1.0" >

                        <uses-sdk android:minSdkVersion="8" />

                        <application
                            android:icon="@drawable/ic_launcher"
                            android:label="@string/app_name" >
                            <activity
                                android:label="@string/app_name"
                                android:name=".OpenCV_CaptureActivity" >
                                <intent-filter >
                                    <action android:name="android.intent.action.MAIN" />

                                    <category android:name=
                                      "android.intent.category.LAUNCHER" />
                                </intent-filter>
                            </activity>
                        </application>

                    </manifest>
                    これを以下の様にしてください。

                    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
                        package="com.pronowa.android.OpenCV_Canny"
                        android:versionCode="1"
                        android:versionName="1.0" >

                        <uses-sdk android:minSdkVersion="8" />

                        <application
                            android:icon="@drawable/ic_launcher"
                            android:label="@string/app_name" >
                            <activity
                                android:label="@string/app_name"
                                android:name=".OpenCV_CannyActivity"
                                android:screenOrientation="landscape" >

                                <intent-filter >
                                    <action android:name="android.intent.action.MAIN" />

                                    <category android:name=
                                      "android.intent.category.LAUNCHER" />
                                </intent-filter>
                            </activity>
                        </application>

                        <uses-permission android:name="android.permission.CAMERA"/>
                        <uses-feature android:name="android.hardware.camera" />
                        <uses-feature android:name="android.hardware.camera.autofocus" />

                    </manifest>
                    android:screenOrientation="landscape" はキャプチャー画面を横長(Androidを横向けに持った状態)に指定します。

                    <uses-permission android:name="android.permission.CAMERA"/>
                    <uses-feature android:name="android.hardware.camera" />
                    <uses-feature android:name="android.hardware.camera.autofocus" />
                    の3行でカメラを利用できる様に指定します。
                    次に「OpenCV_Capture」プロジェクトを右クリックして「プロパティ」を選択します。
                    「Android」を選択し「ライブラリー」のところにある「追加」ボタンをおします。
                    「プロジェクトの選択」ダイアログから「OpenCV-2.3.1」を選択し、「OK」ボタンを押します。 これでOpenCVのライブラリが利用できる様になります。
                    プロジェクトの下にあるsrcを展開し、com.pronowa.android.OpenCV_Captureを右クリックします。
                    「新規」「クラス」を選択します。
                    ダイアログで、名前に「OpenCV_CaptureView」と入力します。
                    スーパークラスの「参照」ボタンを押して、「型を選択してください」の下のエディットボックスに「SurfaceView」と入力します。
                    一致する項目に「SurfaceView」と表示されたら、それを選択状態にして「OK」ボタンを押します。
                    インターフェイス「追加」ボタンを押して、「インターフェイスを追加してください」の下のエディットボックスに「Callback」と入力します。
                    リストから「android.vew.SurfaceHolder:Callback」を選択して「OK」ボタンを押します。
                    もう一度「追加」ボタンを押して、今度は「Runnable」と入力します。
                    リストから「java.lang.Runnable」を選択して「OK」ボタンを押します。
                    パッケージ・エクスプローラーのOpenCV_CaptureActivity.javaをダブルクリックしエディタを開き、以下のコードを入力します。
                    package com.pronowa.android.OpenCV_Capture;

                    import android.app.Activity;
                    import android.os.Bundle;
                    import android.view.Window;

                    public class OpenCV_CaptureActivity extends Activity
                    {
                        @Override
                        public void onCreate(Bundle savedInstanceState)
                        {
                            super.onCreate(savedInstanceState);
                            requestWindowFeature(Window.FEATURE_NO_TITLE);
                            setContentView(new OpenCV_CaptureView(this));
                        }
                    }
                    Eclipseが自動でコード生成をしているので、setContenViewを書き換えるだけでOKです。
                    次にOpenCV_CaptureView.javaをダブルクリックして、エディタを開き、各メソッドの中身を記述します。
                    package com.pronowa.android.OpenCV_Capture;

                    import java.util.List;

                    import android.content.Context;
                    import android.view.SurfaceHolder;
                    import android.view.SurfaceView;
                    import android.graphics.Bitmap;
                    import android.graphics.Canvas;

                    import org.opencv.android.Utils;
                    import org.opencv.core.Mat;
                    import org.opencv.highgui.Highgui;
                    import org.opencv.highgui.VideoCapture;
                    import org.opencv.core.Size;

                    class OpenCV_CaptureView
                        extends SurfaceView implements SurfaceHolder.Callback, Runnable
                    {
                        private SurfaceHolder       m_surfaceHolder;
                        private VideoCapture        m_videoCapture;
                        private Mat                 m_rgbaMat;

                        public OpenCV_CaptureView(Context context)
                        {
                            super(context);
                            m_surfaceHolder = getHolder();
                            m_surfaceHolder.addCallback(this);
                        }

                        public void surfaceChanged(
                            SurfaceHolder holder, int format, int width, int height)
                        {
                            synchronized (this)
                            {
                                if (m_videoCapture != null && m_videoCapture.isOpened())
                                {
                                    List<Size> sizes =
                                        m_videoCapture.getSupportedPreviewSizes();
                                    int frameWidth = width;
                                    int frameHeight = height;

                                    double minDifference = Double.MAX_VALUE;
                                    for (Size size : sizes)
                                    {
                                        if (Math.abs(size.height - height) < minDifference)
                                        {
                                            frameWidth = (int)size.width;
                                            frameHeight = (int)size.height;
                                            minDifference = Math.abs(size.height - height);
                                        }
                                    }

                                    m_videoCapture.set(
                                        Highgui.CV_CAP_PROP_FRAME_WIDTH, frameWidth);
                                    m_videoCapture.set(
                                        Highgui.CV_CAP_PROP_FRAME_HEIGHT, frameHeight);
                                }
                                m_rgbaMat = new Mat();
                            }
                        }

                        public void surfaceCreated(SurfaceHolder holder)
                        {
                            m_videoCapture = new VideoCapture(Highgui.CV_CAP_ANDROID);
                            if (m_videoCapture.isOpened())
                            {
                                (new Thread(this)).start();
                            }
                            else
                            {
                                m_videoCapture.release();
                                m_videoCapture = null;
                            }
                        }

                        public void surfaceDestroyed(SurfaceHolder holder)
                        {
                            if (m_videoCapture != null)
                            {
                                synchronized (this)
                                {
                                    m_videoCapture.release();
                                    m_videoCapture = null;
                                }
                            }
                        }

                        public void run()
                        {
                            while (true)
                            {
                                Bitmap bmp = null;

                                synchronized (this)
                                {
                                    if (m_videoCapture == null)
                                        break;

                                    if (!m_videoCapture.grab()) {
                                        break;
                                    }

                                    m_videoCapture.retrieve( m_rgbaMat,
                                        Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA);
                                    bmp = Bitmap.createBitmap(
                                        m_rgbaMat.cols(), m_rgbaMat.rows(),
                                        Bitmap.Config.ARGB_8888);

                                    if (Utils.matToBitmap(m_rgbaMat, bmp) == false)
                                    {
                                        bmp.recycle();
                                        bmp = null;
                                    }
                                }

                                if (bmp != null)
                                {
                                    Canvas canvas = m_surfaceHolder.lockCanvas();
                                    if (canvas != null)
                                    {
                                        canvas.drawBitmap(bmp,
                                            (canvas.getWidth() - bmp.getWidth()) / 2,
                                            (canvas.getHeight() - bmp.getHeight()) / 2,
                                            null);
                                        m_surfaceHolder.unlockCanvasAndPost(canvas);
                                    }
                                    bmp.recycle();
                                }
                            }

                            synchronized (this)
                            {
                                if (m_rgbaMat != null)
                                {
                                    m_rgbaMat.release();
                                }

                                m_rgbaMat = null;
                            }
                        }
                    }
                    「プロジェクト」メニューの「自動的にビルド」がチェックされていれば、ソースが変更されているときにも同時にビルドしてくれます。
                    入力ミスがあった場合は、エディタの左端とパッケージ・エクスプローラーのjavaファイルの横に×が表示されますので、ソースを修正してください。 ただし、まだ定義されていないメソッドの呼び出しを先に記述した場合も×になってしまいますが、その場合は、後でメソッドを記述すると消えるので気にしないでください。
                    Android端末上で作成したアプリを実行するには、プロジェクト名を右クリックして「実行」「実行の構成」を選択します。 名前に「OpenCV_Capture」と入力し、プロジェクト欄の「参照」ボタンを押し「OpenCV_Capture」プロジェクトを選択し「OK」ボタンを押し、戻ります。
                    「ターゲット」タブを選択し、「手操作」ラジオボタンをチェックします。 Android端末をUSBでPCとつないでおく必要がありますが、PCとの接続方法は端末ごとにことなるので、ここでは割愛させてください。
                    (端末の「アプリケーション」の設定を「提供元不明のアプリ」をチェックし、「USBデバッグ」モードにする方法も割愛しますm(_ _)m)
                    あと、OpenCVが動作するのはAndroid 2.2以降を搭載した端末だけですので、ご了承ください。
                    「実行」ボタンを押し、Android Device Chooserで、接続されたデバイスを選択し、「OK」ボタンを押すと、端末にインストールされたのち、アプリが実行されます。 画面上にカメラのキャプチャー(静止画では無く、動画で表示されます)が表示されたら成功です。 うまく行かない場合は、開発環境の設定からもう一度見直してください。
                    /////
                    第3回 カメラキャプチャの解説
                    OpenCV_CaptureActivity.javaの解説

                    自動生成されたソースからの変更点は以下の1行です。

                    setContentView(new OpenCV_CaptureView(this));
                    でビューをOpenCV_CaptureViewに設定しています。

                    OpenCV_CaptureView.javaの解説

                    まずは、android関連のインポートを行います。

                    import android.content.Context;
                    import android.view.SurfaceHolder;
                    import android.view.SurfaceView;
                    import android.graphics.Bitmap;
                    import android.graphics.Canvas;
                    次に、OpenCV関連のインポートです。

                    import org.opencv.android.Utils;
                    import org.opencv.core.Mat;
                    import org.opencv.highgui.Highgui;
                    import org.opencv.highgui.VideoCapture;
                    import org.opencv.core.Size;
                    OpenCV_CaptureViewクラスの宣言は以下になっています。

                    class OpenCV_CaptureView
                        extends SurfaceView implements SurfaceHolder.Callback, Runnable
                    OpenCV_CaptureViewクラスは、SurefaceViewクラスを継承し、SurfaceHolder.CallbackインタフェースとRunnableインターフェイスを実装しています。 カメラのキャプチャー画像など表示するにはSurfaceViewを継承する必要があります。
                    キャプチャー画面の表示はビデオ再生のようになるので、頻繁に画面を描画することになります。SurfaceViewはメインのスレッドとは別のスレッドで描画を行うので、今回のようなケースに使うためのクラスです。 
                    SurfaceHolder.Callbackインターフェイスでは、以下のメソッドを実装する必要があります。 surfaceCreatedメソッドはSurfaceViewの画面が作られたときに呼ばれます。 
                    surfaceChangedメソッドはSurfaceViewの画面が変化したときに呼ばれ、surfaceDestroyedは削除されるときに呼ばれます。 
                    Runnableインターフェイスはスレッドに用いられ、runメソッドの中にスレッドで実行する処理を実装します。 
                    OpenCV_CaptureViewクラスのメンバ変数の説明です。

                    SurfaceHolder m_surfaceHolder;
                    SurfaceViewの設定にはSurfacHolderクラスのオブジェクトを介して行います。

                    VideoCapture m_videoCapture;
                    VieeoCaptureクラスはOpenCVに用意されたカメラから動画をキャプチャーするクラスです。

                    Mat m_rgbaMat;
                    MatクラスもOpenCVのクラスで画像データを扱うためのものです。(厳密にはマトリックス用のクラスですが、画像も2次元のマトリックスと言うことでMatクラスが担当しているようです) 
                    OpenCV_CaptureViewクラスのコンストラクタの説明です。

                    m_surfaceHolder = getHolder();
                    SurfaceViewクラスのgetHolderメソッドの返値は、そのビューのホルダーになります。

                    m_surfaceHolder.addCallback(this);
                    SurfaceHolder.Callbackインタフェースのコールバックメソッドはどのクラスのメソッドであるかを設定します。thisを渡していますので、OpenCV_CaptureViewクラスに実装されたメソッドを呼び出すことになります。 
                    まずは、surfaceChangedメソッドです。 前述のように、SurfaceViewが変更になったときに呼び出されます。

                    synchronized (this)
                    synchronizedはスレッドの排他制御で、thisであるOpenCV_CaptureViewではrunメソッドがスレッドとして走っています。 このrunメソッドの中で変数などが書き換えられないようにするために、一時的に排他にします。

                    if (m_videoCapture != null && m_videoCapture.isOpened())
                    isOpenedメソッドは、VideoCaptureオブジェクトが初期化済みである場合にtrueを返します。

                    List<Size> sizes = m_videoCapture.getSupportedPreviewSizes();
                    getSupportedPreviewSizesメソッドは、カメラがサポートしているプレビューサイズのリストを返します。SizeクラスはOpenCVのクラスでheight,widthをメンバ変数に持ちます。

                    int frameWidth = width;
                    int frameHeight = height;
                    surfaceChangedメソッドの引数 width, heightは、変更されたSurfaceViewのサイズを保持しています。これをフレームの幅、高さを表す変数に代入します。

                    double minDifference = Double.MAX_VALUE;
                    minDifferenceは、SurefaceViewとVideoCaptureのプレビューサイズの差分を保持する変数です。最初はdouble型の最大値を入れます。

                    for (Size size : sizes)
                    sizesリストのSizeを一つ一つ取り出します。

                    if (Math.abs(size.height - height) < minDifference)
                    カメラのプレビューサイズとSurefaceViewとの差が前より小さい場合、以下の入替をします。

                    frameWidth = (int)size.width;
                    frameHeight = (int)size.height;
                    minDifference = Math.abs(size.height - height);
                    フレームサイズの変数と差分を保持する変数を入れ替えることで、for分を抜けたときは、差分が一番小さいサイズが保持されていることになります。

                    m_videoCapture.set(Highgui.CV_CAP_PROP_FRAME_WIDTH, frameWidth);
                    m_videoCapture.set(Highgui.CV_CAP_PROP_FRAME_HEIGHT, frameHeight);
                    で、VideoCaptureオブジェクトにフレームの幅と高さを設定しています。 
                    setメソッドはVideoCaptreのプロパティをセットするもので、Highgui.CV_CAP_PROP_FRAME_WIDTHを指定すると幅を、Highgui.CV_CAP_PROP_FRAME_HEIGHTを指定する高さを設定することになります。

                    m_rgbaMat = new Mat();
                    キャプチャ画像を取得するMatクラスのオブジェクトを生成しています。 カラー画像(RGBAで表現)を取得するのでm_rgbaMatと言うオブジェクト変数名にします。 
                    次にsurfaceCreatedメソッドです。 これはSurfaceViewが生成されたときに呼び出されます。

                    m_videoCapture = new VideoCapture(Highgui.CV_CAP_ANDROID);
                    VideoCaptureオブジェクトを生成する際に、カメラデバイスをHighgui.CV_CAP_ANDROIDを設定し、androidのビデオキャプチャーを指定しています。

                    if (m_videoCapture.isOpened())
                    VideoCaptureの初期化が成功していたら、

                    (new Thread(this)).start();
                    で、スレッドを開始します。これでrunメソッドが別スレッドで実行されます。 もし、失敗したら

                    m_videoCapture.release();
                    m_videoCapture = null;
                    VideoCaptureオブジェクトを解放しています。 surfaceDestroyedメソッドは、アプリが終了してSurefaceViewが削除されるときに呼び出されます。

                    synchronized (this)
                    別スレッドでrunメソッドの処理も走っているので、排他処理にします。 そして、VideoCaptureオブジェクトの解放をしています。初期化失敗の時と同じですね。 
                    スレッドを実行するrunメソッドの説明です。

                    while (true)
                    runメソッドから抜けるとスレッドは終了してしまうので、無限ループにしています。

                    Bitmap bmp = null;
                    BitmapクラスはAndorid APIに用意されているもので、画像データを扱うクラスです。 生成前なのでnullを入れておきます。

                    synchronized (this)
                    他のスレッドからアクセスされないように排他処理にします。

                    if (m_videoCapture == null)
                    {
                        break;
                    }
                    もし、surfaceDestroyedメソッドなどでVideoCaptureオブジェクトが解放されたら、無限ループを抜けます。

                    if (!m_videoCapture.grab())
                    {
                        break;
                    }
                    grabメソッドは、次のフレームを取得します。失敗したらループを抜けます。

                    m_videoCapture.retrieve(
                        m_rgbaMat, Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA);
                    retrieveメソッドは、取得したフレームを画像データにデコードしm_rgbaMatに格納します。 デコードの種類はHighgui.CV_CAP_ANDROID_COLOR_FRAME_RGBAを指定しており、RGBAのカラーフォーマットになります。 
                    m_rgbaMatはOpenCVに用意されたMatクラスのオブジェクトですので、そのままではAndroidが直接表示することはできません。 Bitmapのオブジェクトに変換する必要があります。

                    bmp = Bitmap.createBitmap(
                        m_rgbaMat.cols(), m_rgbaMat.rows(), Bitmap.Config.ARGB_8888);
                    まずは、Bitmapクラスのオブジェクトを生成します。 引数は幅、高さ、フォーマットの順で、それぞれ m_rgbaMat.cols() Matの列数、m_rgbaMat.rows() Matの行数、Bitmap.Config.ARGB_8888 ARGB各8ビットの32bitカラー に指定します。

                    if (Utils.matToBitmap(m_rgbaMat, bmp) == false)
                    Utils.matToBitmapはMatからBitmapに変換するOpenCVのユーティリティメソッドです。 
                    もし、変換に失敗したら

                    bmp.recycle();
                    bmp = null;
                    Bitmapオブジェクトは一端解放して、nullを代入します。(コマ飛びになります)

                    if (bmp != null)
                    nullでない=変換に成功ですので、取得した画像の描画処理に進みます。

                    Canvas canvas = m_surfaceHolder.lockCanvas();
                    CanvasクラスはAndroidの描画用のクラスです。 Canvasクラスのオブジェクトに画像を描画して (まだ画面には表示されない。メモリの中での話)、 描画が終了したら画面に表示すると言うダブルバッファの仕組みを使います。 lockCanvasメソッドはダブルバッファの仕組みを使うためのメソッドです。

                    if (canvas != null)
                    描画がうまくいったら

                    canvas.drawBitmap(bmp,
                        (canvas.getWidth() - bmp.getWidth()) / 2,
                        (canvas.getHeight() - bmp.getHeight()) / 2, null);
                    drawBitmapメソッドで、CanvasクラスのオブジェクトにBitmapオブジェクト描画します。 画像がCanvasの中心に表示されるようにtop, leftを計算しています。 最後の引数をnullにするとビットマップ描画になります。

                    m_surfaceHolder.unlockCanvasAndPost(canvas);
                    unlockCanvasAndPostメソッドにCanvasのオブジェクトを渡すと、このタイミングで、ダブルバッファの画像データが画面に表示されます。

                    bmp.recycle();
                    フレーム画像のCanvasへの転送がすんだので、Bitmapオブジェクトの画像は不要になり、一端解放します。 これをアプリの終了まで繰り返します。 
                    whileループから抜けてきた場合は、

                    synchronized (this)
                    排他処理にして

                    if (m_rgbaMat != null)
                    m_rbgaMatがnullでないかを調べ、

                    m_rgbaMat.release();
                    m_rgbaMat = null;
                    m_rbgaMatオブジェクトを解放し、runメソッドから抜けます。 
                    OpenCVによるビデオキャプチャの説明でした。
                    /////
                    第4回 グレースケール
                    手順は前回と同じです。

                    プロジェクト作成

                    Eclipseを立ち上げます。
                    「ファイル」メニューの「新規」「Androidプロジェクト」を選択します。
                    プロジェクト名に「OpenCV_Grayscale」と入力し「次へ」ボタンを押します。
                    ビルドターゲットは「Android 2.2」にチェックを入れ「次へ」ボタンを押します。
                    パッケージ名に「com.pronowa.android.OpenCV_Grayscale」と入力し「完了」ボタンを押します。
                    パッケージ・エクスプローラーに「OpenCV_Grayscale」プロジェクトが追加されます。

                    AndroidManifest.xml編集

                    カメラを利用できる様に、AndroidManifest.xmlに記述を追加します。

                    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
                        package="com.pronowa.android.OpenCV_Grayscale"
                        android:versionCode="1"
                        android:versionName="1.0" >

                        <uses-sdk android:minSdkVersion="8" />

                        <application
                            android:icon="@drawable/ic_launcher"
                            android:label="@string/app_name" >
                            <activity
                                android:label="@string/app_name"
                                android:name=".OpenCV_GrayscaleActivity"
                                android:screenOrientation="landscape" >
                                <intent-filter >
                                    <action android:name="android.intent.action.MAIN" />

                                    <category android:name=
                                      "android.intent.category.LAUNCHER" />
                                </intent-filter>
                            </activity>
                        </application>

                        <uses-permission android:name="android.permission.CAMERA"/>
                        <uses-feature android:name="android.hardware.camera" />
                        <uses-feature android:name="android.hardware.camera.autofocus" />
                    </manifest>
                    OpenCVライブラリの追加

                    次に「OpenCV_Capture」プロジェクトを右クリックして「プロパティ」を選択します。
                    「Android」を選択し「ライブラリー」のところにある「追加」ボタンをおします。
                    リストからOpenCV-2.3.1を選択し、「OK」ボタンを押します。
                    これでOpenCVのライブラリが利用できる様になります。

                    Viewクラスの追加

                    プロジェクトの下にあるsrcを展開し、com.pronowa.android.OpenCV_Grayscaleを右クリックします。
                    「新規」「クラス」を選択します。
                    ダイアログで、名前に「OpenCV_GrayscaleView」と入力します。,br> スーパークラスの「参照」ボタンを押して、 「型を選択してください」の下のエディットボックスに「SurfaceView」と入力します。 一致する項目に「SurfaceView」と表示されたら、それを選択状態にして「OK」ボタンを押します。
                    インターフェイス「追加」ボタンを押して、「インターフェイスを追加してください」の下のエディットボックスに「Callback」と入力します。 リストから「android.vew.SurfaceHolder:Callback」を選択して「OK」ボタンを押します。
                    もう一度「追加」ボタンを押して、今度は「Runnable」と入力します。 リストから「java.lang.Runnable」を選択して「OK」ボタンを押します。

                    Activityクラスの修正

                    パッケージ・エクスプローラーのOpenCV_GrayscaleActivity.javaをダブルクリックしエディタを開き、以下のコードを入力します。
                    自動生成されているコードの内、setContentViewメソッドを書き換えるだけです。

                    package com.pronowa.android.OpenCV_Grayscale;

                    import android.app.Activity;
                    import android.os.Bundle;
                    import android.view.Window;

                    public class OpenCV_GrayscaleActivity extends Activity
                    {
                        @Override
                        public void onCreate(Bundle savedInstanceState)
                        {
                            super.onCreate(savedInstanceState);
                            requestWindowFeature(Window.FEATURE_NO_TITLE);
                            setContentView(new OpenCV_GrayscaleView(this));
                        }
                    }
                    Viewクラスの記述

                    次にOpenCV_GrayscaleView.javaをダブルクリックして、エディタを開き、各メソッドの中身を記述します。

                    package com.pronowa.android.OpenCV_Grayscale;

                    import java.util.List;

                    import android.content.Context;
                    import android.view.SurfaceHolder;
                    import android.view.SurfaceView;
                    import android.graphics.Bitmap;
                    import android.graphics.Canvas;

                    import org.opencv.android.Utils;
                    import org.opencv.core.Mat;
                    import org.opencv.imgproc.Imgproc;
                    import org.opencv.highgui.Highgui;
                    import org.opencv.highgui.VideoCapture;
                    import org.opencv.core.Size;


                    class OpenCV_GrayscaleView
                        extends SurfaceView implements SurfaceHolder.Callback, Runnable
                    {
                        private SurfaceHolder   m_surfaceHolder;
                        private VideoCapture    m_videoCapture;

                        private Mat             m_rgbaMat;
                        private Mat             m_grayMat;

                        public OpenCV_GrayscaleView(Context context)
                        {
                            super(context);
                            m_surfaceHolder = getHolder();
                            m_surfaceHolder.addCallback(this);
                        }

                        public void surfaceChanged(
                            SurfaceHolder _holder, int format, int width, int height)
                        {
                            synchronized (this)
                            {
                                if (m_videoCapture != null && m_videoCapture.isOpened())
                                {
                                    List<Size> sizes =
                                      m_videoCapture.getSupportedPreviewSizes();
                                    int mFrameWidth = width;
                                    int mFrameHeight = height;

                                    double minDifference = Double.MAX_VALUE;
                                    for (Size size : sizes)
                                    {
                                        if (Math.abs(size.height - height) <
                                          minDifference)
                                        {
                                            mFrameWidth = (int) size.width;
                                            mFrameHeight = (int) size.height;
                                            minDifference =
                                              Math.abs(size.height - height);
                                        }
                                    }

                                    m_videoCapture.set(
                                      Highgui.CV_CAP_PROP_FRAME_WIDTH, mFrameWidth);
                                    m_videoCapture.set(
                                      Highgui.CV_CAP_PROP_FRAME_HEIGHT, mFrameHeight);
                                }
                                m_grayMat = new Mat();
                                m_rgbaMat = new Mat();
                            }
                        }

                        public void surfaceCreated(SurfaceHolder holder)
                        {
                            m_videoCapture = new VideoCapture(Highgui.CV_CAP_ANDROID);
                            if (m_videoCapture.isOpened())
                            {
                                (new Thread(this)).start();
                            }
                            else
                            {
                                m_videoCapture.release();
                                m_videoCapture = null;
                            }
                        }

                        public void surfaceDestroyed(SurfaceHolder holder)
                        {
                            if (m_videoCapture != null)
                            {
                                synchronized (this)
                                {
                                    m_videoCapture.release();
                                    m_videoCapture = null;
                                }
                            }
                        }

                        public void run()
                        {
                            while (true)
                            {
                                Bitmap bmp = null;

                                synchronized (this)
                                {
                                    if (m_videoCapture == null)
                                    {
                                        break;
                                    }

                                    if (!m_videoCapture.grab())
                                    {
                                        break;
                                    }

                                    m_videoCapture.retrieve(
                                      m_grayMat, Highgui.CV_CAP_ANDROID_GREY_FRAME);
                                    Imgproc.cvtColor(
                                      m_grayMat, m_rgbaMat, Imgproc.COLOR_GRAY2RGBA, 4);

                                    bmp = Bitmap.createBitmap(
                                            m_rgbaMat.cols(), m_rgbaMat.rows(),
                                            Bitmap.Config.ARGB_8888);

                                    if (Utils.matToBitmap(m_rgbaMat, bmp) == false)
                                    {
                                        bmp.recycle();
                                        bmp = null;
                                    }
                                }

                                if (bmp != null)
                                {
                                    Canvas canvas = m_surfaceHolder.lockCanvas();
                                    if (canvas != null)
                                    {
                                        canvas.drawBitmap(bmp,
                                          (canvas.getWidth() - bmp.getWidth()) / 2,
                                        (canvas.getHeight() - bmp.getHeight()) / 2, null);
                                        m_surfaceHolder.unlockCanvasAndPost(canvas);
                                    }
                                    bmp.recycle();
                                }
                            }

                            synchronized (this)
                            {
                                if (m_rgbaMat != null)
                                {
                                    m_rgbaMat.release();
                                }
                                if (m_grayMat != null)
                                {
                                    m_grayMat.release();
                                }

                                m_rgbaMat = null;
                                m_grayMat = null;
                            }
                        }
                    }
                    Androidでの起動方法等は、第2回「カメラキャプチャ」や他の文献を参考にしてください。

                    ソースの説明

                    前回と異なる箇所を中心に説明をします。
                    グレースケール用のMatクラスのオブジェクト変数を追加しています。

                    private Mat             m_grayMat;
                    グレースケールにしているのは、runメソッドの中です。

                    m_videoCapture.retrieve(m_grayMat, Highgui.CV_CAP_ANDROID_GREY_FRAME);
                    retrieveメソッドはキャプチャしたフレームをMatオブジェクトに変換して返します。
                    retrieveメソッドの引数は

                    retrieve( Mat image, int channel )
                    です。
                    channelにHighguiクラスにstaticで定義されているCV_CAP_ANDROID_GREY_FRAMEを渡すとグレイスケールに変換されたものがMatオブジェクトに入ります。
                    Bitmapオブジェクトはフルカラー様に作成しているので、m_grayMatからはそのまま変換できません。
                    そこで、

                    Imgproc.cvtColor(m_grayMat, m_rgbaMat, Imgproc.COLOR_GRAY2RGBA, 4);
                    にて、フルカラーのフォーマットに変換します。
                    cvtColorメソッドの引数は、

                    cvtColor(Mat src, Mat dst, int code, int dstCn)
                    codeにImgproc.COLOR_GRAY2RGBAを渡すと、グレースケールからRGBA(αチャンネルを持った32bitフルカラー)に変換します。
                    dstCnは変換後のチャンネル数です。 RGBAなので、4chに指定します。
                    dstに指定したm_rgbaMatに変換後のデータが入ることになります。
                    このm_rgbaMatは前回「カメラキャプチャ」の時と同じフォーマットなので後の処理は一緒です。
                    /////
                    第6回 エッジ抽出
                    写っているものの輪郭(エッジ)を抽出する処理です。 Canny法という処理を使います。

                    プロジェクト作成

                    Eclipseを立ち上げます。
                    「ファイル」メニューの「新規」「Androidプロジェクト」を選択します。
                    プロジェクト名に「OpenCV_Canny」と入力し「次へ」ボタンを押します。
                    ビルドターゲットは「Android 2.2」にチェックを入れ「次へ」ボタンを押します。
                    パッケージ名に「com.pronowa.android.OpenCV_Canny」と入力し「完了」ボタンを押します。
                    パッケージ・エクスプローラーに「OpenCV_Canny」プロジェクトが追加されます。

                    AndroidManifest.xml編集

                    前回と同じ要領で、カメラを利用できる記述を追加してください。

                    OpenCVライブラリの追加

                    次に「OpenCV_Canny」プロジェクトを右クリックして「プロパティ」を選択します。
                    「Android」を選択し「ライブラリー」のところにある「追加」ボタンをおします。
                    リストからOpenCV-2.3.1を選択し、「OK」ボタンを押します。
                    これでOpenCVのライブラリが利用できる様になります。

                    Viewクラスの追加

                    プロジェクトの下にあるsrcを展開し、com.pronowa.android.OpenCV_Cannyを右クリックします。
                    「新規」「クラス」を選択します。
                    ダイアログで、名前に「OpenCV_CannyView」と入力します。
                    スーパークラスの「参照」ボタンを押して、「型を選択してください」の下のエディットボックスに「SurfaceView」と入力します。
                    一致する項目に「SurfaceView」と表示されたら、それを選択状態にして「OK」ボタンを押します。
                    インターフェイス「追加」ボタンを押して、「インターフェイスを追加してください」の下のエディットボックスに「Callback」と入力します。
                    リストから「android.vew.SurfaceHolder:Callback」を選択して「OK」ボタンを押します。
                    もう一度「追加」ボタンを押して、今度は「Runnable」と入力します。
                    リストから「java.lang.Runnable」を選択して「OK」ボタンを押します。

                    Activityクラスの修正

                    パッケージ・エクスプローラーのOpenCV_CannyActivity.javaをダブルクリックしエディタを開き、setContentViewメソッドを以下に書き換えます。

                    setContentView(new OpenCV_CannyView(this));
                    Viewクラスの記述

                    次にOpenCV_CannyView.javaをダブルクリックして、エディタを開き、各メソッドの中身を記述します。

                    package com.pronowa.android.OpenCV_Canny;

                    import java.util.List;

                    import android.content.Context;
                    import android.view.SurfaceHolder;
                    import android.view.SurfaceView;
                    import android.graphics.Bitmap;
                    import android.graphics.Canvas;

                    import org.opencv.android.Utils;
                    import org.opencv.core.Mat;
                    import org.opencv.imgproc.Imgproc;
                    import org.opencv.highgui.Highgui;
                    import org.opencv.highgui.VideoCapture;
                    import org.opencv.core.Size;

                    public class OpenCV_CannyView
                        extends SurfaceView implements SurfaceHolder.Callback, Runnable
                    {
                        private SurfaceHolder   m_surfaceHolder;
                        private VideoCapture    m_videoCapture;

                        private Mat             m_cannyMat;
                        private Mat             m_grayMat;
                        private Mat             m_tempMat;

                        public OpenCV_CannyView(Context context)
                        {
                            super(context);
                            m_surfaceHolder = getHolder();
                            m_surfaceHolder.addCallback(this);
                        }

                        public void surfaceChanged(
                          SurfaceHolder _holder, int format, int width, int height)
                        {
                            synchronized (this)
                            {
                                if (m_videoCapture != null && m_videoCapture.isOpened())
                                {
                                    List<Size> sizes = 
                                      m_videoCapture.getSupportedPreviewSizes();
                                    int mFrameWidth = width;
                                    int mFrameHeight = height;

                                    double minDiff = Double.MAX_VALUE;
                                    for (Size size : sizes)
                                    {
                                        if (Math.abs(size.height - height) < minDiff)
                                        {
                                            mFrameWidth = (int) size.width;
                                            mFrameHeight = (int) size.height;
                                            minDiff = Math.abs(size.height - height);
                                        }
                                    }

                                    m_videoCapture.set(
                                      Highgui.CV_CAP_PROP_FRAME_WIDTH, mFrameWidth);
                                    m_videoCapture.set(
                                      Highgui.CV_CAP_PROP_FRAME_HEIGHT, mFrameHeight);
                                }
                                m_cannyMat = new Mat();
                                m_grayMat = new Mat();
                                m_tempMat = new Mat();
                            }
                        }

                        public void surfaceCreated(SurfaceHolder holder)
                        {
                            m_videoCapture = new VideoCapture(Highgui.CV_CAP_ANDROID);
                            if (m_videoCapture.isOpened())
                            {
                                (new Thread(this)).start();
                            }
                            else
                            {
                                m_videoCapture.release();
                                m_videoCapture = null;
                            }
                        }

                        public void surfaceDestroyed(SurfaceHolder holder)
                        {
                            if (m_videoCapture != null)
                            {
                                synchronized (this)
                                {
                                    m_videoCapture.release();
                                    m_videoCapture = null;
                                }
                            }
                        }

                        public void run()
                        {
                            while (true)
                            {
                                Bitmap bmp = null;

                                synchronized (this)
                                {
                                    if (m_videoCapture == null)
                                    {
                                        break;
                                    }

                                    if (!m_videoCapture.grab())
                                    {
                                        break;
                                    }

                                    m_videoCapture.retrieve(m_grayMat,
                                      Highgui.CV_CAP_ANDROID_GREY_FRAME);
                                    Imgproc.Canny(m_grayMat, m_tempMat, 80, 100);
                                    Imgproc.cvtColor(m_tempMat, m_cannyMat, 
                                      Imgproc.COLOR_GRAY2BGRA, 4);

                                    bmp = Bitmap.createBitmap(
                                            m_cannyMat.cols(), m_cannyMat.rows(),
                                            Bitmap.Config.ARGB_8888);

                                    if (Utils.matToBitmap(m_cannyMat, bmp) == false)
                                    {
                                        bmp.recycle();
                                        bmp = null;
                                    }
                                }

                                if (bmp != null)
                                {
                                    Canvas canvas = m_surfaceHolder.lockCanvas();
                                    if (canvas != null)
                                    {
                                        canvas.drawBitmap(bmp, 
                                          (canvas.getWidth() - bmp.getWidth()) / 2,
                                        (canvas.getHeight() - bmp.getHeight()) / 2, null);
                                        m_surfaceHolder.unlockCanvasAndPost(canvas);
                                    }
                                    bmp.recycle();
                                }
                            }

                            synchronized (this)
                            {
                                if (m_cannyMat != null)
                                {
                                    m_cannyMat.release();
                                }
                                if (m_grayMat != null)
                                {
                                    m_grayMat.release();
                                }
                                if (m_tempMat != null)
                                {
                                    m_tempMat.release();
                                }

                                m_cannyMat = null;
                                m_grayMat = null;
                                m_tempMat = null;
                            }
                        }
                    }
                    Androidでの起動方法等は、第2回「カメラキャプチャ」や他の文献を参考にしてください。

                    ソースの説明

                    Matクラスのオブジェクト変数は以下の3つを用意します。

                    private Mat m_cannyMat;
                    private Mat m_grayMat;
                    private Mat m_tempMat;
                    m_cannyMatはBitmapに変換する前の画像用です。
                    m_grayMatはキャプチャ画像用です。
                    m_tempMatはm_grayMatからエッジを抽出した画像用です。
                    処理はrunメソッドの中です。
                    まずは、retrieveメソッドでキャプチャ画像をMatオブジェクトに変換しますが、今回は

                    m_videoCapture.retrieve(m_grayMat, Highgui.CV_CAP_ANDROID_GREY_FRAME);
                    と、channelにCV_CAP_ANDROID_GREY_FRAMEを指定し、グレースケール画像で取得します。 これはCanny法でエッジ抽出をするCannyメソッドは入力にグレースケール画像を渡す必要があるためです。

                    Imgproc.Canny(m_grayMat, m_tempMat, 80, 100);
                    OpenCVのImgproc名前空間のCannyメソッドの引数は以下になります。

                    Canny(Mat image, Mat edges, double threshold1, double threshold2)
                    imageはエッジ抽出する元の画像でグレースケール(1chの8bit画像)の必要があります。
                    edgesは抽出後の画像で、imageと同じサイズとフォーマット(グレースケール)になります。
                    threshold1とthreshold2はエッジ抽出処理に使用するしきい値で、2つのうち大きいしきい値を用い抽出し、 次に小さいしきい値で抽出し、先ほどの大きい方の抽出と隣接している場合は抽出したエッジに加えると言う処理になります。
                    m_tempMatはグレースケールなので、このままではフルカラーのBitmapに変換できません。

                    Imgproc.cvtColor(m_tempMat, m_cannyMat, Imgproc.COLOR_GRAY2BGRA, 4);
                    を用いて、34bitフルカラーフォーマットに変換します。(画像自体はRGB各チャンネルとも同じ値のグレースケールのまま) 
                    /////
                    Android用開発メモ  AndroidでOpenCVを使ってみよう | permalink | comments(0) | - |

                    Android用開発メモ OpenCV for Android の導入方法

                    0
                      Android用開発メモ OpenCV for Android の導入方法

                      AndroidでOpenCVを使うための導入方法について解説します。

                      OpenCVとは

                      OpenCVとはOpen Computer Visionの略で開発元はIntel。
                      画像処理などを扱うためのライブラリです。

                      バージョン情報

                      本稿で確認したバージョンは2.4.6です。

                      導入方法

                      ダウンロード

                      まずはこちら( http://opencv.org/downloads.html )からOpenCV-2.4.6-android-sdk-r2.zipをダウンロード、展開

                      スクリーンショット(2013-08-03 11.42.00).png

                      解凍した中のsdk/java/ をEclipseにインポート

                      このとき、Copy projects into workspaceのチェックをつけておくと、
                      後々面倒になるので、チェックを外しておきます。

                      スクリーンショット(2013-08-03 12.52.03).png

                      そのままではビルドエラーになることがあります

                      プロジェクトのproperties->Androidからビルドターゲットを選択して
                      再ビルドすれば治るはずです。

                      スクリーンショット(2013-08-03 11.54.13).png

                      サンプル動作方法

                      サンプルはダウンロードしたファイル群の中の、 samples/ 配下に入っています。まとめてEclipseでインポートします。

                      スクリーンショット(2013-08-03 12.01.06).png

                      ビルドエラーになることがあります。

                      先ほどと同じくプロジェクトのproperties->Androidからビルドターゲットを選択。 また、インポートの仕方によっては、Libraryのリンクでエラーがでていることがあります。その際は一旦LibraryをRemoveしてから、再度Addで最初のライブラリプロジェクト(OpenCV Library 2.4.*)を追加します。

                      スクリーンショット(2013-08-03 12.04.15).png

                      アプリインストール

                      サンプルアプリをインストールして実行しようとすると、ダイアログがでて
                      GooglePlayからOpenCV Managerをインストールするように言われます。
                      これが何者かは後述予定。とりあえず言われたとおりインストールします。

                      スクリーンショット(2013-08-03 12.12.13).png

                      アプリインストール(補足)

                      一部のサンプルアプリはNDKビルドが必要です。
                      実行できないときはNDKビルドしてみて下さい。
                      なお、NDKビルドのためにはパスにスペースがあると不味いので、
                      もしパスにスペースがあれば(最初のインポート時にコピーしてしまった場合はそうなる)プロジェクト名変更が必要です。残念ですね。

                      なお、現時点では、MacOSでのビルドは失敗します。
                      ですのでLinux上でNDKビルドを行います。
                      NDKビルドだけLinux上でやって、ビルド成果物であるsoファイルだけMac上のAndroidSDKに持ってくるのはあり。

                      例えばface-detection配下でNDKビルドすると、libs/armeabi-v7a/libdetection_based_tracker.soが生成されます。これを(パスそのままで)移植してきます。(移植の場合はアクセス権注意)

                      スクリーンショット(2013-08-03 21.14.07).png

                      これで無事サンプルアプリが動作するはずです。
                      下記画像はface-detectionを動かしたときのスクリーンショット。
                      モデルはJOJO。

                      スクリーンショット(2013-08-03 21.30.38).png

                      以上、お疲れ様でした。
                      Android用開発メモ OpenCV for Android の導入方法 | permalink | comments(0) | - |

                      Android用開発メモ  Android OpenCV 2.4.6 の顔検出アプリを一から作ってみる

                      0
                        Android OpenCV 2.4.6 の顔検出アプリを一から作ってみる

                        OpenCV 2.4.6-Android-sdkのサンプルにあるface-detectionを一から作ってみましょう。 

                        まあ、一からと言ってもC++のソースとヘッダーやその他のコードも、まんまお借りする訳ですけど...。 

                        今回の作業には、android-ndkとCygwinが必要ですので、事前にインストールして環境設定しておいてください。 

                        android-ndk 

                        Cygwin 

                        肝はJNIプロジェクトの作成です。 

                        が、その前に以下の項目を事前に決めておきます。 

                        NDKでビルドする場合、メソッド名規約を守らないとUnSatisfiedLinkErrorが出て簡単に落ちます。 

                        ●アプリケーション・プロジェクト名 
                        ●パッケージ名(重要) 
                        ●アクティビティ名 
                        ●レイアウト名 

                        アプリケーション・プロジェクト名はなんか適当に、facedetect246とかにします。 

                        パッケージ名は例えば、jp.example.facedetect246にします。 

                        アクティビティ名も例えば、FdMainActivityとかにします。 

                        レイアウト名はサンプルにならって、face_detect_surface_viewにしときます。 

                        まずは、普通にJavaで新規プロジェクトを作成します。 

                        Eclipseを起動して、File->New->Projectで、上記の名称でプロジェクトを作成。 

                        プロジェクト名を右クリックしてPropertiesを選んで、EncodingをUTF-8、Targetを4.0.3、ライブラリにOpenCV 2.4.6を設定しておきます。 

                        まずサンプルコードを先に移植しておきます。 

                        これをやっておかないと、C++のプロジェクトを追加しようとしても、Eclipseはどこに追加すればいいのか分からなくなるようです。 

                        新規プロジェクトのjp.example.facedetect246パッケージに以下のPublic classを追加。 

                        DetectionBasedTracker 

                        サンプルのresフォルダーからrawとlayoutをコピーして、プロジェクトをRefreshしておきます。 

                        rawにはカスケードファイルが入っています。 

                        サンプルのface-detectionのコードを移植。 

                        FdActivity -> FdMainActivity 
                        DetectionBasedTracker -> DetectionBasedTracker 

                        エラー箇所を修復したら、C++プロジェクトを作成します。 

                        プロジェクト名を右クリックして、New -> Otherを選択。 

                        C/C++の中の、「Convert to a C/C++ Project(Adds C/C++ Nature)」を選択。 

                        Convert to a C/C++ Projectのウィンドウが開いたら、 

                        Candidate for Conversionの自プロジェクトにチェックが入っているのを確認。 

                        Project option で「Makefile Project」と「CygwinGCC」を選んでFinish。 

                        Project Explorerにincludesの項目が追加されています。サンプルとは異なっていると思いますが気にしなくていいです 

                        プロジェクト名を右クリックして、New -> Folderを選択。jniフォルダーを作っておきます。 

                        この中にサンプルのmkファイルやcppのソース・ヘッダーが置かれます。 

                        で、その前にプロジェクトのC/C++の設定をしておきます。 

                        プロジェクト名を右クリックしてPropertiesを選んで、C/C++ Buildを設定。 

                        Build command欄に、NDKのndk-build.cmdの場所をフルパスで設定。 

                        Build directoryが自プロジェクトになっているのを確認。 

                        Behaviourタブを選んで、Buildの2つの欄を空白にして、cleanのチェックも外しておきます(サンプル参考)。 

                        次に、C/C++ GeneralのPath and SymbolsでSource Locationに自プロジェクトのjniフォルダーをAddして、既存のものをDeleteしておきます。 

                        忘れてました 
                        C/C++ GeneralのPath and SymbolsのIncludesで、NDKのincludeフォルダーをAddしておいてください。 
                        例:C:¥android-ndk-r8d¥platforms¥android-8¥arch-arm¥usr¥include 
                        これをやっておかないと、C++のソース・ヘッダーでJNICALLが分からん...というような文句がでます。 


                        AndroidManifest.xmlに以下を追加。
                        android:minSdkVersion="9"

                        ----------------

                        android:screenOrientation="landscape"

                        ----------------

                        <supports-screens android:resizeable="true"
                                              android:smallScreens="true"
                                              android:normalScreens="true"
                                              android:largeScreens="true"
                                              android:anyDensity="true" />

                        <uses-permission android:name="android.permission.CAMERA"/>
                        <uses-feature android:name="android.hardware.camera" android:required="false"/>
                        <uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>
                        <uses-feature android:name="android.hardware.camera.front" android:required="false"/>
                        <uses-feature android:name="android.hardware.camera.front.autofocus" android:required="false"/>


                        この時点ではC++のコードが何も無いので、Eclipseのコンソールにはビルドエラーが吐き出されていると思います。 



                        では、C++の環境を作ります。 

                        まずサンプルどおりに、jniフォルダーに以下のファイルを作っておきます。 

                        Android.mk 
                        Application.mk 
                        DetectionBasedTracker_jni.cpp 
                        DetectionBasedTracker_jni.h 

                        Android.mkとApplication.mkはサンプルどおりです。 

                        DetectionBasedTracker_jni.cppとDetectionBasedTracker_jni.hですが、修正します。 

                        メソッド名規約は、"Java_パッケージ名_クラス名_メソッド名"です。 

                        今回の作り方なら、クラス名_メソッド名はそのままでいいですが、パッケージ名のところが異なります。 

                        サンプルでは、Java_org_opencv_samples_facedetectとなっていますが、ここの例では、Java_jp_example_facedetect246になります。 

                        なおオリジナルのヘッダーファイルには「勝手に書き換えんなよ」と書いてますが....書き換えます。 

                        最後に、プロジェクトをcleanすればC++のコードがビルドされて、プロジェクトにobjとlibs/armeabi-v7a/libdetection_based_tracker.soが作成されます。 

                        PS 

                        cppのソースを移植した場合、Eclipseが山ほどエラーを吐き出す場合があります。 

                        特にnamespaceについてのSymbolエラーですが、実はエラーじゃない場合があります。 

                        Eclipseが誤判定しているような感じ。ndkかCygwinとの相性かもしれないのですが...まだ分かりません。 

                        このままではRunできないので、Eclipseを再起動してみてください。エラーが解消されます...というかエラーが消えるはず。 

                        以上です。 

                        こんな感じ。 

                        なんかオリジナルのサンプルアプリよりカメラ画面が小さくなったような気がするが...気のせいか?。 

                         



                        インストール 

                        サンプルなので、インストール・実行は自己責任でお願いします。 

                        Target:Android 2.3.3 or later 

                        動作確認実機:Xperia acro(docomo) Android 2.3.4、dtab01(docomo) Android 4.1.2 

                        なお、このアプリの実行には別途、OpenCV Managerが必要です。 

                        先に、GooglePlayでインストールしておいてください。 

                         

                        - アプリをQRコードからインストールする方法はコチラを参照 


                        タブレットの場合 

                        QRコードでダウンロードすると、Downloadフォルダー内でzipファイルになってインストールできない状態の場合があります。

                        その場合は、拡張子のzipをapkに変更してファイル名をタップすればインストール用のダイアログが出ますので、そこからインストールしてください。 



                        他のOpenCV関連ページ 

                        OpenCV覚書 

                        矩形領域の座標を取得するページ 

                        OpenCV 2.3.1でカスケードを作って、Androidで使ってみる 

                        アンドロイドでOpenCV(お顔の検出) 

                        アンドロイドでOpenCV(色検出) 

                        アンドロイドでOpenCV(特徴点検出) 

                        Android OpenCV 2.3.1で画像認識 

                        AndroidでOpenCV 2.4.6を使ってみる 

                        OpenCV + NyMMDで初音ミクさんにご挨拶してもらいます 
                        Android用開発メモ  Android OpenCV 2.4.6 の顔検出アプリを一から作ってみる | permalink | comments(0) | - |