【ZXing.Net】C#でQRコードの読取

#C#でQRコードを読みたい
色々調べましたところ、C#でそこそこ使えそうなQRコードライブラリとしては2つくらいに絞れそうでした。
その中からZXing.Netを採用して実験

##準備
環境はVisualStudio 2017
nugetパッケージマネージャから以下コマンド実行

```
Install-Package ZXing.Net -Version 0.16.4
```

##簡易な読取

```C#

//QRコードの映った画像ファイルからビットマップを生成する

//var img = new Bitmap(filename);
//とすると、imgをDisposeするまで
//プロセスが読み込んだビットマップファイルを掴んだままになってしまいます。
//filestreamで読み込むとこの現象を避けられます。
System.IO.FileStream fs = new System.IO.FileStream(
                filename,
                System.IO.FileMode.Open,
                System.IO.FileAccess.Read);
            System.Drawing.Image img = System.Drawing.Image.FromStream(fs);
            fs.Close();
// QRコードの解析
ZXing.BarcodeReader reader = new ZXing.BarcodeReader();
//ZXingに渡すのはBitmap
ZXing.Result result = reader.Decode(new Bitmap(img));

//これでQRコードのテキストが読める
var text = result == null ? string.Empty : result.Text;
//因みにresult.BarcodeFormatでコード種類が取れます。
//QRコードならZXing.BarcodeFormat.QR_CODEのはずです。

```

##実験
文字列「1234567890」をZxingでエンコードした画像を用意しました。

```C#
// QRコードを生成するエンコーダ
var encoder = new ZXing.QrCode.QRCodeWriter();
//ここでQRコードのオプションが色々指定できるようです。
var encodeHints = new Dictionary<EncodeHintType, object>()
{
    { EncodeHintType.CHARACTER_SET, "shift_jis" },
    { EncodeHintType.ERROR_CORRECTION, ZXing.QrCode.Internal.ErrorCorrectionLevel.M }
};

var writer = new BarcodeWriter();
//このimageを画像として吐き出します。
var image = writer.Write(
    encoder.encode(
        "1234567890",//エンコードする文字列
        ZXing.BarcodeFormat.QR_CODE, //ここで指定を変えればバーコードなども作れる模様
        400, 400, //width*heght
        encodeHints
        )
    );

```

StopWatchで処理時間を計測してみました。
デバッグ実行しましたので実際はもう少しパフォーマンス出るかも知れません。

###きれいなQRコードを読み込んでみる
![QRTEST_0.png](https://qiita-image-store.s3.amazonaws.com/0/241416/d251f4e5-7891-a7d2-a7e1-d204ed3cd770.png)

読取結果

|回数|処理時間[ms]|備考|
|---|---|---|
|1|399|起動後初回|
|2|6||
|3|107|起動後初回|
|4|6||
|5|25||
|6|25||
|7|22||

起動後にはインスタンス生成の為か時間がかかる傾向があります。
その次はやたら速い・・・。
キャッシュしてるのでしょうか。
その次からは20ms中盤に落ち着きつつあるように見えます。

###ぼやけたQRコードを読ませてみる
100*100Pixにサイズダウンし、OpenCVSarpでガウシアンフィルタをかけた画像を用意。

```C#
//imageは上で生成したQRコードです。
//この時サイズは100*100にして実験してました。(上では400*400になってますが)
var imageMat = OpenCvSharp.Extensions.BitmapConverter.ToMat(image);
var filterSize = 5;//ここで1,3,5,7と変更しました。
//偶数はガウシアンフィルタの原理上指定できないようです。
//偶数を指定するとExceptionが発生します。
imageMat = imageMat.GaussianBlur(new OpenCvSharp.Size(filterSize, filterSize), 0);
//ビットマップに戻します
var filterResult = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(imageMat);
```

フィルタサイズを1*1から大きくしていってどこまで読めるのか・・・。

|サイズ|読取結果|
|---|---|
|1*1|OK|
|3*3|OK|
|5*5|OK|
|7*7|NG|

5*5の画像はこんな感じでした。
![QRTEST_gaussian.png](https://qiita-image-store.s3.amazonaws.com/0/241416/ac039761-3566-cbdb-e8d1-fd7040d586ba.png)

7*7の画像
![QRTEST_gaussian_NG.png](https://qiita-image-store.s3.amazonaws.com/0/241416/74c2f561-0499-a9e4-b111-96828fd573d3.png)

5*5でも読めることに驚きました。

###傾いたQRコードを読ませてみる X方向
X方向の縮尺のみ小さくして傾きを模擬しました。
どこまで読めるのか・・・。
結果76%までは読めました。
ArcCOS(0.76) ≒ 40deg

![QRTEST_2_X73.png](https://qiita-image-store.s3.amazonaws.com/0/241416/9ad57b56-4e59-319b-bdeb-5cc94919be16.png)


###傾いたQRコードを読ませてみる Y方向
同様にY方向も。
こちらは57%まで読めました。

ArcCOS(0.57) ≒ 55deg
![QRTEST_3_Y59.png](https://qiita-image-store.s3.amazonaws.com/0/241416/c7463c98-ee69-260c-df19-ca1c7c8ce867.png)

この角度までいくと遠近の補正が無くていいのか不安になりますね。
もっと傾きには弱いと思ってましたが、かなり傾いても輪郭がはっきりしていれば読めそうです。
この画像もグレーが混じり始めてしまっているのでその影響のほうが大きいのかもしれません。
もっと画素数を上げてやらないとですかね・・・？