How_to_play_OpenCV
Enjoy playing OpenCV!
OpenCVでいろいろする話 ~part.1 導入編~
Advent Calender 12/02
これはそれにちなんで1人、または複数人で毎日記事を投稿していくという企画を、わが部活でもやろうというものです
というわけで、消火器が頑張らせていただきましょう…!
OpenCVとは
OpenCV(正式名称: Open Source Computer Vision Library)とは... Intelによって開発・公開された画像認識・解析などのコンピュータビジョンのライブラリ
大きな特徴として、オープンソースで、かつ、マルチプラットフォーム そのため、さまざまな環境で手軽に使用する事が可能
学術用途だけでなく商業用としても使用されることがある
今回は、そんなOpenCVを使えるようになり、画像処理を楽しめるようになることを目標に話を進めていきたいと思います
いったいなにができるの?
Q.そんな自由で優秀なライブラリであるOpenCVでできることは? A.色々できすぎて回答できない…
とにかく多いんですよ…
商業で使われるだけあって、とにかくいろんな機能が、比較的簡単に使うことができる
主に画像を受け取りそれに対して何らかの処理を行うことがメインです 0から思いのままの画像を作成することもできるがメインではない印象 それならOpenGLとかのがいいかもしれない
既存の画像に対して、●●をしたい!という願望があれば、OpenCVが適任かなぁと
ちなみにパターン認識に片足突っ込んだようなことも、簡単にできる 顔検出とか、特徴点マッチングとか
次回以降に解説するかも
まずは動かしてみよう
OpenCVはライブラリなので、使ってなんぼだと思います どんなものか色々調べるより、何ができるか考えるより、まず見てみてほしい!
それで楽しめたなら、ぜひもっといろいろしてほしいな~と
ここから、実際に使えるようになるまでを一通り紹介します。 技術的な話は今回はしない予定 準備してサンプル動かしてわぁすごいが目標
今回はPythonで実装したいと思います 理由はPythonの簡潔なコードと、OpenCVのシンプルな書き味がマッチしていると思うため
Pythonの記法自体がわかりやすいため、知らなくてもきっと意味はくみ取れます
なるべくOpenCVの関数をしっかり開設する予定
私の環境はこちら Python 2.7.3
OpenCV 2.4.1 僕のは微妙に古いけど、基本的にPython2系で、OpenCVも2系を使えば以下のソースは大丈夫なはず…
Python3系、OpenCV3の場合はちょっとご存じない…すまない…
もし気になれば、私の方で調査してみようとも思うので是非レスポンスくださいな
インストールについて
自分のPythonのフォルダのパスを書き加えること
僕の場合は「C:\Python27;」を書き加えました
コマンドプロンプトで ''python''と入力・実行して、起動すればOK!
OpenCV自体のインストールは以下の通り OpenCVをサイトからダウンロードして、cv2.pydを探しましょう 僕の時は「C:\opencv\build\python\2.7\cv2.pyd」でした
ほとんどは変わらないと思いますが、Pythonの¥やOpenCVのバージョンによってはディレクトリ名や必要なcv2.pydが違うので注意
なおOpenCVのフォルダ自体は後々使うことがあるので、cv2.pydをコピーした後も消さない方がいいです
私は一回消してしまいました…
でそれを、Pythonのフォルダの「Lib\site-packages」の中にコピーしてやります 私は「C:\Python27\Lib\site-packages」でした
OpenCV自体はOKなんですが、OpenCVが使用しているライブラリとして、''Numpy''と呼ばれるものがあるのでそれもインストールします Numpyの配布サイトにいってzipファイルをダウンロード&解凍 setup.pyがあることを確認してコマンドプロンプトでそのフォルダを開きます Shift+右クリックから「コマンドプロンプトをここで開く」でも、cdで移動して行くでも
''python setup.py install''を実行すればOK!
コマンドプロンプトで ''python''と入力・実行して、起動すればpythonのセットアップはOK! 11行ぶり2度目
続いて''import cv2''を打ち込んで、何のエラーも出なければ準備完了
サンプル1.エッジ画像の出力・生成
ソースはこんなかんじ 非常にシンプルなのがお分かり頂けるだろうか?
code:_
# -*- coding: utf-8 -*-
import cv2
# 画像を読み込み
# 0はグレースケールで読み込むためのオプション
gray_img = cv2.imread('test.png',0)
# エッジ検出
# Canny Edge Detectionというアルゴリズムに則ってエッジを検出します
# 二つの数字はエッジの閾値で、大きい方がエッジがどこまで続いているかに、
# 小さい方が複数のエッジが繋がっているかに効力を発揮します
# 今回は画像が全体的に白っぽいのでそっち寄りで調整
canny_edges = cv2.Canny(gray_img,70,110)
# 結果をウィンドウに表示,enterクリックで閉じる
cv2.imshow('canny_edges',canny_edges)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 画像も生成しちゃいます
# result.pngがある場合上書きされてしまうので注意
cv2.imwrite('result.png', canny_edges)
出力結果はこんな感じ ちょっと雑な部分もあるけど、しっかりエッジをとってくれました
https://iggg.github.io/resources/assets/wiki/How_to_play_OpenCV/sample1-1.png
https://iggg.github.io/resources/assets/wiki/How_to_play_OpenCV/sample1-2.png
サンプル2.人の目検出
ソースはこちら 分類機とか特徴量とか聞きなれない言葉がありますが、「目とはどんなもの?」といったことを読み込んでると思えれば大体あってるかと
code:_
# -*- coding: utf-8 -*-
import cv2
# カスケード分類機の特徴量を取得する
cascade = cv2.CascadeClassifier(r"C:\opencv\data\haarcascades\haarcascade_eye.xml")
# 画像読み込み
img = cv2.imread("face.jpg")
# 画像のグレースケール変換
img_gray = cv2.cvtColor(img, cv2.cv.CV_BGR2GRAY)
# 画像の中に目があるかを検出
# 色んな数値は目として検出する条件のようなもの
# 次回以降にしっかりまとめます
faces = cascade.detectMultiScale(img_gray, scaleFactor=1.1, minNeighbors=3, minSize=(10, 10))
color = (255, 0, 0)
# 目を四角形で囲む処理
if len(faces) > 0:
for rect in faces:
cv2.rectangle(img, tuple(rect0:2),tuple(rect0:2+rect2:4), color, thickness=2) cv2.imshow('eyes',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 画像の保存
cv2.imwrite("result.jpg", img)
画像の出力はこちら こういった検出でよく使われる画像を採用しました
無事に目をとってくれてますね
https://iggg.github.io/resources/assets/wiki/How_to_play_OpenCV/sample2-1.png
https://iggg.github.io/resources/assets/wiki/How_to_play_OpenCV/sample2-2.png
おわりに
書いてたら止まらなくなってしまった…
サンプルの通り、OpenCVを使うと、こんな簡単にそれっぽいことができます! もっといろいろなできることとか、技術的な詳しい話はまた次回にでも
ではでは!!
余談~記事投稿にあたって~
gistとかいろいろ悩んだけど、まぁ部活の企画なので、僕個人のgithubではなくここに載せることに。 みんなgithubだろうし1人ぐらい、pukiwikiで書いてみてもいいかなとも思った(笑)
pukiwikiだと見にくい反面、画像とか見せていろいろしやすいのでまぁ良しとする
なのでというわけでもないけど、詳しく聞きたいとかあったら気軽に連絡くれれば教えますし、適宜ここに反映したいと思います。 ひっそりお待ちしています
OpenCVでいろいろする話 ~part.2 色々できることを紹介したりする編~
Advent Calender 12/09
リンク先が2日目と同じという罠
まぁあんまり似た内容の記事羅列するのもあれだから、多少はね?
何をするんだい?
タイトルの通り、いろいろできることを簡単な解説とともに載せていくよ
こんなん出来るんだ、こうするんだの参考になれば 個人的な備忘録にもなるからね、一石二鳥だね
解説の量に違いがあるのは、予め別の目的で書いていたか、新規で書いたかです1.ピクセルの色情報を取り扱ってみる
OpenCVで画像を読み込むと(たとえば変数名imgで)、Numpyの配列にピクセルの位置と色情報が格納される img でimgのi行j列目の色情報を取り扱える
- 0or1or2は色のRGB各色の値でありどれかがいる
- この時気を付けなければなのがBGRの順番で格納されているということステガノ解析プログラム
というわけで、ステガノ解析ツールを作りました(唐突) ステガノとは…(こちら) すっごく簡単に言うとファイルの中に、特定のファイルとしてそれを見ても気付かないような形で情報を隠す技術ってことです 今回はその中でも色情報に対しての埋め込み情報を解析するツールです 画像の中に埋め込まれた画像を取り出すことが多いですね
code:_
# -*- coding: utf-8 -*-
import cv2
img = cv2.imread("imput.png"); # BGRの順番, imgi,j,0or1or2 でimgのi行j列目の色情報を扱う pixelSizeTuple = img.shape;
for i in range(pixelSizeTuple0): for j in range(pixelSizeTuple1): else :
cv2.imshow("result",img);
cv2.waitKey(0);
cv2.destroyAllWindows();
cv2.imwrite('result.png', img)
これをこの画像に適用すると…
https://iggg.github.io/resources/assets/wiki/How_to_play_OpenCV/sample3-1.png
こうなるじゃ
https://iggg.github.io/resources/assets/wiki/How_to_play_OpenCV/sample3-2.png
抽出したい案件のところにどんな条件を入れるかがポイント 条件を満たすところを、白に
満たさない部分を、暗くして再描画するプログラムです
こうすると隠されていた画像を見ることができました
ステガノ画像作成プログラム
さっきの画像を作るプログラム 目に見える画像は元画像に比べ、実は全ピクセルの色情報が偶数になるように微妙に調整されています 人間は大きな情報の前では小さな情報の差異を見分けられないそうです
色情報がほんの1変わっても気付けないんですね
で裏に隠したい画像を白黒に変換して、白になっている部分を、表に出したい画像のピクセルと照らし合わせて該当ピクセルの色を1だけ増やしてあげています
要するに... 色情報all偶数のピクセル=元画像
all奇数のピクセル=埋め込まれた画
となるわけです
code:_
# -*- coding: utf-8 -*-
import cv2
# img_mainが表見える画像
# img_backが埋め込む画像
# 左上を中心に埋め込むので、同じ大きさだと綺麗に埋め込まれる
# 最低限 main > back だと、埋め込みたい画像が全部入る
img_main = cv2.imread("main.jpg");
img_back = cv2.imread("back.png");
# main画像変換:全画素情報を偶数に
pixelSizeTuple = img_main.shape;
for i in range(pixelSizeTuple0): for j in range(pixelSizeTuple1): if int(img_maini,j,0)%2 == 1 : # main画像変換処理:B値を偶数に変換 if int(img_maini,j,1)%2 == 1 : # main画像変換処理:G値を偶数に変換 if int(img_maini,j,2)%2 == 1 : # main画像変換処理:R値を偶数に変換 # back画像変換: 閾値処理で、二値画像に変換
gray_back = cv2.cvtColor(img_back, cv2.COLOR_BGR2GRAY) # 色空間の変更 imgrgb -> graygray cv2.imshow("threshold",th_back);
cv2.waitKey(0);
cv2.destroyAllWindows();
pixelSizeTuple = img_main.shape;
for i in range(pixelSizeTuple0): for j in range(pixelSizeTuple1): if int(th_backi,j) == 255 : # main画像変換処理:B値を偶数に変換 cv2.imwrite('result.png', img_main)
これに
https://iggg.github.io/resources/assets/wiki/How_to_play_OpenCV/sample3-3.jpg
これを埋め込むと
https://iggg.github.io/resources/assets/wiki/How_to_play_OpenCV/sample3-4.png
code:_
- こうなります
https://iggg.github.io/resources/assets/wiki/How_to_play_OpenCV/sample3-1.png
2.特徴点マッチング
機械学習っぽいことですね 上では学習済みの既存のデータセットを用いて、顔とかを検出しました
今回は似画像のマッチングになります 似ていると思われるところ同士を線で結んでくれます
これを応用すれば、特定の物体を検出できる……かも? ちょっと言い過ぎかもしれないけど、そういうことの第一歩ではある
他には、これを使うと二つの画像の連結とかをしてパノラマっぽい画像が出来たりもする ここは画像処理っぽい
似てる部分同士をくっつけて、一つの大きな画像が作れるなんてことも
code:_
# -*- coding: utf-8 -*-
import numpy as np
import cv2
def main():
# 画像の準備
# 最終的に2枚の画像で一致した特徴点を結ぶので2枚読み込み
# オプションをつけて、グレースケールで読み込む
img1_path = r"img1.jpg"
img2_path = r"img2.jpg"
img1 = cv2.imread(img1_path, cv2.CV_LOAD_IMAGE_GRAYSCALE)
img2 = cv2.imread(img2_path, cv2.CV_LOAD_IMAGE_GRAYSCALE)
img1_c = cv2.imread(img1_path)
img2_c = cv2.imread(img2_path)
# 各検出器・抽出器の種類の決定
# FeatureDetector : 特徴点検出 , 特徴を検出する検出器を使用する
# 特徴検出器の種類の設定 : SURF
detector = cv2.FeatureDetector_create("SURF")
# DescriptorExtractor : 特徴記述 , 特徴点に対して特徴量記述子(descriptor)を計算する
# ディスクリプタ抽出器の設定 : BRIEF
descriptor = cv2.DescriptorExtractor_create("BRIEF")
# DescriptorMatcher : 特徴点マッチング , 記述子を比較して近いものからマッチングさせる
matcher = cv2.DescriptorMatcher_create("BruteForce-Hamming")
# 特徴点検出・抽出
kp1 = detector.detect(img1)
kp2 = detector.detect(img2)
print '#keypoints in image1: %d, image2: %d' % (len(kp1), len(kp2))
# 特徴量記述
k1, d1 = descriptor.compute(img1, kp1)
k2, d2 = descriptor.compute(img2, kp2)
print '#keypoints in image1: %d, image2: %d' % (len(d1), len(d2))
# マッチング結果
matches = matcher.match(d1, d2)
print '#matches:', len(matches)
# マッチング結果よりハミング距離取得 : m.distance
# ハミング距離の最少値、平均、最大値を出力
print 'distance: min: %.3f' % min(dist)
print 'distance: mean: %.3f' % (sum(dist) / len(dist))
print 'distance: max: %.3f' % max(dist)
# 閾値設定 : 平均から求めるよ
thres_dist = (sum(dist) / len(dist)) * 0.00001
# 閾値以下のハミング距離のマッチング結果だけを抽出
print '#selected matches:', len(sel_matches)
# マッチングの可視化について
# 2画像の縦横情報の抽出
# 画像を入れる配列生成
view = np.zeros((max(h1, h2), w1 + w2, 3), np.uint8)
# 左半分に画像1、右半分に画像2
# もともとグレースケールなので、GBRの三つの値を同じにしておく
# 特徴量同士の連結描画
for m in sel_matches:
# 色を乱数からランダムに生成
# m.queryIdx : クエリディスクリプタインデックス
# m.trainIdx : 訓練ディスクリプタインデックス
cv2.imshow("view", view)
cv2.waitKey()
cv2.destroyAllWindows()
cv2.imwrite('view.jpg', view)
if __name__ == "__main__":
main()
これと https://iggg.github.io/resources/assets/wiki/How_to_play_OpenCV/sample4-1.jpg
これを https://iggg.github.io/resources/assets/wiki/How_to_play_OpenCV/sample4-2.jpg
こんな風にマッチングできる https://iggg.github.io/resources/assets/wiki/How_to_play_OpenCV/sample4-3.jpg