teratail header banner
teratail header banner
質問するログイン新規登録

質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.30%
OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

1回答

3374閲覧

[OpenCV] LAB色空間の取る範囲がわからない。

Sakana4432

総合スコア4

OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2022/12/19 15:50

0

0

OpenCV / Python でLAB色空間で2色間の距離を測るために、以下の手順をとりました。

Python

1import cv2 2import numpy as np 3import math 4from scipy import stats 5 6img = cv2.imread(filepath) 7mask_img = cv2.imread(filepath,0) #白255/黒0のマスク画像 8 9_, mask_img = cv2.threshold(mask_img, 160, 255, cv2.THRESH_BINARY) 10img[mask_img==0] = (0,0,0) 11 12img = cv2.cvtColor(img,cv2.COLOR_BGR2LAB) 13 14#マスクで切り抜いた画像から最も多い色を選ぶ 15cropped_img = img[mask==0].reshape(-1,3) 16cropped_img = cropped_img[~np.all(cropped_img==[0,128,128], axis=-1)] 17#この段階で何故か黒=[0,128,128]となっている 18mode_color = stats.mode(cropped_img)[0].squeeze() 19 20L, A, B= mode_color 21 22L1, A1, B1 = img[x,y] 23c_diff = math.sqrt((L - L1)**2 + (A - A1)**2 + (B - B1)**2) #色差

まず、LABに変換した直後の配列を確認すると、黒が[0,128,128]となっています。
調べてみると画像変換の際に、img.astype(np.float32)とすると[0,0,0]で読み込まれるようで、実際にそうなりましたが、原因がよく分かりません。
公式ではLAB = 0~255,..,..となっているようですが。
https://stackoverflow.com/questions/63269882/color-space-transformation-in-opencv-rgb-lab-red-does-not-produce-expecte

ただ、floatに変換した後に、再度LAB2BGRを行うと、画像が青一色に所々ノイズが入ったような状態になってしまいました。
画像をfloatで扱ったことがないので、float変換後にマスク切り抜き→多い色の検出が正常に行われているのかさえもよく分かりません。

私のコードの書き方に問題があるのか、それともLABへの変換は自前で用意した方が良いのか、何か助言を頂けると幸いです。

宜しくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jbpb0

2022/12/19 23:49

> LABに変換した直後の配列を確認すると、黒が[0,128,128]となっています。 調べてみると画像変換の際に、img.astype(np.float32)とすると[0,0,0]で読み込まれるようで、実際にそうなりましたが、原因がよく分かりません。 「符号無し8bit整数」には負(マイナス)の値を格納できないので、a, bの値が正(プラス)だけになるように128を足してます 色差を計算するそれぞれの色のa, bにどちらも128が足されてるのだから、差の計算結果には影響しないので、128が足されてても問題無いと思います なお、 BGR → Lab → BGR とやった結果と、元の画像との差を計算すると、floatの場合の方が差が小さいので、それを気にするのならfloatの方がいいとは思います
mikandesu4

2022/12/20 00:12

ありがとうございます。 色差を求めるだけなら配列のとる値は気にしなくて良く、 もし色を数値で指定したい場合は、0,128,128を0,0,0の代わりに基準として、その差分を入力すれば良いという認識で合っていますか。 inRangeなどで範囲を指定する場合も同様に、0を下回る範囲を指定する場合は、0とするのではなく+255した方が良いのでしょうか。 よろしくお願い致します。
jbpb0

2022/12/20 00:51 編集

私が前のコメントに書いたのは、a, bに128が足されてること自体は > LAB色空間で2色間の距離を測る には影響しない、ということだけで、「符号無し8bit整数」のまま計算することを勧めてるのではありません > img.astype(np.float32)とすると[0,0,0]で読み込まれるようで、実際にそうなりました の方が分かりやすいのなら、そうしたらいいと思いますけど 【追記】 「符号無し8bit整数」のまま計算して、Labの値が「符号無し8bit整数」だと、それの差の計算結果が負(マイナス)になるとまずいです たとえば、質問のコードの > c_diff = math.sqrt((L - L1)**2 + (A - A1)**2 + (B - B1)**2) #色差 で、「A」と「A1」が「符号無し8bit整数」の場合は、「A」よりも「A1」の方が大きい時は本当は「A - A1」は負(マイナス)になってほしいのですが、下記を実行すると分かりますが正(プラス)の誤った値になってしまいます print(np.array(1).astype("uint8") - np.array(2).astype("uint8")) 差を計算する前に負(マイナス)の値が扱える型(「float」等)に変換すれば大丈夫ですが、それならば、(Labに変換する前の)元の画像データを「float」にしておけばいいですよね (「float」にする際は、matukesoさんが回答に書いてるように、255で割るのを忘れずに)
jbpb0

2022/12/20 01:03 編集

> LAB色空間で2色間の距離を測る Lab空間上で色差を計算する機能は、下記で紹介されてるように、pythonでいくつか実装されてます https://qiita.com/hajimen/items/c1cfb0730b99a1257e13 なお、上記Webページで紹介されてる機能は、単にLab空間上の3次元の直線距離を計算してるのではなく、下記で解説されてる、人の感覚に合わせた補正がされた計算だと思います https://www.konicaminolta.jp/instruments/knowledge/color/section2/06.html 以上、ご参考までに
Sakana4432

2022/12/20 03:28

丁寧に教えていただきありがとうございます。 色差の計算が合わなかった原因がようやく分かりました。 URLの方法で試したところ、正しい値を得ることができました。 とても助かりました。 ありがとうございます。
fana

2022/12/21 05:08

解決した場合はちゃんと解決とする手続きを行ってはどうでしょうか(この質問に限らず)
jbpb0

2022/12/26 10:11

matukesoさんの回答が、この質問への直接の回答になってますので、それをベストアンサーにして「解決済」にしてください
guest

回答1

0

8bitのBGR->LAB変換を掛けると、出力先のLABの範囲は0-255(ABは中心128)になります。つまり、8bit LABの[0,128,128]とは[0,0,0]の意味です。
https://docs.opencv.org/4.4.0/de/d25/imgproc_color_conversions.html#color_convert_rgb_lab

32bit floatなら、まずBGR側は範囲0-1である必要があるので、元が8bit画像なら*(1.0/255)でスケール補正する必要があります。この場合出力の32bitLABは範囲L:0-100, AB=±127になります
https://docs.opencv.org/4.4.0/d8/d01/group__imgproc__color__conversions.html#ga397ae87e1288a81d2363b61574eb8cab

For example, if you have a 32-bit floating-point image directly converted from an 8-bit image without any scaling, then it will have the 0..255 value range instead of 0..1 assumed by the function. So, before calling cvtColor , you need first to scale the image down:

img *= 1./255;
cvtColor(img, img, COLOR_BGR2Luv);

投稿2022/12/19 22:51

matukeso

総合スコア1685

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Sakana4432

2022/12/20 03:35

画像をfloatに変換したことがなかったので勝手が分からず混乱してしましました。 画像をfloatで扱うには正規化の様な処理が必要というわけですね。 勉強になりました。 ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.30%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問