YUV420形式の画像ファイルを回転させてみたい 4




さて、YUV画像回転の話も

4回目に突入した。

Visual Studio Expressの

カラースキーマ



今使っているのはC#ではいいが、C++の表示だとコードが読みにくいか...

前回に続き、残りのメンバ関数の説明である。

// 回転角度とオリジナル画像のサイズを指定する
void YuvImageRotate::SetYuvRawData(int orient, unsigned char *src_data, int width, int height)
{
unsigned char *pNew_src = NULL;

//check the image size, even or odd
if ((width % 2 == 0) && (height % 2 == 0)) {
pNew_src = new unsigned char[width * height + (width / 2 * height / 2) * 2];
if (pNew_src != NULL) {
memcpy(pNew_src, src_data, width*height + (width / 2 * height / 2) * 2);
m_pSrc = pNew_src;
m_SrcWidth = width;
m_SrcHeight = height;
}
}
else {
if (width % 2 && height % 2) {
// odd x odd
m_SrcWidth = width + 1;
m_SrcHeight = height + 1;
int NewSize = m_SrcWidth * m_SrcHeight + (m_SrcWidth / 2 * m_SrcHeight / 2) * 2;
pNew_src = new unsigned char[NewSize];
if (pNew_src != NULL) {
// Y成分
for (int i = 0; i < height; i++) {
memcpy(&pNew_src[i * m_SrcWidth], &src_data[i * width], width);
memcpy(&pNew_src[i * m_SrcWidth + width], &src_data[i * width + width - 1], sizeof(unsigned char));
}
memcpy(&pNew_src[height * m_SrcWidth], &pNew_src[(height - 1) * m_SrcWidth], m_SrcWidth);
}
}
else if (width % 2) {
// odd x even
m_SrcWidth = width + 1;
m_SrcHeight = height;
int NewSize = m_SrcWidth * m_SrcHeight + (m_SrcWidth / 2 * m_SrcHeight / 2) * 2;
pNew_src = new unsigned char[NewSize];
if (pNew_src != NULL) {
// Y成分
for (int i = 0; i < height; i++) {
memcpy(&pNew_src[i * m_SrcWidth], &src_data[i * width], width);
memcpy(&pNew_src[i * m_SrcWidth + width], &src_data[i * width + width - 1], sizeof(unsigned char));
}
}
}
else {
//even x odd
m_SrcWidth = width;
m_SrcHeight = height + 1;
int NewSize = m_SrcWidth * m_SrcHeight + (m_SrcWidth / 2 * m_SrcHeight / 2) * 2;
pNew_src = new unsigned char[NewSize];
if (pNew_src != NULL) {
// Y成分
for (int i = 0; i < height; i++) {
memcpy(&pNew_src[i * m_SrcWidth], &src_data[i * width], width);
}
memcpy(&pNew_src[height * m_SrcWidth], &pNew_src[(height - 1) * m_SrcWidth], m_SrcWidth);
}
}

if (pNew_src != NULL) {
// U成分
memcpy(&pNew_src[m_SrcWidth * m_SrcHeight], &src_data[width * height], m_SrcWidth / 2 * m_SrcHeight / 2);
// V成分
memcpy(&pNew_src[m_SrcWidth * m_SrcHeight + m_SrcWidth / 2 * m_SrcHeight / 2],
&src_data[width * height + m_SrcWidth / 2 * m_SrcHeight / 2], m_SrcWidth / 2 * m_SrcHeight / 2);

m_pSrc = pNew_src;
}
}

if (m_pSrc != NULL) {
        // 回転情報を取得し、メンバ変数に格納
getRotateInfo(orient);
if (m_bHorizon) {
                        // 水平反転を実行
invokeReverse();
}
                // 回転を実行
invokeRotate();
}

return;
}


ここでのポイントは、与えられた画像のサイズが、都合よく 偶数 × 偶数 であれば

問題ないが、そうでない場合もあるということである。

偶数サイズでは、U成分、V成分の割合がY成分の半分でこのようになる。

YYYY
YYYY
UUVV

奇数サイズでは、U成分、V成分の割合がY成分の半分だとすると

YYY             YYY
YYY    あるいは   YYY
UUVV           UV

切り上げなのか、切り捨てとなるのかで、扱いには少々都合が悪い。

今回は切り上げ方式として、奇数 × 偶数 あるいは 偶数 × 奇数の場合は

奇数の辺を無理やり偶数にするよう拡張を行っている。

最後のデータをコピーしてちょうど、1ピクセル分増加させることで

すべての画像を 偶数 × 偶数 として扱えるようにしている。


さらに残りのメンバ関数の説明は次回に続く(最終回)


今日の名言
幸不幸は、財産、地位、職業などで決まるものではない。何を幸福と考え、
また不幸と考えるか - その考え方が、幸不幸の分かれ目なのである。
例えば、同じ場所で同じ仕事をしている人がいるとする。二人は、だいたい同じ
財産と地位を持っているにもかかわらず、一方は不幸で他方は幸福だという
ことがよくある。なぜか?気の持ち方が違うからだ。
                                デール・カーネギー

事の成り行きを運命の女神のせいにするのは大きな心得違いだ。
彼女自身は全く無力で「分別」の神に支配されているからだ。
                                ジョン・ドライデン

上着は布地に合わせて裁断すべきだ。同様に、変化する環境に対して
自分自身を合わせるようにした方がよい。
                                ウィリアム・R・イング

いつ機会をつかむべきかということの次に、人生で最も重要なことは、
いつ先立って利益をつかむかである。
                                ベンジャミン・ディズレーリ