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

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

ただいまの
回答率

90.11%

RGB値を直接、LAB値に変換する方法

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 3,246

trafalbad

score 218

RGB値を取得して、それをLAB値に変換したいです

以下のように取得した値をLAB値に変換したいのですが、どのようにすればいいでしょうか?
cv2.cvtColor(image_bgr, cv2.COLOR_BGR2LAB)
を使うと、クラスタリングで色を取得したあとになぜかRGBAに変換されてしまうので、
RGB値を直接LAB値に変換するにはどのようにすればいいのでしょうか?

追記

以下のk-meansでlabの値を求めたのですが、LABは0〜100の間の値しか取らないのに、100を超えてしまいます。これはlABではないのでしょうか?

def load_image(image_file):
    # cv2 load images as BGR, convert it to LAB
    image_bgr = cv2.imread(image_file)
    image_lab = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2LAB)
    image_lab = cv2.resize(image_lab, (150, 150))
    return image_lab


def centroid_histogram(clt):
    numLabels = np.arange(0, len(np.unique(clt.labels_)) + 1)
    (hist, _) = np.histogram(clt.labels_, bins = numLabels)
    hist = hist.astype("float")
    hist /= hist.sum()
    return hist
def plot_colors(hist, centroids):
    bar = np.zeros((50, 300, 3), dtype = "uint8")
    startX = 0
    for (percent, color) in zip(hist, centroids):
        endX = startX + (percent * 300)
        cv2.rectangle(bar, (int(startX), 0), (int(endX), 50),
                      color.astype("uint8").tolist(), -1)
        startX = endX
    return bar

image = image.reshape(-1,3)
clt = KMeans(n_clusters =3)
clt.fit(image)
hist = centroid_histogram(clt)
bar = plot_colors(hist, clt.cluster_centers_)

# show our color bart
plt.figure()
plt.axis("off")
plt.imshow(bar)
plt.show()

resized = cv2.resize(bar, (bar.shape[0], bar.shape[1]))
ch_imgs = cv2.split(resized)
ch_imgs
>>>136,144, 145
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

 各チャンネルの可視化

import cv2
import matplotlib.pyplot as plt

bgr_img = cv2.imread('harinezumi.jpg')
lab_img = cv2.cvtColor(bgr_img, cv2.COLOR_BGR2RGB)
resized = cv2.resize(lab_img, (150, 150))

def draw_each_channel(ch_imgs, labels):
    fig, axes_list = plt.subplots(1, 3, figsize=(8, 5))
    for axes, ch_img, label in zip(axes_list, ch_imgs, labels):
        axes.set_axis_off()
        axes.set_title(label)
        axes.imshow(ch_img, cmap='gray')
    plt.show()

# BGR 画像をチャンネルごとに表示する。
ch_imgs = cv2.split(bgr_img)
labels = ['Blue', 'Green', 'Red']
draw_each_channel(ch_imgs, labels)

# LAB 画像をチャンネルごとに表示する。
ch_imgs = cv2.split(lab_img)
labels = ['L', 'a', 'b']
draw_each_channel(ch_imgs, labels)

BGR 画像
イメージ説明

LAB 画像
イメージ説明

 質問の内容 Lab 色空間の値の範囲について

クラスタリングで色を取得したあとになぜかRGBAに変換されてしまうので、


クラスタリングは関係ありません。
オリジナルの Lab 色空間の各チャンネルの値の範囲は以下ですが、

L: [0, 100]
a: [-127, 127]
b: [-127, 127]

cv2.cvtColor() で変換した際は、値の範囲はすべて [0, 255] になるように補正されます。OpenCV リファレンス を参考にしてください。
補正する理由は、OpenCV の多くの関数は画像の型は uint8 を期待するため、int 型であると不便だからだと思います。
元の範囲で得たい場合は、補正と逆の変換を行えばよいです。算出の式は OpenCV リファレンス にのっています。

def draw_each_channel_hist(ch_imgs, labels, bins_list):
    fig, axes_list = plt.subplots(1, 3, figsize=(10, 3))
    for axes, ch_img, label, bins in zip(axes_list, ch_imgs, labels, bins_list):
        axes.set_title(label)
        axes.hist(ch_img.flatten(), bins=bins, density=True)
    plt.show()

# cv2.COLOR_Lab2BGR 直後の Lab 画像
ch_imgs = cv2.split(lab_img)
bins_list = [np.arange(256), np.arange(256), np.arange(256)]
draw_each_channel_hist(ch_imgs, ['L', 'a', 'b'], bins_list)

# cv2.COLOR_Lab2BGR で最後に [0, 255] に範囲が補正されるので元に戻す、
# L_d := L * 255 / 100 <-> L = L_d * 100 / 255
# a_d := a + 128 <-> a = a_d - 128
# b_d := b + 128 <-> b = b_d - 128

lab_img2 = lab_img.astype(np.float)
lab_img2[:, :, 0] *= 100 / 255  # L の範囲を [0, 100] に戻す。
lab_img2[:, :, 1] -= 128  # L の範囲を [-127, 127] に戻す。
lab_img2[:, :, 2] -= 128  # L の範囲を [-127, 127] に戻す。
lab_img2 = lab_img2.astype(np.int)

# cv2.COLOR_Lab2BGR 直後の Lab 画像
ch_imgs = cv2.split(lab_img2)
bins_list = [np.arange(101), np.arange(-127, 128), np.arange(-127, 128)]
draw_each_channel_hist(ch_imgs, ['L', 'a', 'b'], bins_list)

イメージ説明
イメージ説明

 ラベル画像作成

PIL や matplotlib など多くのライブラリでも、色は [0, 255] の範囲であることを前提としているので、[]0, 255] に補正したままのほうがよさそうです。

# k-平均クラスタリングを行う。
kmeans = KMeans(n_clusters=3)
kmeans.fit(lab_img.reshape(-1, 3))

# ラベル一覧及び各ラベルの個数を取得する。
unique, counts = np.unique(kmeans.labels_, return_counts=True)
rates = counts / counts.sum()  # 各ラベルの割合

# 画像を作成する。
height, width = 50, 300  # 画像の大きさ
bar_img = np.empty((height, 0, 3), dtype=np.uint8)
for color, rate in zip(clt.cluster_centers_, rates):
    bar_width = int(rate * width)
    bar = np.full((height, bar_width, 3), color, dtype=np.uint8)
    bar_img = np.hstack([bar_img, bar])

    print('color: {}, rate: {:.2f}'.format(color, rate))
# color: [168.23241035 106.80193675 180.55651384], rate: 0.37
# color: [ 89.67927036 110.89743899 153.16863977], rate: 0.32
# color: [208.73413897 112.50177328 172.6562459 ], rate: 0.31

plt.imshow(bar_img)
plt.axis('off')
plt.show()

イメージ説明

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/09/20 17:34

    追記しました。k-meansでlabの値を求めたのですが、LABは0〜100の間の値しか取らないのに、100を超えてしまいます。これはlABではないのでしょうか?

    キャンセル

  • 2018/09/20 19:52

    回答を追記しました。色空間によって値の範囲が異なりますが、cv2.cvtColor() で変換した際にすべて [0, 255] になるよう補正されます。
    補正する理由は、OpenCV や PIL、matplotlib などほとんどのライブラリは画像は、値の範囲が [0, 255] で uint8 型であることを前提としているためです。

    キャンセル

  • 2018/09/20 20:20

    とても参考になりました、ありがとうございました!

    キャンセル

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

  • ただいまの回答率 90.11%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る