FC2カウンター FPGAの部屋 YUV-RGB変換1(方式の検討)
FC2ブログ

FPGAやCPLDの話題やFPGA用のツールの話題などです。 マニアックです。 日記も書きます。

FPGAの部屋

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。Xilinx ISEの初心者の方には、FPGAリテラシーおよびチュートリアルのページをお勧めいたします。

YUV-RGB変換1(方式の検討)

さて、Sobelフィルタがうまくいっていないが、たぶん飽和演算の丸め方の問題だと思っている。ラプラシアン・フィルタもうまく行ったので、今度はYUV-RGB変換してカラーにしてみようと思う。
DWMの2007年8月号の”VGA ディジタルCMOS カメラ・モジュールからの入力回路を作ろう”でもYUV-RGB変換のやり方が書いてあるが、乗算器を9個使ってしまうので、精度は落ちても乗算器を使わないでやってみようと思う。
YUVフォーマット及び YUV<->RGB変換”ページの”8bitフルスケールYUVと8bitフルスケールRGBの相互変換”を参考にしてみた。それによるとU/Vが0から255の値を取る場合のRGB信号を求める式は下のようになる。

R = 1.000Y + 1.402(V-128)
G = 1.000Y - 0.344(U-128) -0.714(V-128)
B = 1.000Y + 1.772(U-128)


上記の式を1とする。

ここで、Twitterでs_osafuneさんに変換の公式を教えていただいた。それによるとYUV=8:S8:S8, RGB=8:8:8とすると、下のような式になるとのことだった。(s_osafuneさん、昨日の時点でここまでブログは式1まで書きかけでした)

R = (Y<<8 + 359*V)>>8
G = (Y<<8 - 183*V - 88*U)>>8
B = (Y<<8 + 454*U)>>8


上記の式を2とする。これを16ビットまでで飽和演算をするそうだ。RGBよりもYUVの方が空間が広いとのことだった。これは良く考えてみれば、通常の値を取り扱うRGBよりもUVが差分値のYUVの方が同じ8ビット長ずつとすれば、表せる値が大きいのがわかる。
あれ、良く見ると式2のR式のVの係数359を256で割ると1.4023...、G式の183を256で割ると0.7148...、Uの88を256で割ると0.34375、B式の454を256で割ると1.7734...となり、1式と2式は(U-128),(V-128)を除いて、ほとんど等価であるということがいえると思う。それでは式2のUをU-128、VをV-128に置き換えた下の3式でYUV-RGB変換をしてみようと思う。(s_osafuneさん、ありがとうございました。式1を変換する手間が省けました)

R = (Y<<8 + 359*(V-128))>>8
G = (Y<<8 - 183*(V-128) - 88*(U-128))>>8
B = (Y<<8 + 454*(U-128))>>8


ここで定数項を括りだして、最終的な式に展開する前に1.402などの10進数の小数を2進数の小数に変換する方法を紹介しておこうと思う。(”小数表現”などを参照した)
2進数の小数の0.1は2^(-1) = 10進数の0.5
2進数の小数の0.01は2^(-2) = 10進数の0.25
よって、2進数の0.11を10進数に直すと0.5 + 0.25 = 0.75となる。
逆に10進数の0.75を2進数に直すのは2^(-1)と2^(-2)を引くと0になるので0.11となる。
参考にしたサイトに紹介されていたのは10進数の小数に2を掛けて行って桁上がりしたところの2進数のビットを1にする方法だ。
この方法で0.402を8桁の2進数の小数に直してみよう。
まずは1.402を2進数に変換してみよう。小数部分だけ取り出した0.402に2を掛ける。

0.402 X 2 = 0.804 なので2進数の小数の最初の桁は0
0.804 X 2 = 1.608 なので2進数の小数のこの桁は 1、次は桁上がりの1は除く。
0.608 X 2 = 1.216 なので2進数の小数のこの桁は 1、次は桁上がりの1は除く。
0.216 X 2 = 0.432 なので2進数の小数のこの桁は 0
0.432 X 2 = 0.864 なので2進数の小数のこの桁は 0
0.864 X 2 = 1.728 なので2進数の小数のこの桁は 1、次は桁上がりの1は除く。
0.728 X 2 = 1.456 なので2進数の小数のこの桁は 1、次は桁上がりの1は除く。
0.456 X 2 = 0.912 なので2進数の小数のこの桁は 0


