「C++」カテゴリーアーカイブ

Heroes of the Storm のスクリーンショットのプレイヤー名をぼかすプログラム作成

ブログ記事を書くときに、スクリーンショットのプレイヤー名にボカシを入れる処理を、毎回やるのが面倒そうなので、そういうプログラムを作ってみました。

方針

引数でスクリーンショットの画像ファイルを渡すと、プレイヤー名の位置にボカシを入れた画像ファイルを生成することにします。

実装

OpenCV の matchTemplate() を使って、用意した体力フレーム画像とマッチングを行います。
具体的には、赤青それぞれのチームの以下のような画像をゲーム中の画像から切り抜いて用意しました。 jpg 画像から切り抜いたせいか、微妙に各チームの色味があるのがわかります。

blue_frame red_frame

ソースコードの処理概要は、引数で渡された画像を読み込み、枠のテンプレート画像とのマッチングを順番に行っていることくらいです。 難しくないです。

ソースコードへのリンク

動作例

hots_training_clipped hots_training_clipped.png.masked

このくらいの重なりぐらいなら、適切に処理できます。
(名前でない場所にボカシを入れたり、名前のある箇所を検出できなかったりすることもあります)

ソースコードの場所

下記アドレスで Mercurial 管理しています。
https://bitbucket.org/satofumi/hots_tools

今後の予定

もう少し自分で使ってから、Windows 版を作成して配布します。(使ってみたい方は、お知らせ下さい。大喜びでお渡しします)
あとは、このプログラムとは別ですが、ゲーム中の視線を記録してミニマップを見るよう矯正したり、脈拍を計測して自分にどういう影響があるかを可視化するプログラムも作っていきたいと思っています。

Window Athletic の仕組み (その2)

前回 に引き続き Window Athletic の紹介です。 今回は、プロ生ちゃんのテーマを構成するファイルの説明と、テーマを駆動する Lua スクリプトの解説です。

pronama_screenshot

まず、テーマファイルは、以下のファイル群から構成されます。

  • README.txt
  • COPYING.txt
  • logo.png
  • events.lua
  • resource.yaml
  • 画像ファイルとか

テーマファイルとは、これらのファイルを Zip (のような) 圧縮したものになっています。
(Zip のような 圧縮、という表現になる理由は、「zlib 使って圧縮まわりを実装したんだけど、途中で手を抜いたせいで既存の Zip ツールでは展開できないから」 です。 察して頂けると助かります)
(11/28 追記: zip コマンドが扱えるようになりました!)

それぞれのファイルについて簡単に説明すると、README.txt, COPYING.txt, logo.png は、アプリのテーマ変更フォームで表示されるデータになっています。 また、resource.yaml には利用する画像ファイル名や、画像ファイルをどう組み合わせて 1つのセルにするか、という定義がなされています。

resource.yaml の抜粋。(全文へのリンクは、こちら)

- Image:
  - Background: background.png
  - Parts:
      left_0: [ 01-1.png, +16+0 ]
      left_1: [ 01-2.png, +16+0 ]
      left_2: [ 01-3.png, +16+0 ]

そして events.lua には、アプリから定期的に呼び出される関数などが定義されていて、この Lua スクリプトで、マスコット画像をどの位置に、どの画像で表示するか、といったことを制御しています。 以下では、この events.lua について具体的に説明していきます。
events.lua の API については、このページ にドキュメントがあります。

events.lua の役割は、アプリから「これの処理をしてね」っていう依頼が来た時に、それをこなすことです。 具体的には、以下の関数がアプリ側から呼び出されます。

  • initialize_theme() … テーマが読み出された時に1回だけ呼び出される関数です。
  • window_rects_changed() … デスクトップ上のウィンドウの位置や大きさが変更されたら呼び出される関数です。
  • add_actor(actor) … マスコットが追加されたときに呼び出される関数です。マスコッとの初期化などを行います。
  • remove_actor(actor) … マスコットが削除されるときに呼び出される関数です。
  • update_actor(actor) … マスコット毎に 25 msec 間隔で呼び出される関数です。 ここでマスコット位置や画像の更新を指示します。 この関数の戻り値で false を返すことでマスコットの削除を指示します。 (false を返すことで、引き続き remove_actor() が呼び出されます)

プロ生ちゃんのテーマの場合だと、各関数の役割は、以下のようになります。

  • initialize_theme() … 乱数シードの初期化。
  • window_rects_changed() … ウィンドウ情報から、地面とみなす直線を計算する。
  • add_actor(actor) … 新たなプロ生ちゃん生成の処理を行う。
  • remove_actor(actor) … 特に何もしていない。
  • update_actor(actor) … プロ生ちゃんの足元に地面があるかを判定して、落下させたり移動させたりする。 プロ生ちゃんが画面外まで移動したら false を返してプロ生ちゃんを削除する。

events.lua の全文は このリンク になります。 このスクリプトを修正して pronama.dat を作り直すと、テーマの挙動が変更できます。

最後に events.lua において注意するべき点を、2点ほど説明します。

  1. events.lua は、マスコットが作られる毎に読み込まれる。
  2. マスコット(character) 毎のデータは character:set_data(), character:data() を用いて管理する。
マスコット(character) 毎のデータは character:set_data(), character:data() を用いて管理する。

マスコットのデータを保存するために、add_character(), remove_character(), update_character() の引数に渡される character を用います。 character:set_data(key, value), data = character:data(key) といった使い方ができます。 set_data(), data() では文字しか扱えないので、数値を扱う場合には文字に変換してから処理する必要があります。

