hirakun-jpの日記

日記を書きます

MVVM試した2

この記事をほぼ写経しました。計算ができた!

WPF/C#/MVVM/Prismで、簡単なWPFアプリケーションを作ります [C#][WPF] - nprogram’s blog

ViewModelを残しとく。

using Prism.Commands;
using Prism.Mvvm;

namespace MrNprogramExample
{
    class ViewModel: BindableBase
    {
        private Model _model;
        public ViewModel()
        {
            _model = new Model();
        }

        private string _leftValue;
        public string LeftValue
        {
            get { return _leftValue; }
            set { this.SetProperty(ref _leftValue, value); }
        }

        private string _rightValue;
        public string RightValue
        {
            get { return _rightValue; }
            set { this.SetProperty(ref _rightValue, value); }
        }

        private string _answerValue;
        public string AnswerValue
        {
            get { return _answerValue; }
            set { this.SetProperty(ref _answerValue, value); }
        }

        #region コマンド
        private DelegateCommand _concatCommand;
        public DelegateCommand ConcatCommand
        {
            get { return _concatCommand = _concatCommand ?? new DelegateCommand(ConcatExecute); }
        }

        private void ConcatExecute()
        {
            AnswerValue = _model.Concat(LeftValue, RightValue);
        }
        #endregion

    }
}

f:id:hirakun-jp:20180606162309p:plain

前回記事MVVM試した - hirakun-jpの日記で参考(ほぼ写経ですすみません)にさせてもらったコードだとコマンドクラスが別にあったけど、これはViewModelの中に入ってるみたい。 いろんな書き方ができるのだなあ。

XAMLの書き方でstar value知らなかったので勉強なった。 このブログhttp://blog.okazuki.jp/entry/20130106/1357483477で勉強したい。

BindingにあるOneWayについて、この記事 今さら入門するMVVMに必要な技術要素(Xamarin.Forms & UWP) - かずきのBlog@hatena

で理解できました。

