備忘録

備忘録

C#でテンプレートマッチを行う

Ⅰ. はじめに

OpenCV3 のラッパーである OpenCvSharp の MatchTemplate メソッドを使ってテンプレートマッチを行います。

Ⅱ. サンプル

スクリーンショットを取り、メモ帳のアイコンを探すサンプルです。

NuGet から OpenCV3 のラッパーをインストールする。

f:id:kagasu:20170609192018p:plain

Install-Package OpenCvSharp3-AnyCPU
template.png

f:id:kagasu:20170609191705p:plain

Program.cs
class Program
{
  /// <summary>
  /// スクリーン全体のスクリーンショットを撮る
  /// </summary>
  static Bitmap TakeFullScreenScreenShot(int width, int height)
  {
    var bmp = new Bitmap(width, height, PixelFormat.Format32bppRgb);
    //var bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb);
    using (var g = Graphics.FromImage(bmp))
    {
      g.CopyFromScreen(0, 0, 0, 0, bmp.Size);
    }

    return bmp;
  }

  /// <summary>
  /// テンプレートマッチを行う
  /// </summary>
  static (OpenCvSharp.Point minPoint, OpenCvSharp.Point maxPoint) MatchTemplate()
  {
    var screen = BitmapConverter.ToMat(TakeFullScreenScreenShot(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height));
    var template = BitmapConverter.ToMat(new Bitmap("template.png"));

    var result = new Mat();
    Cv2.MatchTemplate(screen, template, result, TemplateMatchModes.CCoeffNormed);
    Cv2.Threshold(result, result, 0.8, 1.0, ThresholdTypes.Binary);
    Cv2.MinMaxLoc(result, out OpenCvSharp.Point minPoint, out OpenCvSharp.Point maxPoint);

    //screen.Rectangle(maxPoint, new OpenCvSharp.Point(maxPoint.X + template.Width, maxPoint.Y + template.Height), Scalar.Red);
    //screen.SaveImage("out.bmp");
    
    return (minPoint, maxPoint);
  }

  static void Main(string[] args)
  {
    MatchTemplate();
  }
}

Ⅲ. 実行結果

メモ帳ウィンドウの左上のアイコンのテンプレートマッチに成功し、四角い枠が付いています。
f:id:kagasu:20170609191434p:plain

Ⅳ. エラー対策

ハンドルされていない例外:
OpenCvSharp.OpenCVException:
(depth == CV_8U || depth == CV_32F) && type == _templ.type() && _img.dims() <= 2

Windowsに標準でインストールされているペイントで画像をpng形式で保存した場合、
アルファ値の有無が変わる場合があります。(なぜ変わるか、詳細はよく分かってないです)
PixelFormat を適切に設定すると解決します。

Photonの生パケットを読む

Ⅰ. はじめに

1. Photon とは

クロスプラットフォームで動作する「ネットワークエンジン」です。
ドイツのベンチャー企業「Exit Games」が開発しています。

クラウド(SaaS)」と「オンプレミス」が選択できます。
アジアリージョンのクラウドGMOが独占して提供しています。

サーバは Windows Server のみで動作します

2. 仕組み

Photon には「ネームサーバ」と「マスタサーバ」と「ゲームサーバ」が存在します。
※この記事では「ネームサーバ」について触れません。
「マスタサーバ」は「ゲームサーバ」のインスタンスの状態を全て監視します。
負荷状態等をもとにユーザーをどの「ゲームサーバ」に割り当てて通信させるか最適な選択を行います。

Ⅱ. マスタサーバの生パケットを読む

詳しいことはこちらに書いてあるようです。

英語
https://doc.photonengine.com/en-us/onpremise/current/reference/binary-protocol
日本語
https://doc.photonengine.com/ja-jp/onpremise/current/reference/binary-protocol

重要な部分だけをメモ。

1. 赤色の枠で囲んでいる部分を見つける


画像の場合 0x04 0xF3 0x02 です。

# 意味
1バイト目 データ送信(受信)回数
2バイト目 0xF3固定
3バイト目 不明。0x01~0x10の場合が多い

2. 緑色の枠で囲んでいる部分を見つける


