動画の解説を参照
ピクセルの色を表すには、いままで使っていたRGBの値を使う方法のほかに、色相、彩度、明度の3つの情報を使う方法 (
HSV表現) があります。
- 色相 (Hue) : 色の種類。OpenCVでは0~179の値であらわす
- 彩度 (Saturation) : 色の鮮やかさ。大きいほど鮮やかになる。色空間では中心軸からの距離として扱い、OpenCVでは0~255の値であらわす
- 明度 (Value) : 明るさ。色空間では縦方向の座標として扱い、OpenCVでは0~255の値であらわす
これを下のような図で表わしたものを
色立体とよび、この3つの座標で表わされる空間を
色空間と言います。
今回は画像の色相・彩度・明度を変えてその結果を確認します。
そのために、以下の条件を満たす元画像が必要になります。
- 赤・黄・緑・シアン・青・マゼンタの6色のいずれかに近い色を含む
- 鮮やかすぎずくすみ過ぎてもいないエリアを含む
- 明るすぎず暗すぎないエリアを含む
例えばこのような画像です。
元画像を決めたら、以降の変換の元になる画像変数「img」と、それをHSV形式に変換した変数「img_hsv」を作っておきます。
(この時点では読み込むだけで、画像は出力しません)
import cv2
import numpy as np
from google.colab import files
file = files.upload()
filename = next(iter(file))
img = cv2.imread(filename)
img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
動画の解説を参照
概要で述べたように、Hue (色相) はOpenCVでは 0~179 の値をとります。
ただし、一般的には色相は「1回転で元の色に戻る」このような図で表されます。
この図での時計回りの回転角 (0~359) は、OpenCVでいう Hue の値の2倍にあたります。
Hue の値を30ずつ増やすと、色がこのように変わります。
元画像の黄色い部分に注目すると、緑、シアン、青、マゼンタ、赤に変わっていることがわかります。
元画像
60°回転 (Hue += 30)
120°回転 (Hue += 60)
180°回転 (Hue += 90)
240°回転 (Hue += 120)
300°回転 (Hue += 150)
OpenCVで Hue の値を増やす処理はこのようになります。
img1[:, :, 0] = (img1[:, :, 0] + dh) % 180
「% 180」は、Hue の値の範囲が 0~179 なので、その範囲がらはみ出したときに範囲内に収まるようにするための処理です。
(たとえば 175 → 175 + 30 = 205 → 25)
dhs = [30, 60, 90, 120, 150]
for dh in dhs:
img1 = img_hsv.copy()
img1[:, :, 0] = (img1[:, :, 0] + dh) % 180
img1 = cv2.cvtColor(img1, cv2.COLOR_HSV2BGR)
cv2.imwrite('ex1_' + format(dh * 2, '03') + '.jpg', img1)
動画の解説を参照
彩度は鮮やかさを表す値なので、小さくすればくすんだ色になり、大きくすれば鮮やかになります。
色立体ではそれぞれ中心側への移動、外側への移動に対応します。
元画像
彩度下げ
(Saturation -= 100)
彩度上げ
(Saturation += 100)
OpenCVでの彩度の範囲は 0~255 なので、値を変更したあとで clip関数で範囲内に収まるように修正します。
img2[:, :, 1] = np.clip(img2[:, :, 1] + ds, 0, 255)
ただし、clip関数を使うためには値の形式を float32型にする必要があるので、彩度を変える前に
img2 = img2.astype(np.float32)
で型を変え、処理後に
img2 = img2.astype(np.uint8)
で元の型に戻します。
dss = [-100, 100]
for ds in dss:
img2 = img_hsv.copy()
img2 = img2.astype(np.float32)
img2[:, :, 1] = np.clip(img2[:, :, 1] + ds, 0, 255)
img2 = img2.astype(np.uint8)
img2 = cv2.cvtColor(img2, cv2.COLOR_HSV2BGR)
cv2.imwrite('ex2_' + str(ds) + '.jpg', img2)
動画の解説を参照
明度は明るさを表す値なので、小さくすれば暗くなり、大きくすれば明るくなります。
色立体ではそれぞれ下への移動、上への移動に対応します。
元画像
明度下げ
(Value -= 100)
明度上げ
(Value += 100)
OpenCVでの明度の範囲は 0~255 なので、値を変更したあとで clip関数で範囲内に収まるように修正します。
(彩度の変更のときと同様に、この処理の前後で型の変更を行います)
img3[:, :, 2] = np.clip(img3[:, :, 2] + dv, 0, 255)
dvs = [-100, 100]
for dv in dvs:
img3 = img_hsv.copy()
img3 = img3.astype(np.float32)
img3[:, :, 2] = np.clip(img3[:, :, 2] + dv, 0, 255)
img3 = img3.astype(np.uint8)
img3 = cv2.cvtColor(img3, cv2.COLOR_HSV2BGR)
cv2.imwrite('ex3_' + str(dv) + '.jpg', img3)
動画の解説を参照
今回作成したノートブックを「imgprc2024@gmail.com」と共有してください。
※ 第2回で共有した、画像共有用の「画像処理」フォルダの中に「第12回」フォルダを作り、その中に今回の元画像と出力画像を入れてください。
※ 課題の再提出の際は、ノートブックの再度の共有はせずにチャットで連絡してください。