いかおです。
前回の「プレモルの宣伝でやってるエフェクトを真似して」の続きです。
一つ一つのピクセルがuyvy422でくるとなると、hueへの変換は以下の様になります
まず、RGBにします。
R = 1.000Y + 1.402V
G = 1.000Y – 0.344U – 0.714V
B = 1.000Y + 1.772U
hue = 180 / π * atan2(√3 * (G – B), 2 * R – (float)G – B)
※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)){ // モノ黒にする }
で、前回のサンプルでもいまいちキレイじゃないので、調査の上、
キレイにして掲載します(いずれね)