shuhelohelo’s blog

Xamarin.Forms多めです.

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