OpenCV/C++で画像処理入門 vol.6 〜画像を行列にしてみよう②〜
2019.01.31
こんにちは、代表の大野です。
OpenCV/C++で画像処理入門シリーズの第6回目です。
画像を行列にするにあたり、
前回は、デジタル画像と行列の関係性について見てきました。
今回は、実際モノクロ画像を行列に変換する
という操作を、OpenCVを使ってやってみたいと思います。
環境があれば、ぜひみなさんも一緒に
プログラムを書いて体験してみてくださいね。
バックナンバー
vol1. 画像を表示してみよう
vol2. 画像を加工してみよう
今回やること
- デジタル画像に行列にしてみる
- デジタル画像の一部分を行列として取得してみる
環境
マシン :mac OS Mojave 10.14.1
言語 :C++
ライブラリ:OpenCV 3.4.3
コンパイラ:Clang / LLVM
準備 & 画像の用意
OpenCVのインストールなどは
バックナンバーなどから、参考にしてください。
今回のサンプルは
スワワちゃんが愛用しているスマートフォンである
「スワートフォン(通称スワホ)」を用いることにします。
スワートフォン(swartphone.jpg)
width : 300px
height : 300px
これを見た瞬間に
300 × 300行列だな
スワホ本体の領域には、数値が低いものが多そうだな
と思った方は、前回の内容が
十分に理解されていますね。
では、いってみましょう。
デジタル画像に行列にしてみる
さて、さっそくですが、
今日はプログラムから見てみたいと思います。
行列にするのはそんなに難しくありません。
なぜなら、これまでのブログで
すでにやっている操作だからです。
それではみてみましょう。
<ソースプログラム>
matrix.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #include <opencv2/opencv.hpp> #include <iostream> int main() { cv::Mat img, dst; img = cv::imread("swartphone.jpg"); cv::cvtColor(img, dst, cv::COLOR_BGR2GRAY); std::cout << dst << std::endl; return 0; } |
さて、ここまでOpenCV/C++入門ブログを愛読いただいた方なら
このままビルドして、すでに実行してしまっているかもしれませんが、
ビルドはできますが、
ターミナルの画面がひどいことになります(笑)
まずソースコードから説明しますね。
1 2 3 4 | cv::Mat img, dst; img = cv::imread("swartphone.jpg"); cv::cvtColor(img, dst, cv::COLOR_BGR2GRAY); |
でやった、
画像を白黒にする処理です。
まずは、モノクロ画像を行列にするため
cv::cvtColor()を使って、スワホ画像を白黒にしています。
もし、cv::imshow()するなら以下の感じになっているはずです。
続いて、
1 | std::cout << dst << std::endl; |
あれ、いきなり標準出力のcoutしちゃっています。
行列にする処理は
どこで行なったのでしょうか?
そう、実は、OpenCVでは、
cv::imread()をして、デジタル画像を読み込んだタイミングで
行列として、読み込んでいます。
これはものすごく当たり前のことを言っているんですが
なぜなら、cv::imread()で格納する先は、
cv::Mat img
だからです。
cv::Matは、Matrixの略です。
つまり、Matrix(行列)なんです。
じゃあ、何も難しいことはありません。
このままビルド&実行してしまえば
当然行列が取れます。
やめたほうがいいですが、
きっとやってみたい気持ちMAXだと思うので(笑)
300×300行列 = 90000の数値
をターミナルに表示してやりましょう。
<ビルド & 実行>
ターミナル
1 2 | c++ $(pkg-config --cflags --libs opencv) matrix.cpp ./a.out |
結果は、書きません(笑)
読めるかこんなもん!
って感じかと思います…
デジタル画像の一部分を行列として取得してみる
ということで、デジタル画像処理をするには、
この行列に、四則演算をしていけばいいのですが、
もっとわかりやすいように
まずはデジタル画像の一部分だけを取り出して
行列として表示してみるのが、わかりやすいでしょう。
いきなり、300 × 300行列だと
標準出力でとんでもないことになるので、
1行目だけを取り出してみたいと思います。
それでも300の数値がありますけどね。
<ソースプログラム>
matrix_part.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #include <opencv2/opencv.hpp> #include <iostream> int main() { cv::Mat img, dst; img = cv::imread("swartphone.jpg"); cv::cvtColor(img, dst, cv::COLOR_BGR2GRAY); std::cout << dst.row(0) << std::endl; return 0; } |
(ビルドは、先ほどの手順と同じ)
どうですか?
300ならなんとか表示画面に
おさまったのではないかと思います。
(おさまらない場合は表示文字サイズの縮小を)
あれ、全部255だ
と思った方もいると思いますので、
画像をもう一度みてみましょう。
縦幅300pxあるので、
一番上の1行目は、全部白であることがわかりますよね?
なので、全部255で表示されているのは正常なんです。
ソースコードの該当部分をみてみると
1 | std::cout << dst.row(0) << std::endl; |
この、dstというcv::Matクラスのrow()を使って、
引数に行数を入力すれば、その行のみを取得できます。
画像の行列は、
1行目、1列目は0から始まります。
横幅300pxなら、0から299です。
今回は、引数が0なので
1行目だけの行列が取得されています。
では、真ん中の150行目あたりを表示すれば、
255以外の値も、行列から取得できそうなのでやってみましょう。
matrix_part2.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #include <opencv2/opencv.hpp> #include <iostream> int main() { cv::Mat img, dst; img = cv::imread("swartphone.jpg"); cv::cvtColor(img, dst, cv::COLOR_BGR2GRAY); std::cout << dst.row(149) << std::endl; return 0; } |
(ビルドは、先ほどの手順と同じ)
どうですか?
こんな感じになりました。
同様に列だけ取り出したい場合は
1 | std::cout << dst.col(149) << std::endl; |
で取得することができます。
ここでは、やりませんが、
ぜひ自身でやってみてください。
では、最後に
部分行列を指定した場所から取り出す方法をみてみたいと思います。
こちらのスワートフォンの画像のうち
スワワちゃんの右目の部分のみの行列を
取り出してみます。
右目は、この画像でいくと
だいたい
(x, y) = (95, 115)
あたりを左上頂点座標として、
width 30px × height 40px = 1200行列
で取得できると思います。
<ソースプログラム>
matrix_part3.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #include <opencv2/opencv.hpp> #include <iostream> int main() { cv::Mat img, dst; img = cv::imread("swartphone.jpg"); cv::cvtColor(img, dst, cv::COLOR_BGR2GRAY); std::cout << dst(cv::Rect(95,115,30,40)) << std::endl; return 0; } |
(ビルドは、先ほどの手順と同じ)
<結果表示>
いかがでしょうか?
目の画像のように
丸い円状に、高い数値が出力されている行列になっていますよね?
1 | std::cout << dst(cv::Rect(95,115,30,40)) << std::endl; |
このコードの通り、cv::Mat型のdstを
cv::Rect型を使って切り取っています。
cv::Rect型は
第一引数 x座標
第二引数 y座標
第三引数 width(横幅)
第四引数 height(縦幅)
でしたね?
この引数の値を変更することで
任意の好きな画像領域から、
行列が取得できることがわかりました。
まとめ
いかがでしたでしょうか?
時間があるときに、様々な画像を使って
デジタル画像を行列として取得してみるのも面白いと思いますので
ぜひ試してみてください。
それでは。
↓↓↓ぜひチェックしてください
~提供中のヒューマンセンシング技術~
◆人物検出技術
歩行者・来店者数計測やロボット搭載も
https://humandetect.pas-ta.io
◆視線検出技術
アイトラッキングや次世代UIに
https://eyetrack.pas-ta.io
◆生体判定技術
eKYC・顔認証のなりすまし対策を!
https://bio-check.pas-ta.io
◆目検出技術
あらゆる目周りデータを高精度に取得
https://pupil.pas-ta.io
◆音声感情認識技術
会話から怒りや喜びの感情を判定
https://feeling.pas-ta.io
◆虹彩認証技術
目の虹彩を利用した生体認証技術
https://iris.pas-ta.io