2008年11月06日

RGBとHSVの相互変換[R]

Rのrimageパッケージはjpeg形式の画像をRに読み込ませて取り扱うのに便利なパッケージだが、色の表現形式としてはRGBのみの対応になっている。

RGB形式は確かに便利でわかりやすいが、用途によっては色相(Hue)、彩度(Saturation・Chroma)、明度(Brightness・Lightness・Value)の3つの成分を用いて色を指定するHSVという形式が便利なことがある。

便利なことがあるゆえに、様々な言語においてRGB⇔HSV相互変換のためのプログラム、アルゴリズムが書かれ、公開されているのだが、ちょっと探した感じではR用のものは見つけられなかった。(2008/11/7追記:はてブのコメント見ててもしやと思ったら変換用の関数があった。しかも名前がrgb2hsv。ちょっと打ち込んでみてたら分かったのに恥ずかしい…。ただそのままでは使えそうにないのでもうちょっと調べてまた書く予定。hsvをrgbにする関数は本当に無いかも?とりあえず以下のスクリプトのオブジェクト名は変更。)

ので作ってみた。

まずはRGB→HSV

#3次元配列から第3次元各要素の最大値を要素とする2次元行列を生成する
max.rgb <- function(z){
	y <- z[,,1]
	y[z[,,1]<=z[,,2] & z[,,3]<=z[,,2]] <- z[,,2][z[,,1]<=z[,,2] & z[,,3]<=z[,,2]]
	y[z[,,1]<=z[,,3] & z[,,2]<=z[,,3]] <- z[,,3][z[,,1]<=z[,,3] & z[,,2]<=z[,,3]]
	y
	}

#3次元(略)最小値を要素とする(略)
min.rgb <- function(z){
	y <- z[,,1]
	y[z[,,1]>=z[,,2] & z[,,3]>=z[,,2]] <- z[,,2][z[,,1]>=z[,,2] & z[,,3]>=z[,,2]]
	y[z[,,1]>=z[,,3] & z[,,2]>=z[,,3]] <- z[,,3][z[,,1]>=z[,,3] & z[,,2]>=z[,,3]]
	y
	}

#RGB→HSV変換
my.rgb2hsv <- function(x){
	#Vの計算
	hsV <- max.rgb(x)
	#Sの計算
	hSv <- (max.rgb(x)-min.rgb(x))/max.rgb(x)
	hSv[max.rgb(x)==0] <- 0
	#Hの計算
		#入れ物の用意
			Hsv <- x[,,1]
		#Rがmaxの部分のH
			Rmax <- 60*(x[,,2]-x[,,3])/(max.rgb(x)-min.rgb(x))
			Hsv[x[,,1]==max.rgb(x)] <- Rmax[x[,,1]==max.rgb(x)]
		#Gがmaxの部分のH
			Gmax <- 60*(x[,,3]-x[,,1])/(max.rgb(x)-min.rgb(x)) +120
			Hsv[x[,,2]==max.rgb(x)] <- Gmax[x[,,2]==max.rgb(x)]
		#Bがmaxの部分のH
			Bmax <- 60*(x[,,1]-x[,,2])/(max.rgb(x)-min.rgb(x)) +240
			Hsv[x[,,3]==max.rgb(x)] <- Bmax[x[,,3]==max.rgb(x)]
		#Hが定義されない部分
			Hsv[max.rgb(x)==min.rgb(x)] <- 0
		#値がマイナスの部分
			Hsv[Hsv<0] <- Hsv[Hsv<0]+360
	array(c(Hsv, hSv, hsV),dim=c(dim(Hsv),3))  #imagematrixオブジェクトと同様にH,S,Vの配列を出力
	}

最初にRGB成分の最大値・最小値のみを要素とする行列を作成する関数を定義し、これを変換用の関数中で用いている。なんかもうちょっと綺麗な書き方をしたい・できそうな気がしたけど思いつかない。

RGB→HSV変換関数の出力はimagematrixオブジェクトと呼ばれる配列と同様のものにした。H成分、S成分、V成分がそれぞれ一枚ずつ行列に格納される。

使うにはrimageパッケージのread.jpeg関数などで作成したimagematrixオブジェクトを突っ込むだけ。

photo <- read.jpeg("写真.jpeg")
photo.hsv <- rgb2hsv(photo)

ちょっと重いのが気になる。どこが原因なんだろ。

次にHSV→RGB変換。場合分けが多いのでちょっと大変。

#HSV→RGB変換
my.hsv2rgb <- function(x){
	H <- x[,,1]
	S <- x[,,2]
	V <- x[,,3]
	R <- array(rep(0,length(H)), dim=dim(H))
	G <- array(rep(0,length(H)), dim=dim(H))
	B <- array(rep(0,length(H)), dim=dim(H))
	#Hiという数値の計算
		Hi <- floor(H/60)
	#Fの計算
		rgbF <- H/60 - Hi
	#Mの計算
		M <- V*(1-S)
	#Nの計算
		N <- V*(1-S*rgbF)
	#Kの計算
		K <- V*(1-S*(1-rgbF))
	#Hiが0のとき
		R[Hi==0] <- V[Hi==0]
		G[Hi==0] <- K[Hi==0]
		B[Hi==0] <- M[Hi==0]
	#1のとき
		R[Hi==1] <- N[Hi==1]
		G[Hi==1] <- V[Hi==1]
		B[Hi==1] <- M[Hi==1]
	#2のとき
		R[Hi==2] <- M[Hi==2]
		G[Hi==2] <- V[Hi==2]
		B[Hi==2] <- K[Hi==2]
	#3のとき
		R[Hi==3] <- M[Hi==3]
		G[Hi==3] <- N[Hi==3]
		B[Hi==3] <- V[Hi==3]
	#4のとき
		R[Hi==4] <- K[Hi==4]
		G[Hi==4] <- M[Hi==4]
		B[Hi==4] <- V[Hi==4]
	#5のとき
		R[Hi==5] <- V[Hi==5]
		G[Hi==5] <- M[Hi==5]
		B[Hi==5] <- N[Hi==5]
	#S=0のとき
		R[S=0] <- V[S=0]
		G[S=0] <- V[S=0]
		B[S=0] <- V[S=0]
	imagematrix(array(c(R, G, B),dim=c(dim(R),3)))  #imagematrixオブジェクトとして出力
	}

出力はimagematrixオブジェクトなのでそのままプロットしておk。

plot(my.hsv2rgb(photo.hsv))

ついでにhsv形式の画像をプロットする関数なども作っておくと便利かもしれない。

#HSV形式のデータをプロットする関数
hsv.plot <- function(x){
	plot(my.hsv2rgb(x))
	}

まあちょっとだけ打ち込む文字数が減るだけなんですけど。

これだけなんだけど、肝心のhsvへ変換する関数が重いのがやっぱ気になる。使えないほどじゃないんだけど、rgbへの変換より明らかに重い。もうちょっと調べて改良しないとだめか。

posted by Rion778 at 20:09 | Comment(0) | TrackBack(0) | PC関連。HTMLとか,Linuxとか,Rとか | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前: [必須入力]

メールアドレス: [必須入力]

ホームページアドレス: [必須入力]

コメント: [必須入力]

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
この記事へのトラックバックURL(言及がない、関連がないと判断した場合削除することがあります)
http://blog.seesaa.jp/tb/109190602
※言及リンクのないトラックバックは受信されません。

この記事へのトラックバック
×

この広告は1年以上新しい記事の投稿がないブログに表示されております。