YMSBで試そうと思っていた「配信画面から画像認識で勝者を判定し、自動的にスコアボードに反映させる」ことに成功したので、その方法をドキュメントとして残しておきます。
今回は例としてVFes(VF5REVO、VF5US)で解説していきます。
OBSで画像認識させる
Advanced Scene SwitcherをOBSにインストールする
OBSプラグイン「Advanced Scene Switcher」をインストールしましょう。
このプラグインを使って画像認識を行います。他にもシーンの変更やトラジション、音声などをキーにして色々な動作ができる高機能プラグイン……のようです。筆者は使いこなしきれていません。
Advanced Scene Switcherのダウンロードはこちらから!


ダウンロードできたら、インストーラーの場合はダブルクリックでインストールが始まります。
完了後、OBSを起動すると「ツール」に「高機能シーンスイッチャー」というものがあればOK!
※筆者もこのポストを残すにあたり再インストールしたのですが、最新版は日本語対応されてるのですね……1.26.1の時は全部英語だったのに、世の中便利になったものじゃのう。

Advanced Scene Switcherの設定
これは実際の設定画面を見た方が理解が早いでしょう!
「高機能シーンスイッチャー」を開いて、マクロタブから以下の画像のように設定してみましょう。
マクロ名はなんでも構わないです。今回は「VFes_GetR1」としています。
他、ほとんどの項目が日本語で記載されているので、詳細な説明は省略します。

画像は判定させたい画像を自分で用意しましょう。
今回はVFesから、1P側が3ラウンド取得した状態のランプを切り抜いて使っています。
なお、ランプ周りの背景は自分で削除して透明な状態にしているので、マクロ設定でも「パターンのマスクとしてアルファチャンネルを使用します」にチェックを入れています。
画像認識のテスト
画像を指定できたら「ショーマッチ」ボタンをクリック。
実際に動画などを流すと、画像認識のマッチ度を表示してくれます。
マッチしたい場合のシーンのマッチング値を参考に、マクロの「閾値」を調整していきましょう。


OBSから自前プログラムにWebsocketを出す
OBSのマクロ設定
先ほどのマクロ設定画面の右下部分の設定は「画像がマッチした場合にOBSが行う処理」を示しています。
今回は自作プログラム(YMSBコントローラー)に「GetSet : 1」というメッセージを含めたWebsocketを送信するように設定しています。

OBSのWebSocketサーバー設定
OBSと自作プログラムと連携させるために、OBS側でWebSocketサーバー設定を行います。
「ツール」から「WebSocketサーバー設定」を選択してください。

設定は下の画像の通り。
「WebSocketサーバーを有効にする」と「認証を有効にする」にチェックを入れておきましょう。

自作プログラム側で必要になる「サーバーパスワード」はこの画面では見えませんが、「接続情報を表示」をクリックした先の画面で見えるので、コピーして自作プログラム側で使いましょう。
自作アプリ側のシーケンス
自作アプリ側……YMSBはJavaScriptを使ってコーディングしています。
簡単なシーケンスはこんな感じ。
詳細を解説していますが、概要だけが欲しい場合は次項のコードへGO。

