
Pythonでwebカメラを操作できるようになれば、実時間で様々な処理が可能になります。ここでは、人間の視線が行く場所を推定する計算に用いられる「サリエンシーディテクション」をwebカメラの画像に対して適用した事例を紹介します。
こんにちは。wat(@watlablog)です。
webカメラをプログラムで扱えるようになったので、リアルタイムにサリエンシーディテクションの計算を行う方法を紹介します!
Pythonを使ったWebカメラ操作
「Python/OpenCVでWebカメラの情報をリアルタイムに表示」では、Pythonでwebカメラにアクセスしてリアルタイムに画像情報を取得する基本のコーディングを習得しました。
ここではそのコードに少し手を加えるだけでリアルタイムに画像処理結果を表示させる方法を紹介します。
Webカメラの情報をリアルタイムに表示させる
まず初めに前回のおさらいですが、Python等のプログラムを使ってWebカメラにアクセスすると、フレームと呼ばれる1枚1枚の静止画を取得することができます。
以下の図のように、このフレームをPCのディスプレイに単純に表示させるというのが、前回の記事の内容でした。

Webカメラの情報に画像処理を施してから表示させる
今回は上記処理に加え、フレーム画像に画像処理を施したものをPCに表示させるだけです。
以下の図はそのイメージですが、上記リアルタイム表示との違いとして画面表示させる直前に画像処理を行うというのが今回の内容です。

サリエンシーディテクションのおさらい
サリエンシーディテクションは目立つ場所を特定する計算手法
今回Webカメラで行う画像処理は、「Pythonでサリエンシーマップを作成!人の視線の行き場を数値化」で行った内容です。
サリエンシーとは、顕著性という意味で、サリエンシーの計算は簡単に言うと画像の中で目立つ場所を計算で定量的に特定しようというものです。
以下の図は先ほど紹介した記事の内容ですが、元の画像に対してサリエンシーディテクションの計算をかけると、サリエンシーマップという輝度値分布を得ることができます。

この輝度値の高い部分が人の視線の行きやすい場所になっていると言われております。この技術は人の視覚の数値化の1つと考えられ、既にスマートな機能を積むために様々な産業界で利用され始めている技術です。
サリエンシーディテクションの応用例
当WATLABブログでは、そんなに難しい応用をしているわけではありませんが、サリエンシーディテクションを使った応用例として「Pythonでブログの広告が目立つかどうか「動的」に評価する方法」に示す内容を紹介しました。
この記事では、予めスマホを使ってWebページをスクロールしながら閲覧した動画ファイルに対しサリエンシーディテクションを使い、「ページの中でどこに視聴者の視線が行きやすいか?」を可視化しました。
そして記事の中ではマップを得るだけではなく、さらにサリエンシー値が高い場所を特定して、下の図のように円を描画することをやってみました。

しかしこの内容では、予め動画を用意する工程が必要でいまいち汎用性にかけていました。
今回はこの処理をWebカメラで取得したフレームに対して適用することで、リアルタイムにサリエンシーを検出するコードを紹介します。
Webカメラでサリエンシーディテクションを行うPythonコード
実行例
百聞は一見にしかず!まずは以下のYouTube動画をご覧下さい。
今回行う処理は、Webカメラで映し出した映像に対してサリエンシーディテクションをかけるので、動画ファイルを用意する必要はありません。
以下の動画は実際にWebカメラで被写体の撮影を行っている最中のPC画面をキャプチャしたものです。
上記動画では円を描画して目立つ場所の一点のみを指示していましたが、実際にやっている画像処理のイメージは以下の動画のように画像の明暗を使っています。
全コード
実行例の動画を見るとプログラムコードのイメージがつきやすいと思いますが、以下が今回のプログラムの全コードになります。
brightnessは画像情報を受け取って輝度値の高い位置座標を特定するための関数ですが、詳細のアルゴリズムの説明は「Pythonでブログの広告が目立つかどうか「動的」に評価する方法」に記載しましたので、ご興味のある方は是非参照してみて下さい。
camera=の部分からはWebカメラの処理です。ここに記載しているサリエンシーディテクションの方法も上記記事に使い方を記載しています。今回は「Python/OpenCVでWebカメラの情報をリアルタイムに表示」で紹介したWebカメラの扱い方と併用しているだけです。
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
import numpy as np import cv2 # 画像の中でどこが最も明るいかを調べる関数 def brightness(img): h, w = img.shape[:2] # グレースケール画像のサイズ取得(カラーは3) x = int(w / 20) # 領域の横幅 y = int(h / 20) # 領域の高さ x_step = x # 領域の横方向へのずらし幅 y_step = y # 領域の縦方向へのずらし幅 x0 = 0 # 領域の初期値x成分 y0 = 0 # 領域の初期値y成分 j = 0 # 縦方向のループ指標を初期化 latest = 0 # 最新の平均輝度値 coordinate = [0, 0] # 最も明るい領域の座標値 # 縦方向の走査を行うループ while y + (j * y_step) < h: i = 0 # 横方向の走査が終わる度にiを初期化 ys = y0 + (j * y_step) # 高さ方向の始点位置を更新 yf = y + (j * y_step) # 高さ方向の終点位置を更新 # 横方向の走査をするループ while x + (i * x_step) < w: roi = img[ys:yf, x0 + (i * x_step):x + (i * x_step)] # 元画像から領域をroiで抽出 # ここからが領域に対する画像処理 # 領域毎に平均輝度を算出し、これまでの平均値と比べ大きかったらlatestを更新 ave = np.mean(roi).astype("uint8") if latest < ave: latest = ave coordinate = [i, j] else: pass img[ys:yf, x0 + (i * x_step):x + (i * x_step)] = np.full(roi.shape, ave) # ここまでが領域に対する画像処理 i = i + 1 # whileループの条件がFalse(横方向の端になる)まで、iを増分 j = j + 1 # whileループの条件がFalse(縦方向の端になる)まで、jを増分 # 最も明るい領域の中心座標を計算 px = int(coordinate[0] * x_step + (x / 2)) py = int(coordinate[1] * y_step + (y / 2)) return px, py, img camera = cv2.VideoCapture(0) # カメラCh.(ここでは0)を指定 # 撮影=ループ中にフレームを1枚ずつ取得(qキーで撮影終了) saliency = cv2.saliency.StaticSaliencyFineGrained_create() # サリエンシーディテクション用の設定 while True: ret, frame = camera.read() # フレームを取得 # ここからサリエンシーディテクション bool, map = saliency.computeSaliency(frame) # frameに対してサリエンシーディテクション map = (map * 255).astype("uint8") # マップの輝度値を0-255にする px, py, img = brightness(map) # どこが最も明るいか、座標を調べる関数を実行 i_saliency = cv2.circle(frame, (px, py), 50, (255, 0, 0), 20) # 計算された座標にサークルを描画する cv2.imshow('camera', i_saliency) # フレームを画面に表示 # キー操作があればwhileループを抜ける if cv2.waitKey(1) & 0xFF == ord('q'): break # 撮影用オブジェクトとウィンドウの解放 camera.release() cv2.destroyAllWindows() |
まとめ
本ページではWebカメラを使ったリアルタイム映像表示と、人の視線の行き場を数値化するサリエンシーディテクションのコラボレーションを紹介しました。
今回の方法の画像処理部分を色々変えることで様々なWebカメラ処理ができるようになりますので、是非お試し下さい。
やっとWebカメラに対する画像処理が出来てきた!これは可能性が拡がったね!
Twitterでも関連情報をつぶやいているので、wat(@watlablog)のフォローお待ちしています!