shuhelohelo’s blog

Xamarin.Forms多めです.

ASP.NET MVCプロジェクトにIdentityユーザー認証機能を追加する

とりあえずチュートリアルに従ってアプリを作る。

そうだ、ユーザー認証機能を追加しよう。

というときのためのメモです。

また、Identityユーザー認証機能を後付するとプロジェクト内にIdentityで使われるクラスやページのソースコードが作成されるので、いろいろアレンジしやすいです。

Identityユーザー認証機能の追加

追加自体はとても簡単です。 スキャフォールディングによって作成されます。

ソリューションエクスプローラで右クリックしてコンテキストメニューから追加 > 新規スキャフォールディングアイテムを選択します。

f:id:shuhelohelo:20190612122308p:plain

スキャフォールディングを追加ウィンドウが開くので、左ペインからIDを選択して右下の追加ボタンを押します。

f:id:shuhelohelo:20190612122451p:plain

IDの追加ウィンドウが開く。

f:id:shuhelohelo:20190612122900p:plain

とりあえずやること。

Startup.csの編集

認証機能を使うことを指定する。

Configureメソッドに以下を追加

これはapp.UseMVCよりも前に置くこと。

app.UseAuthentication();

_Layout.cshtmlの編集

Identityのスキャフォールディングで_LoginPartial.cshtmlが作成されているので、これがサイトのヘッダ部分に表示されるようにする。

<partial name="_LoginPartial" />を埋め込む。

    <header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container">
・・・
                <div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
                    <partial name="_LoginPartial" />
・・・
                </div>
            </div>
        </nav>
    </header>

IdentityのLoginページやRegisterページはライブラリ内に保持されているので、直接編集などはできない。 困ったな。

わかった!!!

IDの追加画面で、オーバーライドする項目でチェックをつけたページがAreas/Identity/Pages/Account内に作成されて、オーバーライドという形で編集できるようになる。

OpenCvSharpでHSVで特定の色を取り出すときの簡易確認ツール

OpenCVで特定の色だけにしぼり込むときに、HSV(Hue,Saturation,Value)で範囲を指定するとします。

ある画像をサンプルとして、自分が絞り込みたい色の範囲はHSVでどの値の範囲なのかを確認したいです。

そんなちょっとした確認に便利なツールがあると便利です。ここでは、そんなちょっとしたツールをOpenCvSharpで作ります。

OpenCVでは独自のウィンドウに加え、スライダーをウィンドウに設置することができるため、こういった値を変えながら結果を確認したい、という用途にピッタリのツールを簡単に作ることができます。

f:id:shuhelohelo:20201123124148p:plain

参考

OpenCVのサンプルコードはPythonC++のものがたくさん見つかりますが、OpenCvSharpでも書き方はほとんど同じなので、他言語のサンプルを簡単な脳内変換でOpenCvSharpで使うことができます。

今回参考にさせてもらったのは以下の記事です。

qiita.com

ありがとうございました。

実装

流れとしては、

  1. 名前付きのウィンドウを作成する
  2. そのウィンドウにスライダー(trackbar)を配置する
  3. スライダーのOnChangedイベントにイベントハンドラを設定する
  4. イベントハンドラの中でスライダーの値をもとに画像を生成してウィンドウを更新

です。これがほぼすべてです。

using OpenCvSharp;
using System;

namespace OpenCvHsvChecker
{
    class Program
    {
        private static int _h_min = 0;
        private static int _h_max = 0;
        private static int _s_min = 0;
        private static int _s_max = 0;
        private static int _v_min = 0;
        private static int _v_max = 0;

        private static Mat src = new Mat();
        private static Mat hsv = new Mat();
        //private static Mat dst = new Mat();

        private const string WINDOW_NAME = "HSV Checker";
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");

            string inputImagePath = "Images/gauge-1.jpg";

            src = Cv2.ImRead(inputImagePath);
            if (src is null)
                return;
            Cv2.ImShow("src", src);

            Cv2.CvtColor(src, hsv, ColorConversionCodes.BGR2HSV, 3);
            Cv2.ImShow("hsv", hsv);

            //名前つきウィンドウを作成
            Cv2.NamedWindow(WINDOW_NAME);

            //ウィンドウ名を指定してスライダーを配置
            Cv2.CreateTrackbar("H_Min", WINDOW_NAME, 179, onChange: H_Min_Changed);
            Cv2.CreateTrackbar("H_Max", WINDOW_NAME, 179, onChange: H_Max_Changed);
            Cv2.CreateTrackbar("S_Min", WINDOW_NAME, 255, onChange: S_Min_Changed);
            Cv2.CreateTrackbar("S_Max", WINDOW_NAME, 255, onChange: S_Max_Changed);
            Cv2.CreateTrackbar("V_Min", WINDOW_NAME, 255, onChange: V_Min_Changed);
            Cv2.CreateTrackbar("V_Max", WINDOW_NAME, 255, onChange: V_Max_Changed);