ここまでで、0.402を2進数の小数に直すと0.01100110になった。最後に0.912残っているので四捨五入すると、0.01100111となる。これに1を加えると1.01100111となる。これを8ビット右シフトすると1_0110_0111となった。これを10進数に変換すると359となる。これで計算することができた。

さて、式3を展開して、定数項を出すと下の式4が導ける。

R = (Y<<8 + 359*V - 45,952)>>8
G = (Y<<8 - 183*V - 88*U + 34,688)>>8
B = (Y<<8 + 454*V - 58,112)>>8


これを16進数に直すと下の式5となる。(2進数では書くのが面倒なため)

R = (Y<<8 + X"167"*V - X"B380")>>8
G = (Y<<8 - X"58"*U - X"B7"*V + X"8780")>>8
B = (Y<<8 + X"1C6"*U - X"E300")>>8


これからはこの式を元にYUVをRGBに変換することにする。演算のビット数は2+1+16 = 19ビットとする。

(2009/11/23 追記)
takepon256さんから式を展開しないで、U-128、V-128の演算をしたほうが良いとのご指摘を受けたので、上の式3で演算してみることにした。

(200/12/02 追記)
式3を16進数に変換した。

R = (Y<<8 + X"167"*(V-128))>>8
G = (Y<<8 - X"B7"*(V-128) - X"58"*(U-128))>>8
B = (Y<<8 + X"1C6"*(U-128))>>8


さらに2進数に変換した。

R = (Y<<8 + "1_0110_0111"*(V-128))>>8
G = (Y<<8 - "1011_0111"*(V-128) - "0101_1000"*(U-128))>>8
B = (Y<<8 + "1_1100_0110"*(U-128))>>8


やはり演算のビット数は19ビットとする。

(2009/12/03 追記)
符号付きの掛け算のやり方を調べたが面倒だということがわかった。参照元は4ビットの符号付き掛け算器ウィキペディアの乗算器
やはり符号なしの掛け算ができる式5を使った方が演算器も少なくて済むという結論に達した。(U,Vはもともと符号なしの値)
それで式5を変形する。

R = (Y<<8 + "1_0110_0111"*V - X"B380")>>8
G = (Y<<8 - "1011_0111"*V - "0101_1000"*U + X"8780")>>8
B = (Y<<8 + "1_1100_0110"*U - X"E300")>>8


これで最終的にやってみることにした。

2010/08/27:追記
Rの式が間違っていたので修正しました
  1. 2009年11月22日 06:19 |
  2. 画像処理
  3. | トラックバック:0
  4. | コメント:4

コメント

わざわざ指摘するのもどうかと思ったのですが・・・
U、Vが8bitであれば、(U-128)、(V-128)は最上位bitを論理反転すれば出来ますよ。
  1. 2009/11/22(日) 21:19:36 |
  2. URL |
  3. takepon256 #-
  4. [ 編集 ]

takepon256さん、こんにちは。
それは私も不思議に思ったのですが、ESP企画から付いてきたサンプルがそうなっていたんです。なんか理由があるのかなとは思ったのですが、やはり、演算が面倒になってしまうし、takepon256さんご指摘のようにとりあえず(U-128)、(V-128)でやってみます。
いつもありがとうございました。
  1. 2009/11/23(月) 05:11:52 |
  2. URL |
  3. marsee #f1oWVgn2
  4. [ 編集 ]

名無しですみませんが…
ターゲット基板の製造元は専門家がやってる訳ではないのであまり参考にはしない方が良いと思います。
「とりあえず動いてるサンプル」って事で。
  1. 2009/12/09(水) 10:18:55 |
  2. URL |
  3. 名無し #JalddpaA
  4. [ 編集 ]

名無しさん、こんにちは。

了解しました。そのつもりですが、掛け算は掛け算器を使わない予定なので、展開した方が良かったようです。10nsのSRAMを10nsサイクルで使っているところなどは、納得が行かないところです。
  1. 2009/12/09(水) 13:04:35 |
  2. URL |
  3. marsee #f1oWVgn2
  4. [ 編集 ]

コメントの投稿


管理者にだけ表示を許可する

トラックバック URL
http://marsee101.blog.fc2.com/tb.php/1300-61d32a53
この記事にトラックバックする(FC2ブログユーザー)