-- 文字データを保存したり読み出したりする場合
character:set_data('state', 'falling')
state = character:data('state')
数値データを保存したり読み出したりする場合
character:set_data('x', "" .. x)
x = character:data('x') + 0

ここまでで、Window Athletic の簡単な説明はおしまいになります。

何か不明な点があれば、質問して頂ければ追記などいたしますので、コメントをお願いします。

Window Athletic の仕組み (その1)

Window Athletic とは、デスクトップ上のウィンドウ情報を取得して、マスコット画像を表示するアプリです。 (http://hyakuren-soft.sakura.ne.jp/window_athletic/)
ウィンドウの上をマスコットが走ったり、落ちてくるずんだ餅を食べさせたりと、色々できます。

pronama_screenshot zunko_screenshot

この記事では、このアプリの仕組みを解説していきます。
まず、大雑把に説明すると、

  1. ウィンドウの位置情報を取得する。
  2. マスコットを表示するためのウィンドウを作成して、描画する。
  3. マスコットの位置と、どの画像を描画するかは、Lua スクリプトで制御する。
  4. ウィンドウの情報が更新されたら、アプリから Lua スクリプトに通知する。

という処理をしています。
というか、それだけです。

以下の画像を見ると、仕組みがイメージしやすいと思います。

window_athletic_frame
ウィンドウ枠を消さずに表示したときの動作

アプリ全体の動作は、アプリとテーマとの組み合わせで実現されています。
テーマの中には Lua スクリプトや画像ファイルが Zip (のような) 圧縮をされており、アプリがプレイヤーで、テーマがデータとして動作します。

具体的な実装に興味がある方は、ソースコード をご覧ください。
それでは、次回はプロ生ちゃんのテーマのスクリプト紹介をしていこうと思います。

Qt で Windows のタスクバーにアプリ名を表示させないようにする

Qt でマスコット系のアプリを作っていると、タスクバーにアプリ名が表示されるのを抑制したいことがあります。(抑制すると Alt-Tab を押したときにも表示されなくなる) そういう場合、単に

#if defined(Q_OS_WIN)
    WId wid = winId();
    LONG style = GetWindowLong(wid, GWL_EXSTYLE);
    SetWindowLong(wid, GWL_EXSTYLE, style | WS_EX_TOOLWINDOW);
#endif

を追記してもよいのですが QWidget::setWindowFlags() が SetWindowLong() を呼び出しているせいか、設定がうまく反映されなかったりしました。

仕方がないので、タスクバーへのアプリ名表示を抑制する Widget クラスに(例えば Balloon_widget) の setWindowFlags() をオーバーライドして、以下のようにしました。

void Balloon_widget::setWindowFlags(Qt::WindowFlags flags)
{
    QWidget::setWindowFlags(flags);
#if defined(Q_OS_WIN)
    WId wid = winId();
    LONG style = GetWindowLong(wid, GWL_EXSTYLE);
    SetWindowLong(wid, GWL_EXSTYLE, style | WS_EX_TOOLWINDOW);
#endif
}

親クラスのメソッドを呼び出してから、setWindowLong() を呼び出すようにしただけですが、こんな感じでうまくいきます。

SICK LMS5xx 用の C++ ドライバの作成 (マルチエコーを扱えるようにした)

LMS511 用に開発している C++ ドライバの Lms_driver で、マルチエコー情報を扱うあたりを実装した。

lms_viewer_2013_1217
2エコー目の距離が水色で表示されている

とりあえずは利用できるようになったので、ここまでの実装を hrk_lidar という名前のライブラリとして公開した。URG や LMS センサ用の C++ ドライバで Windows, Linux, Mac で動作する。

hrk_lidar, Lidar_viewer パッケージのダウンロードページ
https://bitbucket.org/satofumi/hobby_robot_sdk/downloads

ドライバの細かな修正は、使いながら行っていきたい。
あとは、このドライバで利用している Viewer も Lidar_viewer という名前のパッケージにして公開した。(Windows 版 binary は Lidar_viewer_win? という名前)

今後は、前回の実験で取得したデータを解析するあたりを行いたい。

SICK LMS5xx 用の C++ ドライバの作成 (強度情報を取得できるようにした)

暇なわけではないが、メイン仕事をする気が起きなかったので Lms_driver.cpp に強度情報を取得するあたりの機能を実装した。
https://bitbucket.org/satofumi/hobby_robot_sdk/src/b5734dc0ba50bf78957748e978cf05223d2d1f3d8/lib/lidar/Lms_driver.cpp?at=default

lms_viewer_2013_1210
オレンジ色のプロットが強度情報

正面に回帰反射版を置いたところ、そこの値が 16 進数の 8 bit 表記で 0xFE になっているのが確認できた。(0xFF には、ならないようだ)

強度データが 0xFE になる特性を利用すれば、反射版かどうかの判定が簡単にできるはず。是非、次回の実験時にこのあたりの情報をうまく使っていきたい。

残るは複数エコーを取得するあたりだが、その実装はまた今度にしたい。

 

SICK LMS5xx 用の C++ ドライバ作成 (Scale Factor の修正)

作成中の Lms_driver で取得した距離が 1/2 になっていたので修正した。
LMDscandata コマンド応答の Scale Factor が x2 なのに、取得した距離データをそのまま表示していたのが原因だった。

lms_viewer_2013_1207
修正前

lms_viewer_2013_1207_2nd
修正後

引き続き、強度情報を取得したりするあたりを実装したい。