Bindingには、Modeがあります。Modeには以下のようなものがあります。 OneWay: ソース(C#のオブジェクト)からターゲット(画面のコントロール側)への1方向同期 TwoWay: ソースとターゲットの双方向同期 OneTime: ソースからターゲットへの1度きりの同期 指定しない場合は、デフォルトでOneWayになります。

ということらしい。

MVVM試した

この記事をほぼ写経させてもらいました。とても分かりやすくシンプルに書かれていました!

WindowsFormをそろそろやめてXaml+C#に移行したい話

コマンドのクラスだけ日記に残しとく。

using System;
using System.Windows;
using System.Windows.Input;

namespace MrJunkiExample
{
    class MainWindowTestCommand: ICommand
    {
        public MainWindowTestCommand(MainWindowViewModel vm)
        {
            _vm = vm;
        }

        private MainWindowViewModel _vm;

        public event EventHandler CanExecuteChanged;

        public bool CanExecute(object parameter)
        {
            return !string.IsNullOrEmpty(_vm.InputText);
        }

        public void Execute(object parameter)
        {
            MessageBox.Show( "Command Success! Input Text is " + _vm.InputText);
        }
    }
}

参照パラメーターとか「nullの場合には○○とする」というルールの「??」演算子忘れてた。 以下で再学習した。

独習C# 第3版

独習C# 第3版

C#プログラマーのための 基礎からわかるLINQマジック!

C#プログラマーのための 基礎からわかるLINQマジック!

スクリーンショットをImageコントロールに表示する

こちらの記事を参考にさせていただきました!すごい!できた! 参考にといいつつ毎回まるパクリですすみません。

【WPF】 スクリーンショットを撮り続けて動画に保存する - 旅行好きなソフトエンジニアの備忘録

C#でBitmapで描いた画像をImageコントロールに表示してみた

        private void Button_Click_2(object sender, RoutedEventArgs e)
        {
            var bmp = GetScreenShot(640, 480);

            // 表示
            IntPtr hbitmap = bmp.GetHbitmap();
            imageArea.Source = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(hbitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
            DeleteObject(hbitmap);
        }

        [System.Runtime.InteropServices.DllImport("gdi32.dll")]
        public static extern bool DeleteObject(IntPtr hObject);

        private Bitmap GetScreenShot(int width, int height)
        {
            var resizedBmp = new Bitmap(width, height);
            using (var bmp = new Bitmap((int)SystemParameters.PrimaryScreenWidth, (int)SystemParameters.PrimaryScreenHeight))
            using (var g = System.Drawing.Graphics.FromImage(bmp))
            using (var resizedG = System.Drawing.Graphics.FromImage(resizedBmp))
            {
                // スクリーンショットを撮る
                g.CopyFromScreen(new System.Drawing.Point(0, 0), new System.Drawing.Point(0, 0), bmp.Size);

                resizedG.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Bilinear;
                resizedG.DrawImage(bmp, 0, 0, width, height);
            }

            return resizedBmp;
        }

f:id:hirakun-jp:20180605212208p:plain

C#でExcelファイルの操作をする

これらのサイトを参考にさせていただきました。

(∩´ω`∩)EPPlusを使って、便利にExcel操作(∩´ω`∩)

EPPlusの基本的な使い方メモ (xlsx形式, Excelのインストール必要ない, COM使わない) - いろいろ備忘録日記

 // ファイルを読み込む
            var inputExcelFile = new FileInfo(@"C:\Users\dev\Excel_Service\excel\Book1.xlsx");

            using (var inputFile = new ExcelPackage(inputExcelFile))
            {
                // シート名取得
                string sheetNames = "";
                foreach (var item in inputFile.Workbook.Worksheets)
                    sheetNames += " " + item.ToString();


                var sheet = inputFile.Workbook.Worksheets[inputFile.Workbook.Worksheets.ElementAt(0).ToString()];
                sheet.Cells[1, 1].Value = sheetNames;

                inputFile.Save();
            }

この本読んでLINQ to Objectsを使って無駄にわかりづらくしました。

【省エネ対応】 C#プログラムの効率的な書き方

【省エネ対応】 C#プログラムの効率的な書き方

てかエクセルファイル開いたままリアルタイムに更新したかったんだけど、どうやるんだろか 調べよう

画像中の数字を取得する2

前回記事画像中の数字を取得する - hirakun-jpの日記で使ったTesseractのラッパーとは別のものを使ってみた。

これです。 www.nuget.org

バージョンも4.0.0に上げて(前回は3.0.2)使ってみたけど、前より精度いい感じ。

string langPath = @"C:\Users\dev\Excel_Service\tessdata\tessdata_best";
            //string langPath = @"C:\Users\dev\Excel_Service\tessdata\special";
            string langStr = "eng";
            //string langStr = "equ";
            //string langStr = "jpn";
            string imgFile = @"C:\Users\dev\Excel_Service\images\num_example_oanda_web_002.png";
            //string imgFile = @"C:\Users\dev\Excel_Service\images\num_example_oanda_web_001.png";
            //string imgFile = @"C:\Users\dev\Excel_Service\images\num_example_MT4_001.png";
            //string imgFile = @"C:\Users\dev\Excel_Service\images\num_example_MT4_001_gray.png";
            //string imgFile = @"C:\Users\dev\Excel_Service\images\num_example_MT4_001_gray_reverse.png";
            OcrEngineMode oem = OcrEngineMode.LSTM_ONLY;
            PageSegmentationMode psm = PageSegmentationMode.AUTO_OSD;

            TessBaseAPI tessBaseAPI = new TessBaseAPI();

            // Initialize tesseract-ocr 
            if (!tessBaseAPI.Init(langPath, langStr, oem))
            {
                throw new Exception("Could not initialize tesseract.");
            }

            // Set the Page Segmentation mode
            tessBaseAPI.SetPageSegMode(psm);

            // 数字のみを対象とする
            tessBaseAPI.SetVariable("classify_bln_numeric_mode", "1");
            //tessBaseAPI.SetVariable("tessedit_char_whitelist", "1234567890");

            // 計測開始(今回は画像のセットから測る)
            var sw = new System.Diagnostics.Stopwatch();
            sw.Start();

            // Set the input image
            Pix pix = tessBaseAPI.SetImage(imgFile);

            // Recognize image
            tessBaseAPI.Recognize();

            ResultIterator resultIterator = tessBaseAPI.GetIterator();

            // Extract text from result iterator
            StringBuilder stringBuilder = new StringBuilder();
            PageIteratorLevel pageIteratorLevel = PageIteratorLevel.RIL_PARA;
            do
            {
                stringBuilder.Append(resultIterator.GetUTF8Text(pageIteratorLevel));
            } while (resultIterator.Next(pageIteratorLevel));

            tessBaseAPI.Dispose();
            pix.Dispose();

            // OCR表示
            textBlockOCR.Text = stringBuilder.ToString();

            // 計測終了・処理時間表示
            sw.Stop();
            textBlockTime.Text = sw.ElapsedMilliseconds.ToString() + "ms";
        }

画像データ

f:id:hirakun-jp:20180604165707p:plain

結果

f:id:hirakun-jp:20180605134208p:plain

JavaだとTess4jとかいうラッパー使うみたいだ TessAPI1.TessPageIteratorLevel (Tess4J API)

今回使ったC#のラッパーのWikiはこれ How to use tesseract.net · tvn-cosine/tesseract.net Wiki · GitHub

使ったデータファイルはこれ GitHub - tesseract-ocr/tessdata_best: Best (most accurate) trained LSTM models.

縦書きの日本語とか、数式に特化したやつとかあるみたい!

画像中の数字を取得する

タイトル通り。

下記の投稿を参考に(というかほぼそのまんまですすみません)OCRがどんなものか試してみました。 C#で文字認識をする(導入)

時間の計測は下記の投稿を参考にさせていただきました。 C#メモ 処理時間計測

string langPath = @"C:\Users\dev\Excel_Service\tessdata\tesseract-ocr\tessdata";
            string langStr = "jpn";

            // 画像ファイル
            var img = new Bitmap(@"C:\Users\dev\Excel_Service\images\num_example_oanda_web_002.png");

            using (var tesseract = new Tesseract.TesseractEngine(langPath, langStr))
            {
                // OCR実行
                Tesseract.Page page = tesseract.Process(img);


                // 計測
                var sw = new System.Diagnostics.Stopwatch();
                sw.Start();

                // OCR表示
                textBlockOCR.Text = page.GetText();

                // 処理時間表示
                sw.Stop();
                textBlockTime.Text = sw.ElapsedMilliseconds.ToString() + "ms";


            }

画像データ

f:id:hirakun-jp:20180604165707p:plain

結果

f:id:hirakun-jp:20180604165839p:plain

画像小さいから?はやい(ベンチマークないし根拠ありません)かんじ(リリースビルドだと33msだった)。 間違った画像について正解情報与えて学習とかってできるのかな?調べよう。

それと、自分のやりたいこと的に、数字だけ扱えればいいんだけど、Accord.Netとか機械学習ライブラリつかって自分で作ったほうがいいのかな? まずは、Tesseractに再学習機能あるか調べよう。

あと、グレースケール?するともっとよくなったりするかもしれないし、使ったTesseractはバージョン3.0.2なので、最新の4.0.0にしたらもっとよくなるかもしれない(LSTMとかいう機械学習の手法使ってるらしい)。