            //初期画像を表示
            Cv2.ImShow(WINDOW_NAME, src);

            Cv2.WaitKey();
        }

        private static void V_Max_Changed(int pos, IntPtr userData)
        {
            _v_max = pos;
            Update();
        }

        private static void V_Min_Changed(int pos, IntPtr userData)
        {
            _v_min = pos;
            Update();
        }

        private static void S_Max_Changed(int pos, IntPtr userData)
        {
            _s_max = pos;
            Update();
        }

        private static void S_Min_Changed(int pos, IntPtr userData)
        {
            _s_min = pos;
            Update();
        }

        private static void H_Max_Changed(int pos, IntPtr userData)
        {
            _h_max = pos;
            Update();
        }

        private static void H_Min_Changed(int pos, IntPtr userData)
        {
            _h_min = pos;
            Console.WriteLine(_h_min);
            Update();
        }


        static void Update()
        {
            //HSV画像とスライダーの値からマスクを生成
            var scalar_min = new Scalar(_h_min, _s_min, _v_min);
            var scalar_max = new Scalar(_h_max, _s_max, _v_max);
            Mat mask = new Mat();
            Cv2.InRange(hsv, scalar_min, scalar_max, mask);

            //マスク画像を使って元画像にフィルタをかける
            Mat dst = new Mat();
            src.CopyTo(dst, mask);

            //ウィンドウの画像を更新
            Cv2.ImShow(WINDOW_NAME, dst);
        }
    }
}

OpenCvSharpのインストールについては以下の記事を。

shuhelohelo.hatenablog.com

ソースコード

github.com

OpenCvSharp4で特定の色だけを抜き出す

以下の記事をOpenCvSharpを使ってやった内容になります。

tecsingularity.com

RGBで指定

RGBで色の範囲を指定して抜き出すには以下のようにします。

using OpenCvSharp;
using System;

namespace OpenCVColorExtraction
{
    class Program
    {
        //抽出したい色の範囲をRGBで指定
        const int B_MAX = 40;
        const int B_MIN = 0;
        const int G_MAX = 50;
        const int G_MIN = 0;
        const int R_MAX = 170;
        const int R_MIN = 100;

        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");

            string inputFilePath = "Images/gauge-1.jpg";

            //画像を読み込み
            var src = Cv2.ImRead(inputFilePath);
            if (src is null)
                Console.WriteLine("fail to read file.");

            //マスクを作成
            Scalar s_min = new Scalar(B_MIN, G_MIN, R_MIN);
            Scalar s_max = new Scalar(B_MAX, G_MAX, R_MAX);
            Mat maskImage = new Mat();
            Cv2.InRange(src, s_min, s_max, maskImage);


            //マスクを使ってフィルタリング
            Mat masked = new Mat();
            src.CopyTo(masked, maskImage);

            //表示
            using (new Window("src", src))
            using (new Window("maskImage", maskImage))
            using (new Window("masked", masked))
                Cv2.WaitKey();//何かキーが押されるまで待つ

        }
    }
}

概ねOKですね。

元画像 f:id:shuhelohelo:20201123094350p:plain

マスク f:id:shuhelohelo:20201123094404p:plain

抽出 f:id:shuhelohelo:20201123095126p:plain

HSVで指定

(追記:HSVの値を変えながらデバッグを繰り返すのは面倒なので簡易確認ツールを作成しました。

shuhelohelo.hatenablog.com )

using OpenCvSharp;
using System;

namespace OpenCVColorExtraction
{
    class Program
    {
        //抽出したい色の範囲をHSVで指定
        const int H_MAX = 120;
        const int H_MIN = 111;
        const int S_MAX = 255;
        const int S_MIN = 50;
        const int V_MAX = 255;
        const int V_MIN = 50;
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");

            string inputFilePath = "Images/gauge-1.jpg";

            //画像を読み込み
            var src = Cv2.ImRead(inputFilePath);
            if (src is null)
                Console.WriteLine("fail to read file.");

            //HSVに変換
            Mat hsv = new Mat();
            Cv2.CvtColor(src, hsv, ColorConversionCodes.RGB2HSV);

            //マスクを作成
            Scalar s_min = new Scalar(H_MIN, S_MIN, V_MIN);
            Scalar s_max = new Scalar(H_MAX, S_MAX, V_MAX);
            Mat maskImage = new Mat();
            Cv2.InRange(hsv, s_min, s_max, maskImage);

            //マスクを使ってフィルタリング
            Mat masked = new Mat();
            src.CopyTo(masked, maskImage);

