Pythonいぬ

pythonを使った画像処理に関する記事を書いていきます

OpenCVを使ってHSV色空間の色相Hを回転させる

OpenCVを使って、画像のHSV色空間における色相 Hue を回転させて色を変化させてみる。つまり、下記の図のような出力を得たい。

f:id:tzmi:20200107215821j:plain

RGBからHSVへの変換

ja.wikipedia.org

上記のサイトに詳しく書いてあるけど、HSVは色相(Hue)、彩度(Saturation・Chroma)、明度(Value・Brightness)の三つの成分からなる色空間。

今回やることは

  1. RGBをHSVに変換する
  2. H(Hue)を回転させる
  3. 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の値がどの色に相当するのかを調査してみた。結果はこちら

f:id:tzmi:20200107224937j:plain

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)

結果の大きめの画像

f:id:tzmi:20200107225322j:plain