OpenCVを使って、画像のHSV色空間における色相 Hue を回転させて色を変化させてみる。つまり、下記の図のような出力を得たい。
RGBからHSVへの変換
上記のサイトに詳しく書いてあるけど、HSVは色相(Hue)、彩度(Saturation・Chroma)、明度(Value・Brightness)の三つの成分からなる色空間。
今回やることは
- RGBをHSVに変換する
- H(Hue)を回転させる
- RGBに戻す
という単純な処理。まずはRGBからHSVへの変換。
import numpy as np import cv2 rgb = rgb.astype(np.uint8) hsv = cv2.cvtColor(rgb, cv2.COLOR_RGB2HSV)
cv2.cvtColorは入力されたrgbの型がuint8かfloat32かで挙動が変化する。今回は画像を読み込んだときと同じuint8でhsvに変換する。
hsvのhの値の上限下限は下記のように[0,179]となっている。
In [7]: h = hsv[:,:,0] In [8]: h.max() Out[8]: 179 In [9]: h.min() Out[9]: 0
Hueの値と色の関係
Hueの値がどの色に相当するのかを調査してみた。結果はこちら
0が赤で60が緑、120が青というようになった。この図を出力するためのコードは以下
import numpy as np import cv2 from matplotlib import pyplot as plt if __name__ == '__main__': h = np.arange(180, dtype=np.uint8).reshape(1, 180, 1) s = (np.ones(180, dtype=np.uint8)*255).reshape(1, 180, 1) v = s.copy() hs = np.append(h, s, axis=2) hsv = np.append(hs, v, axis=2) hsv = np.repeat(hsv, 90, axis=0) rgb = cv2.cvtColor(hsv, cv2.COLOR_HSV2RGB) plt.figure(figsize=(6,3.2)) plt.imshow(rgb) plt.yticks([]) # y軸を消す plt.xticks([0, 60, 120, 180], fontsize=15) plt.tight_layout(pad=0.3) plt.savefig('color.jpg', pad_inces=0.01) plt.show()
色相の回転
forループで少しずつ色相を回転させてみる。今回はuint8を使っているので、255以上で値が不定にならないように注意する。ということで回転の直前で型をuint16に変換してから回転させる。回転後は180以上になった値を0からに変換したいので、割り算の余り(%)を使う。
import numpy as np import cv2 mm = 16 imgs = [] for i in range(mm): ang = int(i*(180//mm)) hsv = cv2.cvtColor(img, cv2.COLOR_RGB2HSV) # HSVに変換 hsv = hsv.astype(np.uint16) # uint8だと255以上で不定になるので型を変更 hsv[:,:,0] = (hsv[:,:,0]+ang)%180 # 回転処理 hsv = hsv.astype(np.uint8) # 型を戻す dst = cv2.cvtColor(hsv, cv2.COLOR_HSV2RGB) # RGBに変換 imgs.append(dst)
サンプルコード
このページの一番最初のにあった画像を出力するためのコードを貼っておく。
import numpy as np import cv2 from skimage import data from skimage import io as skio from matplotlib import pyplot as plt if __name__ == '__main__': img = data.astronaut() h,w,c = img.shape img = img[:,:h] img = cv2.resize(img, (256, 256)) h,w,c = img.shape m = 4 mm = 4**2 imgs = [] for i in range(mm): ang = int(i*(180//mm)) hsv = cv2.cvtColor(img, cv2.COLOR_RGB2HSV) hsv = hsv.astype(np.uint16) # uint8だと255以上で不定になるので型を変更 hsv[:,:,0] = (hsv[:,:,0]+ang)%180 hsv = hsv.astype(np.uint8) # 型を戻す dst = cv2.cvtColor(hsv, cv2.COLOR_HSV2RGB) imgs.append(dst) imgs = np.array(imgs) imgs = imgs.reshape(m,m,h,w,c) imgs = imgs.transpose(0,2,1,3,4) imgs = imgs.reshape(m*h,m*w,c) skio.imsave('hsv.png', imgs)
結果の大きめの画像