画像の場合 0xE1 です。
この部分は 「OperationCode」 を意味しています。
0xE1 を 10進数表記すると 225 です。
以下のリファレンスから 225 は OperationCode.JoinRandomGame であることが解ります。
https://doc-api.photonengine.com/en/dotnet/current/class_exit_games_1_1_client_1_1_photon_1_1_load_balancing_1_1_operation_code.html

3. オレンジ色の枠で囲んでいる部分を見つける


画像の場合 0x00 0x04 です。
この部分は「パラメータが何個あるか」を意味しています。
0x00 0x04の場合4個です。

4. 水色の枠で囲んでいる部分を見つける


画像の場合 0xD5 です。
この部分は「ParameterCode」を意味しています。
0xD5 を 10進数表記すると 213 です。
以下のリファレンスから 213 は ParameterCode.LobbyName であることが解ります。
https://doc-api.photonengine.com/en/dotnet/current/class_exit_games_1_1_client_1_1_photon_1_1_load_balancing_1_1_parameter_code.html

5. ピンク色の枠で囲んでいる部分を見つける

画像の場合 0x73 です。

この部分は「GpType」を意味しています。
0x73 を 10進数表記すると 115 です。
GpType は 逆コンパイラを用いて調べます。
以下の表から 115 は GpType.String であることが解ります。

GpType 値(10進数)
Array 121
Boolean 111
Byte 98
ByteArray 120
ObjectArray 122
Short 107
Float 102
Dictionary 68
Double 100
Hashtable 104
Integer 105
IntegerArray 110
Long 108
String 115
StringArray 97
Custom 99
Null 42
EventData 101
OperationRequest 113
OperationResponse 112

6. 茶色の枠で囲んでいる部分を見つける


画像の場合 0x00 0x01 です。
この部分は「長さ」を意味しています。
0x00 0x01 の場合1バイトです。

5 の項目が GpType.String だったので、String型で1バイトということが解ります。

7. 紫色の枠で囲んでいる部分を見つける


画像の場合 0x31 です。
この部分は「データの値」を意味しています。
5 の項目が GpType.String だったので、0x31はASCII文字コード表より'A'であることが解ります。

8. これ以降は同様にします。

留意点
・ParameterCode の Enum に含まれてない値が出てきた。
Photon マスタサーバに対する独自の拡張です。
Photon Server (On-Premises) を利用している場合は独自の拡張が可能となります。

・GpType.String は最大 0xFFFF バイトです。
・GpType.ByteArrayは最大 0xFFFFFFFF バイトです。

Ⅲ. ゲームサーバの生パケットを読む

こちらを使います。
WiresharkLua スクリプを読み込むだけです。
https://github.com/AltspaceVR/wireshark-photon-dissector

C#で bzip2 の圧縮、展開を行う方法

Ⅰ. はじめに

タイトルの通り「C#で bzip2 の圧縮、展開を行う方法」です。
bzip2のマジックナンバーは「BZh」(45 5A 68)です。
f:id:kagasu:20180214183022p:plain

Ⅱ. SharpZipLib をインストールする

SharpZipLib というライブラリを使います。

1. NuGet から SharpZipLib で検索し、インストールする。

f:id:kagasu:20170519230429p:plain
※.NET Standard 版もありますが、作成者の名前が異なるので非公式リリースのような気がします。
(深く調べていないので詳細は不明です。)
f:id:kagasu:20170519230500p:plain

Ⅲ. サンプル

1. 圧縮する

private byte[] BZip2Compress(byte[] bytes)
{
  var outStream = new MemoryStream();
  BZip2.Compress(new MemoryStream(bytes), outStream, true, 9);
  return outStream.ToArray();
}

2. 展開する

private byte[] BZip2Decompress(byte[] bytes)
{
  var outStream = new MemoryStream();
  BZip2.Decompress(new MemoryStream(bytes), outStream, true);
  return outStream.ToArray();
}

Ⅳ. その他

isStreamOwner を true にすると自動的に stream を close してくれます。
level は 0-9 までの数値です。0が圧縮率が最低で、9が圧縮率が最高です。