イラストの色を簡単取得「Mouse point Spuit」、プログラム解説付き

2020年7月8日

イラストを描くときに上手な人が塗った絵の色を参考にしたいと思うときはありませんか?

色を連続でスポイトしたいけど、画像をダウンロードするのが面倒といった場合のために画面映っていれば、色を簡単に取得するためのソフトを作成しました。

本記事の目的

画面に映っているイラストや動画などの色を取得をしてRGBとHSVの値に変換して表示をしてくれるソフトを作成しました。

ソフトの配布と使い方について説明を行っています。

本ソフトはLabVIEWを用いてプログラム開発を行っています。作成したソフトのプログラムについても併せて解説を行っています。

「Mouse point Spuit」概要

  • 画面上に映されていればソフトやファイル形式など特に問わずにどこでも色を取得することが出来ます。
  • PixivやTwitterなどのサムネイルからでも色を取得することが可能です。
  • 連続で色を取得することが可能なため動画の色変化にもある程度は対応可能です。

「Mouse point Spuit」ダウンロード先

本ソフトはLabVIEW2020 Community Editionを用いて作成されています。実行するためにはLabVIEWランタイムエンジン2020が必要です。(Googleドライブでソフトを共有をしています。)

Mouse point spuit(インストーラー無し) 約1MB ※ソフトのみ、LabVIEWランタイムエンジンは含まない

Mouse point spuitインストーラー付き 約375MB ※インストーラー、LabVIEWランタイムエンジンを含む

※Nortonやウィルスバスターのセキュリティに引っかかる場合があります。

「Mouse Point Spuit」使い方

  1. 色の取得方法(通常):右クリック
  2. STOPボタン:ソフトを終了します。
  3. 連続色取得ボタン:ONにすると右クリックをしなくても自動で色を取得します。OFFで自動取得を止めて元に戻ります。
  4. RGB、HSVバー色の値を表示しています。SとVについては%の値になっています。
  1. 色相:Hの値に応じてバーが移動します。
  2. 前に取得した色:取得した色の履歴を表示しています。
  3. 彩度明度:取得した色に応じた彩度と明度の場所を表示しています。
  4. 最新の取得した色を表示しています。

注意点

  • CLIPSTUDIOPAINTでペンツールを使用しているとカーソルの色を取得してしまいます。(移動ツールなどは問題なし)
  • 10時間ほど連続で駆動させると、メモリエラーが起きて、プログラムが止まります。(約85万回のデータ取得)
  • ディスプレイの設定から画面のスケーリング設定を100%から変更していると画面と座標の位置がズレてしまい、マウスカーソル違う位置の色を取得してしまいます。

【Mouse point Spuitプログラムの解説】

プログラムの全体構成は上記図の通りです。右端はプログラムを動作させるための初期設定を行っています。中央部のループ内が実際の処理部分となっています。右端はプログラム終了時の対応です。

※VIスニペットで画像ファイルを公開していますので画像のリンク先を開いてもらえば、元のファイルを表示することが出来ます。画像ファイルを保存してLabVIEWのブロックダイアグラムにドラッグ&ドロップをすればVIを再現出来ます。

プログラムの特徴的な部分について内容を記載しています。

【ウィンドウを常に前面に表示する】

本ソフトで色を取得する場合に右クリックを使用していますが、この時にウィンドウを常に前面にしておかないと、色を取得するたびにウィンドウが隠れてしまうという問題がありました。

当初はNI社のHPで紹介をされていたUSER32.dllの「Set foreground window」を使用して色を取得した後に前面に出てくるように設定しましたが、一瞬ウィンドウが後ろに隠れてから前面に戻ってくるという動作をするのと、他のウィンドウを操作することが出来ないという問題が出てきました。

https://knowledge.ni.com/KnowledgeArticleDetails?id=kA00Z000000PA7NSAW&l=ja-JP

他にウィンドウを常に前面に移動してくれるAPI関数がないか探したところ、「SetWindowPos」という物が見つかりました。

ウィンドウの位置やサイズ、ウィンドウの順番などを変更することが出来ます。「GetForegroundWindow」を使用して、作業中のウィンドウのハンドルを「SetWindowPos」に渡しています。

ウィンドウを一番上に持ってきたかったのでHWNDには」「-1」

