OpenCV – cv2.LUT を使ったカラー画像に対する階調変換について

目次

概要

cv2.LUT() を使ったカラー画像に対する階調変換について解説します。

階調変換については以下の記事を参照してください。

OpenCV – cv2.LUT の使い方、ガンマ補正、ネガポジ反転、ポスタリゼーション – pystyle

sample.jpg

In [1]:
import cv2
import numpy as np
from IPython.display import Image, display


def imshow(img):
    """ndarray 配列をインラインで Notebook 上に表示する。
    """
    ret, encoded = cv2.imencode(".jpg", img)
    display(Image(encoded))


# 画像を読み込む。
img = cv2.imread("sample.jpg")

すべてのチャンネルに同じ階調変換を適用する

以下の記事で解説した階調変換を各チャンネルに適用した例を紹介します。

OpenCV – cv2.LUT の使い方、ガンマ補正、ネガポジ反転、ポスタリゼーション – pystyle

ネガポジ反転

In [2]:
# ネガポジ反転
x = np.arange(256)
y = 255 - x

# 変換する。
dst = cv2.LUT(img, y)
imshow(dst)

ソラリゼーション

In [3]:
# ソラリゼーション
x = np.arange(256)
y = (np.sin(x * 2 * np.pi / 255) + 1) * 255 / 2

# 変換する。
dst = cv2.LUT(img, y)
imshow(dst)

コントラストを上げる (1)

In [4]:
# コントラストを上げる折れ線型トーンカーブ
t = 155
x = np.arange(256)
y = np.clip(255 / t * x, 0, 255)

# 変換する。z
dst = cv2.LUT(img, y)
imshow(dst)

コントラストを上げる (2)

In [5]:
# コントラストを上げる折れ線型トーンカーブ
t = 55
x = np.arange(256)
y = (255 - t) / 255 * x + t

# 変換する。
dst = cv2.LUT(img, y)
imshow(dst)

コントラストを下げる (1)

In [6]:
# コントラストを下げる折れ線型トーンカーブ
t = 55
x = np.arange(256)
y = np.clip(255 / (255 - t) * x - 255 / (255 - t) * t, 0, 255)

# 変換する。
dst = cv2.LUT(img, y)
imshow(dst)

コントラストを下げる (2)

In [7]:
# コントラストを下げる折れ線型トーンカーブ
t = 200
x = np.arange(256)
y = t / 255 * x

# 変換する。
dst = cv2.LUT(img, y)
imshow(dst)

明るさ、コントラストの補正

In [8]:
# 明るさ、コントラストの補正
alpha = 2
beta = 30
x = np.arange(256)
y = np.clip(alpha * x + beta, 0, 255)

# 変換する。
dst = cv2.LUT(img, y)
imshow(dst)

ガンマ補正

In [9]:
gamma = 1 / 3
x = np.arange(256)
y = (x / 255) ** gamma * 255

# 変換する。
dst = cv2.LUT(img, y)
imshow(dst)
In [10]:
gamma = 3
x = np.arange(256)
y = (x / 255) ** gamma * 255

# 変換する。
dst = cv2.LUT(img, y)
imshow(dst)

S 字型トーンカーブ

In [11]:
def scale(x):
    """x の範囲を [0, 255] にスケールする。
    """
    return 255 / (x.max() - x.min()) * (x - x.max()) + 255


x = np.arange(256)
y = np.arctan(np.linspace(-5, 5, 256))
y = scale(y)  # [atan(-5), atan(5)] -> [0, 255] にスケール

# 変換する。
dst = cv2.LUT(img, y)
imshow(dst)

周期関数

In [12]:
x = np.arange(256)
y = (np.sin(x * 12 * np.pi / 255) + 1) * 255 / 2

ax = plot_tone_transform(x, y, "周期関数")
plt.show()
In [13]:
x = np.arange(256)
y = (np.sin(x * 12 * np.pi / 255) + 1) * 255 / 2

# 変換する。
dst = cv2.LUT(img, y)
imshow(dst)

特定のチャンネルにだけ階調変換する

cv2.split() でチャンネルごとに分解したあと、グレースケール画像と同様に cv2.LUT() で階調変換を行い、cv2.merge() でチャンネルを結合して、カラー画像に戻します。

In [14]:
x = np.arange(256)
f = lambda x, gamma: ((x / 255) ** gamma * 255).astype(np.uint8)

# 画像をチャンネルごとに分解する。
b, g, r = cv2.split(img)

# 青のチャンネルを明るくする
b = cv2.LUT(b, f(x, 0.6))

# チャンネルを結合して画像にする。
dst = cv2.merge([b, g, r])
imshow(dst)
In [15]:
alpha = 1.3
beta = 10
x = np.arange(256)
y = np.clip(alpha * x + beta, 0, 255).astype(np.uint8)

# 画像をチャンネルごとに分解する。
b, g, r = cv2.split(img)

# 赤のチャンネルを明るくする
r = cv2.LUT(r, y)

# チャンネルを結合して画像にする。
dst = cv2.merge([b, g, r])
imshow(dst)

疑似カラー

グレースケール画像に対して、3つの階調変換を行ったあとに統合してカラー画像化することで、擬似的にグレースケール画像をカラー画像にすることができます。これを疑似カラーといいます。例えば、グレースケールの赤外線画像に色付けするのに使われます。

sample2.jpg

In [16]:
# 画像を読み込む。
img = cv2.imread("sample2.jpg")

# LUT テーブルを作成する。
x = np.arange(256)
by = np.interp(x, np.linspace(0, 255, 5), [0, 0, 255, 255, 0]).astype(np.uint8)
gy = np.interp(x, np.linspace(0, 255, 5), [0, 255, 255, 0, 0]).astype(np.uint8)
ry = np.interp(x, np.linspace(0, 255, 5), [255, 255, 0, 255, 255]).astype(np.uint8)

# 画像をチャンネルごとに分解する。
b, g, r = cv2.split(img)

b = cv2.LUT(b, by)
g = cv2.LUT(g, gy)
r = cv2.LUT(r, ry)

# チャンネルを結合して画像にする。
dst = cv2.merge([b, g, r])
imshow(dst)

グレースケール画像の色付けは cv2.applyColorMap() を使ってもできます。 これは予め用意されたいくつかのカラーマップを選んで適用できます。

In [17]:
dst = cv2.applyColorMap(img, cv2.COLORMAP_AUTUMN)
imshow(dst)

HSV に変換してから階調変換する

HSV 色空間は、色を色相 (Hue)、彩度 (Saturation)、明度 (Value) の3つの要素で表します。 画像を HSV 色空間に変換してから階調変換を行うことで、色合いや明るさを調整しやすくなります。

In [18]:
# 画像を読み込む。
img = cv2.imread("sample.jpg")
imshow(img)

# BGR -> HSV
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

# 画像をチャンネルごとに分解する。
h, s, v = cv2.split(hsv)

# 色相に対して、階調変換する。
x = np.arange(256)
y = (50 / 255 * x).astype(np.uint8)
h = cv2.LUT(h, y)

# チャンネルを結合して画像にする。
hsv = cv2.merge([h, s, v])

# HSV -> BGR
dst = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)

imshow(dst)

コメント

コメントする

目次