①アプリ→OBSへ接続
プログラム側から「new WebSocket()」でOBSへ接続を作成します。
②アプリ内でイベントハンドラを作成
作成したWebSocketのイベントハンドラを作成。
これでOBS側からメッセージを受信した場合の処理を用意しておきます。
③OBS→アプリへ認証開始
①の直後にOBSから認証開始のメッセージが来ます。
この中にSHA256でハッシュ値を作成するためのソルト値とチャレンジ値が入っているので、その値とOBSのサーバーパスワードを使ってハッシュ値を作成します。
④アプリ→OBSへ認証応答
ハッシュ値と、どのイベントをOBSから受け取るか(eventSubscription)を送信します。
eventSubscriptionの詳細は以下の通り。
今回はAdvanced Scene Switcherからのイベントメッセージを受けたいので、["Vendors"]のビットを立てる = 2^9 = 512を設定する形になります。
/* eventSubscriptions bitpattern
["None"] = 0,
["General"] = 1 << 0,
["Config"] = 1 << 1,
["Scenes"] = 1 << 2,
["Inputs"] = 1 << 3,
["Transitions"] = 1 << 4,
["Filters"] = 1 << 5,
["Outputs"] = 1 << 6,
["SceneItems"] = 1 << 7,
["MediaInputs"] = 1 << 8,
["Vendors"] = 1 << 9,
["UI"] = 1 << 10,
["InputVolumeMeters"] = 1 << 16,
["InputActiveStateChanged"] = 1 << 17,
["InputShowStateChanged"] = 1 << 18,
["SceneItemTransformChanged"] = 1 << 19,
*/
⑤OBS→アプリへ認証完了メッセージ
ハッシュ値が正しいものであれば、OBSからアプリへ認証完了メッセージが送られます。
これで画像認識時のメッセージを受け取れるようになります。
⑦再認証メッセージ
eventSubscriptionsを変更したい場合は再認証メッセージを送ります。
YMSBでは必要ないのでここは省略。
アプリ→OBSへ動作要求
実はOBSのシーンチェンジなどの要求をアプリ→OBSへ送ることもできます。
こちらもYMSBでは実装予定はありませんので省略します。
自作アプリ側のソース
まずはメイン部。
#obsPassに先ほどのWebSocketサーバーのサーバーパスワードを設定しておきます。
OBSのURLはws://127.0.0.1:4455でOK。
let OBS_PASS = "";
const OBS_URL = 'ws://127.0.0.1:4455'
let OBS_SOCKET = "";
// ■■ OBS連携開始 ■■
const startOBSLink = () => {
if ("" == jQuery("#obsPass").val()) {
// error
}
else {
OBS_PASS = jQuery("#obsPass").val();
OBS_SOCKET = new WebSocket(OBS_URL);
OBS_SOCKET.addEventListener("message", (event) => {
const rcvData = JSON.parse(event.data);
console.log("rcv[Message] : ", rcvData);
if (0 == rcvData.op) {
const rcvSalt = rcvData.d.authentication.salt;
const rcvChal = rcvData.d.authentication.challenge;
const rcvRpcv = rcvData.d.rpcVersion;
sendIdentify(rcvSalt, rcvChal, rcvRpcv);
}
else if (5 == rcvData.op) {
if (512 == rcvData.d.eventIntent) {
const msg = rcvData.d.eventData.eventData.message;
console.log("rcv[message] : " + msg);
switch (msg) {
case "GetSet : 1" :
sumScore(0);
break;
case "GetSet : 2" :
sumScore(1);
break;
default:
break;
}
}
}
});
}
}
続いてSHA256でハッシュ化する処理。
これを実装するにあたって「jsSHA」というライブラリを使わせてもらいました。
const EVENT_SUB = 512;
const sendIdentify = (rcvSalt, rcvChal, rcvRpcv) => {
const salt = rcvSalt;
const challenge = rcvChal;
const pass = OBS_PASS;
const textHash = new jsSHA("SHA-256", "TEXT");
textHash.update(pass);
textHash.update(salt);
const hash = textHash.getHash("B64");
const textHash2 = new jsSHA("SHA-256", "TEXT");
textHash2.update(hash);
textHash2.update(challenge);
const resp = textHash2.getHash("B64");
const sendData =
{
"op": 1,
"d": {
"rpcVersion": rcvRpcv,
"authentication": resp,
"eventSubscriptions": EVENT_SUB
}
};
sendToOBS(sendData);
}
const sendToOBS = (sendData) => {
const sendDataJSON = JSON.stringify(sendData, null, 2);
OBS_SOCKET.send(sendDataJSON);
console.log("sendToOBS : ", sendData);
}
最後に画像認識メッセージを受信したときにスコアをカウントアップする処理sumScore()を実装して完了。ここは任意の処理になるのでソースコードは割愛します。
参考文献
先人たちの経験と情報展開に大いなる感謝を。