            //表示
            using (new Window("src", src))
            using (new Window("hsv", hsv))
            using (new Window("maskImage", maskImage))
            using (new Window("masked", masked))
                Cv2.WaitKey();//何かキーが押されるまで待つ
        }

でも、色相の指定がよくわからないな。 なぜこの色がこの範囲になるのか。

f:id:shuhelohelo:20201123103926p:plain

f:id:shuhelohelo:20201123103948p:plain

f:id:shuhelohelo:20201123104000p:plain

ソースコード

github.com

C#でOpenCVを使うOpenCVSharp

OpenCVC#ラッパーとしてOpenCvSharpというNugetパッケージがあります。

github.com

これを使うとC#OpenCVによる画像処理や色々ができます。

例えば、画像を読み込んで表示させたり、画像の色空間を変更したりというのは以下のようなコードを書きます。

using OpenCvSharp;
using System;

namespace OpenCVColorExtraction
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");

            string inputFilePath = "Images/gauge-1.jpg";

            var src = Cv2.ImRead(inputFilePath);
            if (src is null)
                Console.WriteLine("fail to read file.");

            Mat hsv = new Mat();
            Cv2.CvtColor(src, hsv, ColorConversionCodes.RGB2HSV);

            using (new Window("src", src))
            using (new Window("hsv", hsv))
                Cv2.WaitKey();

        }
    }
}

C++Pythonでおなじみだと思います。

これを実行すると以下のように元画像とHSV色空間に変換された画像が表示されます。 f:id:shuhelohelo:20201123091140p:plain

インストール

インストールは簡単で、OpenCvSharpのReadMeにも書かれているとおり、Nugetパッケージからインストールするだけです。

ここではWindowsの場合のみを紹介しますが、他にもUWPの場合やUbuntuの場合などが書いてありますので、自分の環境に合わせてインストールするパッケージを選択します。

Windowsの場合は2とおりあります。

  • OpenCVSharp4 と OpenCVSharp4.runtime.winの組み合わせ
  • OpenCVSharp4.Windowsのみ

特段理由がなければ後者のOpenCvSharp.Windowsをインストールすればよいでしょう。

Dell Latitude 7300でFnキーロック

Latitude 7300ではファンクションキーを使う場合にはFnキーをあわせて押す必要があります。 例えば、Visual Studioデバッグを実行したいとき(F5)などですね。

Fnキーを一緒に押さない場合は、画面の明るさや音量を変更する機能が割り当てられています。

Surfaceとは真逆なので、結構戸惑ってしまいますが、当然それを解消する設定が用意されており、以下のように公式で紹介されています。

Fn+EscでFnキーをロックすることができ、Surfaceなどと同じ操作にすることができます。 音量などを変更したい場合は逆にFnキーと併用することになります。

www.dell.com

正規表現でマッチした部分を同じ文字数の記号で置換する

実装の一例としてメモ

例えば,連続する半角スペースに対して2文字目以降をnbspで置き換える場合は以下のようにする.

        public static string ConsecutiveBlanksToNBSP(string sentense)
        {
            Regex re = new Regex(@"(?<= )( )+");
            MatchCollection matches = re.Matches(sentense);

            if (matches.Count == 0)
            {
                Console.WriteLine("nothing");
                return sentense;
            }

            var strBuilder = new StringBuilder(sentense);
            foreach (Match m in matches)
            {
                strBuilder.Remove(m.Index, m.Length);//対象部分を削除
                strBuilder.Insert(m.Index, new string('\u00a0', m.Length));//挿入
            }

            return strBuilder.ToString();
        }

Gitでrefusing to merge unrelated historiesエラーの対処

www.educative.io

remoteとlocalでcommit履歴が一致していない場合にpullやmergeを行うと以下のエラーが発生する.

refusing to merge unrelated histories

上のリンク先で使用されている画像がわかりやすいので引用するが,こんな感じ.

f:id:shuhelohelo:20200826144230p:plain

どういう状況かというと,remoteとlocalで別々に作成されたリポジトリがあって,local側でremote側のリポジトリgit remote addコマンドで追加した,という状況.

local側でfb62efcのコミットが行われ,それとは別にremote側でda7cc7aのコミットが行われている.

このため,local側とremote側で保持しているコミット履歴が異なるためにエラーが発生している,という状況.

このエラーが発生している状態でgit logを実行すると,以下のとおり.

> git log --oneline --all
da7cc7a (origin/master) Initial commit
fb62efc (HEAD -> master) Created sln and added gitignore file.

これに対して以下のコマンドを実行する.

git pull origin master --allow-unrelated-histories
> git pull origin master --allow-unrelated-histories
From https://github.com/shuheydev/xUnitPractice
 * branch            master     -> FETCH_HEAD
Merge made by the 'recursive' strategy.
 README.md | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 README.md

コンフリクトなどがなければこれまで関連のない2つのリポジトリがマージされて以下のようになる.

> git log --all --oneline --graph
*   df81915 (HEAD -> master) Merge branch 'master' of https://github.com/shuheydev/xUnitPractice into master
|\
| * da7cc7a (origin/master) Initial commit
* fb62efc Created sln and added gitignore file.