※ウィンドウを一番上に移動をさせた状態でダイアログボックスまたはタスクマネージャーを開くと、VIがフリーズをします。ウィンドウの順番については注意をしてください。

ウィンドウのサイズや座標を変更する必要はないので「X,Y,cx,cy」には「0」

ウィンドウをアクティブにする必要は無いので「x10(16進数)」、またウィンドウサイズ変更なしなので「x1」、ウィンドウを移動させないので「x2」を複合演算で足して「19」として渡しています。

「SetWindowPos」に渡す値の詳細については下記のMicrosoftの「SetWindowPos」のAPIに関するページに記載されています。

https://docs.microsoft.com/ja-jp/windows/win32/api/winuser/nf-winuser-setwindowpos?redirectedfrom=MSDN

ライブラリ関数の呼び出しに使用しているパラメータはAPIの構文の通り入力をしています。

  HWND hWnd,//符号なし32ビット整数
  HWND hWndInsertAfter,//符号付き32ビット整数
  int  X, //符号付き32ビット整数
  int  Y,//符号付き32ビット整数
  int  cx,//符号付き32ビット整数
  int  cy,//符号付き32ビット整数
  UINT uFlags//符号なし32ビット整数

【色の取得方法】

色の取得については別の記事で紹介をしているスクリーンショット撮るプログラムを使用しています。

スクリーンショットについてはLabVIEWの標準で備わっている「入力デバイス制御」の中にある「入力データ取得関数」を用いて「マウスカーソルの座標を取得」しています。

スクリーンショットは画面の座標を指定して取得する仕様なのでマウスカーソルの位置から1pxの範囲だけをスクリーンショットするようにしています。

本来はピクチャデータとして出力されるので「ビックスマップを非平坦化」を使用して画像データを一度2次元配列のデータ(RGBデータ 256^3=約1677万色)に置き換えて1行1列目の色データを取得しています。

数値のままだと、どのような色を取得したのか判らないのでRGBカラーとして最終的に出力を行っています。

※Windowsのスケーリング設定が100%以外になっていると入力データ取得関数で得られるマウスの座標が変わってしまう(200%だと半分の位置)ため、マウスカーソル位置の色を取得することが出来なくなる。スケーリングを変更されている場合に補正するためのAPIを追加で入れる必要があります。

【RGBからHSVに変換】

HSVの変換についてはRGBから変換するための式があるので、RGB色をHSV色に変換するための計算を行っています。

RGBからHSVへの計算方法

V(明度)=max

S(彩度)=255*[(max-min)/max]

Rmax

H(色相)=60*[(G-B)/(max-min)]

Gmax

H(色相)=60*[(B-R)/(max-min)]+120

Bmax

H(色相)=60*[(R-G)/(max-min)]+240

色を「RGB数値に変換」Viを用いて、RGBごとの数値にします。その後にRGBの配列データを作成しHSVを計算するためのRGBの最大と最小を出力することが出来るようにしています。

RGBの最大値によって計算式が変わるので、「配列最大&最小」から最大の行を出力して「ケースストラクチャ」に入力を行い、数値ごとに計算式を変えています。

※値ごとに毎回「U8」の配列を3つ確保しているので、メモリを無駄に消費している可能性があります。初期化配列を外に出し、必要以上にメモリを確保しないようにした方がよいかもしれません。

「S(彩度)」と「V(明度)」については単純に計算をすれば問題はありませんが、「H(色相)については、計算式のまま計算を行うと、Hの値が「マイナス」になってしまう場合があります。

その場合、Hの値を補正するために、「360」を足す必要があります。Hの計算が終わった後に、Hの値が「0ゼロ」未満になっていないかを判定し、「0ゼロ」以上であれば、計算した値をそのまま出力し、「0ゼロ」未満であれば、「360」を足して補正するように出力を行っています。

「RGB」の値が全て同じになった場合についてはいずれの値もMAXになってしまうため「H」を「0ゼロ」として出力するようにしています。

後は、RGBとHSVの計算した値をメインViに戻すためにクラスタにをして、コネクタペーンの割当を行っています。クラスタにせず、一つずつコネクタペーンを割り当てることも出来ますが、端子処理が煩雑になるため、クラスタでまとめています。

