WEBカメラで撮影してJPEGファイルにするプログラム(後編)
後編では、WEBカメラから取得した画像データを変換してJPEGファイルにするところと、4G-LTEを使用してサーバにアップロードした時の通信所要時間の変化について解説します。
前編はこちら:WEBカメラで撮影してJPEGファイルにするプログラム(前編)
カメラ映像フォーマット
カメラから出力された画像のフォーマットは、YUYVフォーマット(Y=明るさ成分、U=青色成分、V=赤色成分)でした。
PCで扱う画像ファイルのフォーマットの多くはRGBフォーマットなので、変換が必要です。
また、非圧縮のままでは大きすぎるので、JPEGファイルにします。
そこで、JPEGライブラリを活用します。
インターネットに接続した状態でライブラリをinstallします。
sudo apt-get install libjpeg-dev
ライブラリにはヘッダファイルなどが含まれているので、下記の様にincludeすると、ライブラリの関数や定数などが使えるようになります。
#include <jpeglib.h>
コンパイル時には、自分で作ったプログラムと、ライブラリをリンクするため、オプション(-ljpeg)を指定する必要があります。
gcc cam.c -ljpeg
ライブラリにはYUYVからJPEGに変換する機能は無く、あらかじめYUVかRGBに変換する必要があるようです。
つまり、変換方法は2通り考えられます。
- YUYVフォーマットをRGBフォーマットに変換(自作)してから、ライブラリでJPEGに変換する。
- YUYVフォーマットをYUVフォーマットに変換(自作)してから、ライブラリでJPEGに変換する。
まずは、簡単にできそうな後者を試して、動作が遅いようでしたら前者を検討しましょう。
ソースはこちら:ソース倉庫
結果、ライブラリの性能が優秀なおかげで、後者で問題ありませんでした。
さて、YUYVをYUVに変換する際、UとVを取り違えたらどうなるでしょうか?
Uが青の色差成分、Vが赤の色差成分ですので、簡単に言うと、青系の色と赤系の色が反転するのでは?
では、白や黒や金は?
緑やオレンジは?
今が試すチャンスです。
やってみましょう。
あなたの予想通りでしたか?
緑がほとんど変わらない理由を説明できますか?
YUVフォーマットにおける4:4:4と4:2:2
カメラのYUV出力において、Y(明るさ)成分は1ピクセル当たり1byte(8bit)。
しかし、U成分は2ピクセル当たり1byte。V成分も2ピクセル当たり1byte。
ちょっと不思議ですね?
人間の目は、明るさよりも色味の違いの方が気づきにくく、
モニタの構造において、明るさよりも色の表現の方が難しいためです。
より高画質のカメラの場合、UもVも1ピクセル当たり1byte、というモノもありますが、情報量が1.5倍になるので、記録媒体(ビデオテープやディスク)を余分に消費します。
このフォーマットを4:4:4と呼び、前者を4:2:2と呼びます。
テレビ画面やWEBカメラに求められる画質を考えると、ほとんど気づかない様な色味よりもコストを優先しよう、という考え方が生まれたわけです。
デメリットもあります。明るさと色味の情報量に差があると、機械やアプリの処理が複雑になります。
今回jpegライブラリに渡す前に変換が必要になった様に。
エンジニアの負担が増えるわけですね。
その代わり、消費者のお財布の負担が減るわけです。
エンジニアたちの努力と根性によって、我々のビデオライフがより安価で豊かなものになっているのです。
ありがたいですね。
4G-LTE接続時間とサーバログイン時間は変動する
4G-LTE接続に要する時間なのか、サーバログインに要する時間なのか、定かではありませんが、しばらく繰り返していると、徐々に短時間で接続できるようになります。
回線の混雑状況にも影響されるでしょう。
あるいは、どこかで優先処理が働いているのでしょうか。
今回の例でみると、最初は1ファイルのアップロードは3秒~10秒くらいで平均は3~4秒くらいかかっていましたが、数百枚アップロードした頃の所要時間を見てみると、1.7秒~9秒で平均2.3秒くらいになりました。
元より、インターネットを用いているので、通信速度の変化やバラツキは念頭に置くべきです。
今回は更に、携帯電話網を用いるので、更に変動が激しくなるのは必然です。
サーバ側のトラフィックによって左右されることも考えなければなりません。
通信時間を追及しなければならない場合や、一定時間内に通信を完了しなければならない、といった制限がある場合、設計者はこれら外的要因もすべて加味して設計しなければなりません。
より広く知識を求め、選択肢を増やす。そうしないと…
今回、YUVフォーマットを変換するか否か、選択するシーンがありました。
そして、動作が遅くなければ、簡単な方が良い、という判断を下しました。
プログラムを設計する際、目的は同じでも、その手段は様々です。
そして、より多くの手段を選択できる/思いつくことができるエンジニアが有利です。
選択の幅が広い方が、障害を回避したり品質を高めることができるからです。
「有利」であって、必ずしも「優れている」という訳ではありません。
選択肢は多くても1つも実現できないエンジニアよりも、選択肢は少なくても1つでも実現できる方が、評価されるでしょう。
もちろん、少ない選択肢の中に、実現に至る道が1つも無ければ、結果は得られず、評価されることもありません。
選択肢を広げるのが目的ではなく、目的を実現する手段を持つこと、探し出せることが大事なのです。
開発者は覚える事よりも、知ることの方が大事だと思います。
10個のライブラリやプログラムを深く記憶しているよりも、20個の手法やルールの存在を知っている方が、成果にたどり着く可能性が高いのです。
1つ目の理由は、目的を達成する手段が、実は少ないということにあります。
前述した内容と真逆のことを言っていますね?
前述した「目的」は、小さな「目的」です。
今話したい「目的」は、大きな「目的」です。
例えば、カメラの映像をJPEGにしたい、という小さな目的であれば、様々な言語のどれを使っても良いですし、デバイスやライブラリも色々選択できます。
例えば、来週お客様のところに映像監視システムのデモ機を持っていきたい、という目的ならば、生産と実用に耐えるデバイスを使わなければならず、既存資産を流用できそうな言語を選択しなければならず、数時間でコーディングできそうでライセンスもクリアできるライブラリを選択しなければなりません。
例えば、1つの製品を作るとき、様々な機能を実現するために、各々の機能が占有するメモリ容量やCPU使用率が、他の機能を阻害しない様に、特化したライブラリやプログラムの組み方は避けなければなりません。使いたいライブラリがあっても、そのOSには対応していないかもしれません。
この様に、目的によっては、手段が多く、それらをいくつか組み合わせるだけで実現できる場合もありますが、目的によっては、選択できる手段や組み合わせ可能な手段が極端に少ない場合もあります。
2つ目の理由は、情報化社会の恩恵です。
使えそうなライブラリの存在を知っていれば、詳しいことは覚えていなくても、少し調べれば情報が得られます。
自分の目的と似たようなケースや関係しそうなキーワードを思い出せたら、目的にたどり着くまで手段を、たぐり寄せることができます。
3つ目の理由は、加速する技術躍進と広がる活用シーンです。
技術の進歩は留まることを知らず、常に新しい技術の発表や、既存技術の更新が行われています。
それらを知らずに新しいものを生み出すのは非常に困難でしょう。
仮に生み出したとしても、あっという間に新しい潮流に流されてしまいます。
しかし、一つ一つ細かく覚えてる余裕はありません。
また、日々生み出される技術やアイデアは、その活用シーンも加速度的に広げています。
インターネットは当初、軍事や一部の研究者しか触れていませんでしたが、現在では知っての通りです。
今インターネットが無くなったら…SNSやメールが止まって発狂しかねません。
IoTが盛り上がり、徐々に実用レベルのデバイスが身の回りに増えてきました。その元をたどれば、何のことはない、電話機や照明スイッチがちょっと進化しただけです。
目的を達成する道筋は多い時も少ない時もあります。
多くても、その中から、より効率の良い、品質の高い手段を取らなければ、後々後悔することになるかもしれません。
(トラブルが多発したり、ライバルに負けたり…)
世に存在する技術や新たに組み立てる技術や手段が無限にあり、それらを目的に合わせて組み合わせることを考えると、ぐっと数が減ります。
しかし、その減ったモノを知っていなければ、その糸口さえ知らなければ、ゼロです。
達成不可能になってしまいます。
しかし、気後れする必要はありません。
少なくとも、ブラウザで技術情報を見ているあなたは、既に糸口をつかんでいます。
そして、「知らなければならない」「無理に暗記しなくてもいい」ということを知っているあなたは、既に1歩も2歩も先を歩いています。
ソースはこちら:ソース倉庫
プログラムのオプションについてはこちら:WEBカメラで撮影してJPEGファイルにするプログラム(前編)