プレモルの宣伝でやってるエフェクトを真似してみた(その方式).vol2

タグ: | 投稿日: 投稿者:

いかおです。

前回の「プレモルの宣伝でやってるエフェクトを真似して」の続きです。

一つ一つのピクセルがuyvy422でくるとなると、hueへの変換は以下の様になります

まず、RGBにします。
R = 1.000Y + 1.402V
G = 1.000Y – 0.344U – 0.714V
B = 1.000Y + 1.772U

hue = 180 / π * atan2(√3 * (GB), 2 * R – (float)GB)

※double atan2(double y, double x); // math.h のやつね

これでHueがマイナスである場合がありますので、マイナスだったら
360を足します

これでやうやくHueになります。

こんな計算を例えば(たかだか)1080iでやろうとすると
毎秒この計算を、1920x1080x30 回やりますとかなりゴーヂャスなPCでも間に合いません

確かにこのままやったら再生が間に合わなかった
で、最初に全パターン計算しといてテーブルに格納するんです
マッチングテーブルですねぇ・・・

ただ、yuv値ってそれぞれ(この場合)8bitですが、実際の値の範囲は

y 16~235
u(cb)/ v(cr) 16~240

こんな感じになりますが、とりあえず全部作っちゃえってんで、ソースコード公開!!
★RGB全パターンからHueを求めてYUVのテーブルに押し込みます。

.
#define KOSUU     256
.
.
    memset((char *)YUVTable, 0x00, sizeof(uint16_t) * KOSUU * KOSUU * KOSUU);
    double root3 = sqrt(3);
    float  hue;
    for(int ir=0;ir < KOSUU;ir++){
        for(int ig=0;ig < KOSUU;ig++){
            for(int ib=0;ib < KOSUU;ib++){
                float y, u, v;
                uint8_t ucy, ucu, ucv;
                y = (0.299f  * ir) + (0.577f * ig) + (0.114f * ib);
                u = (-0.169f * ir) - (0.331f * ig) + (0.5f   * ib);
                v = (0.5f    * ir) - (0.419f * ig) - (0.081f * ib);
                if((round(y) < 0.0f) || (round(y) > 255.0f)){
                    syslog(LOG_ERR, "Y overfloow at(%d:%d:%d)", ir, ig, ib);
                    continue;
                }
                if((ir == 0) && (ig == 0) && (ib == 255)){
                    u = 255.0f;
                } else if((round(u + 128.0f) < 0.0f) || (round(u + 128.0f) > 255.0f)){
                    syslog(LOG_ERR, "U overfloow at(%d:%d:%d)", ir, ig, ib);
                    continue;
                }
                if((ir == 255) && (ig == 0) && (ib == 0)){
                    v = 255.0f;
                } else if((round(v + 128.0f) < 0.0f) || (round(v + 128.0f) > 255.0f)){
                    syslog(LOG_ERR, "V overfloow at(%d:%d:%d)", ir, ig, ib);
                    continue;
                }
                ucy = (uint8_t)round(y);
                ucu = (uint8_t)round(u + 128.0f);
                ucv = (uint8_t)round(v + 128.0f);
                hue = 180 / M_PI * atan2(root3 * ((float)ig - (float)ib), 2 * (float)ir - (float)ig - (float)ib);
                if(hue < 0.0f) hue = hue + 360;
                YUVTable[(ucy * KOSUU * KOSUU) + (ucu * KOSUU) + ucv] = (uint16_t)round(hue);
             }
         }
     }

これを、Hue中央値とレンジを指定させといて、比較のため”0″変位に置き換えて

 // m_hue   ..中央値
 // m_range ..レンジ
 // m_gap   ..変位値(0変位比較のための加算する値) 
 // こんな風にしといて         
 if((m_hue + m_range) > 360)
    m_high = (m_hue + m_range) - 360;
  else
    m_high = m_hue + m_range;

  if(((int)m_hue - (int)m_range) < 0)
      m_low = ((int)m_hue - (int)m_range) + 360;
  else
      m_low = m_hue - m_range;         if(m_low > m_high){

  m_gap = 360 - m_low;
  m_low = 0;
  m_high = m_high + m_gap;
......
  uint16_t nowHue = YUVTable[(y * KOSU * KOSU) + (u * KOSU) + v] + m_gap;
  if(nowHue > 360) nowHue = nowHue - 360;
  if((nowHue <= m_low) || (nowHue >= m_high)){
      // モノ黒にする
  }

で、前回のサンプルでもいまいちキレイじゃないので、調査の上、
キレイにして掲載します(いずれね)

Share on Google+Tweet about this on TwitterShare on StumbleUponShare on Facebook