【カラーピッカーの作成】

RGBとHSVのバーについては先ほどの計算した値を入力することで表示させることができるようになります。

しかし、色相に対応したカラーピッカー(画像右側)を出力するためには画像ファイルを作成する必要があります。

カラーピッカーは右側に行くほど「彩度」が大きくなり、下側に行くほど「明度」が小さくなります。(左上はS「0」 V「255」、右下はS「255」 V「0」となります。)

S、V共に値は「0~255」まであるので256×256回のループを行う必要があります。1色につき65,536回のループを毎回行っているので処理に時間がかかっています。

H(色相)については先ほど計算した値を入力し、V(明度)については初期値を「255」としてループごとに「1」ずつ減らすようにしています。S(彩度)は逆に「0ゼロ」を初期値として、「1」ずつ増やしています。

最終的にHSVのままでは色として出力が出来ないので、HSVをRGBの値に戻しています。

※RGBのままカラーピッカーを作成することが出来れば一番良いのです個人的に一番判りやすい方法で作成を行っています。実行速度も極端に遅くもなっていないため現状は問題ないと認識をしています。

カラーピッカーを作成するためにHSVから更にRGBに戻す処理を行います。HSVからRGBに戻すには、「H(色相)」の値によって計算式が6つに分岐をします。そのためHがどの範囲にいるのかを先に判定する必要があります。

「H(色相)」については同じ値を何度も使用するため保持をしておきたいのでFGV(機能的グローバル変数」の形式をとっています。

計算方法については下記のサイトを参考にしています。

https://www.peko-step.com/tool/hsvrgb.html

色相の判断用の配列を作成し、入力されたHがどの範囲にいるのかをループ内にある比較と論理演算を用いています。

1回目の計算では1以上60以下になり2回目は61以上120以下というように範囲を決めています。「0ゼロ」だけが範囲計算が出来ないため、別途で判定を行っています。Hがどの範囲にいるのかが解った段階でループを終了します。(ループの回数でどのHでの計算を行うかを決めるための値を出力しています。)

ループの一つ外側にケースストラクチャを配置していますが、「H(色相)」の値が前回と同じ場合はループ内の処理を行わないようにしています。(計算時間の短縮)

あとはHの値ごとに計算を行うことで「HSV」を「RGB」の値に変換することが出来ます。「RGB」の値を「RGBを色に変換」Viを用いることで、「色」の値を取得することが出来ます。これを2次元配列化することでカラーピッカーの色を作り出すことが出来ます。

色の2次元配列データを「非平坦化ビックスマップ描画」Viへ入力をすることで、ピクチャ画像を得ることが出来ます。

※ポイント描画のViを使用してもカラーピッカーを作ることは出来るとは思いますが、ピクチャーの描画は時間を要するため、数値データでまとめて計算を行った方が早く処理をすることが出来ます。

【装飾品を移動させる】

色相やカラーピッカーにあるバーや四角アイコンについてはLabVIEWの装飾品を使用しています。

装飾品の配置を移動するためには、プロパティノードを使用して「このVI」⇒「フロントパネル」⇒「装飾品」の順番で装飾品のリファレンスを取得します。

装飾品のリファレンスについては配列で出力されるため「指標配列」を用いて、任意の装飾品の位置を移動させることが可能です。

注意点としては装飾品のリファレンスはフロントパネルに新しく設置したものほど若い番号になるため、後から装飾品を追加をすると既にあるプロパティノードに入力しているリファレンスを変更する必要があります。装飾品をプログラムで動かしたい場合は先に必要な分だけ装飾品を設置しておくのがよいと考えます。

プログラム自体は難しくなく、装飾品の初期位置に対して増加(減少)した分だけ装飾品の位置を移動させるように足し算引き算をおこなっているだけです。色相の場合はHの増加量によって右方向へ移動させるため、Leftの数値を増加させる。

カラーピッカーはSが増加した場合はLeftの数値を増加させ、、Vが減ると上に移動するように毎回計算しています。

※プロパティノードを頻繁に更新を行うと、実行速度を遅延させる可能性があるため、あまりオススメはされていません。

簡単にですが、以上が「Mouse point Spuit」のLabVIEWプログラムの解説になります。