Camera YUV 圖片格式轉(zhuǎn)換和畫(huà)面旋轉(zhuǎn)的問(wèn)題

Camera YUV 圖片格式轉(zhuǎn)換和畫(huà)面旋轉(zhuǎn)的問(wèn)題

YUV 格式

Camera 拍照方向與預(yù)覽的問(wèn)題

YUV 轉(zhuǎn) RGB 的轉(zhuǎn)換矩陣
橫屏拍照到預(yù)覽效果

前面介紹 YUV 格式和 Camera 的方向問(wèn)題,就是為了這一個(gè)做準(zhǔn)備的。

遇到的問(wèn)題:

  • Camera 拿到的幀都是 YUV 格式的。
  • 一些圖片處理算法需要基于 RGB 圖片進(jìn)行處理。
  • Camera 方向與 Activity 方向不一致,需要進(jìn)行多角度兼容。
  • 進(jìn)行 YUV 轉(zhuǎn) RGB 和圖片旋轉(zhuǎn),兩個(gè)步驟加起來(lái)比較耗時(shí)。

考慮到 YUV 轉(zhuǎn) RGB 是一個(gè)個(gè)像素點(diǎn)進(jìn)行轉(zhuǎn)換的。

而 RGB 圖片旋轉(zhuǎn)也是一個(gè)個(gè)像素點(diǎn)進(jìn)行變換的。

那么可以?xún)蓚€(gè)過(guò)程合并處理,根據(jù)旋轉(zhuǎn)角度的不同進(jìn)行不同方向的遍歷存儲(chǔ)。


Camera 默認(rèn)幀的 YUV 格式為 NV21 (YUV420SP,不了解的可以看這篇文章 YUV 格式 )。

所以基于 NV21 轉(zhuǎn) RGB 同時(shí)實(shí)現(xiàn) RGB 圖片的旋轉(zhuǎn)。

處理 XY 坐標(biāo)變換的類(lèi)(寫(xiě)得復(fù)雜了些,可以按自己的想法寫(xiě))。


public class TwoDimensionalMatrixRotate {
    private int orienta;
    private int xmax;
    private int ymax;
    private int xmax_new;
    private int ymax_new;
    private int x_start;
    private int y_start;
    private int x_add;
    private int y_add;
    private int index;

    public TwoDimensionalMatrixRotate(int xmax, int ymax, int orienta) {
        init(xmax, ymax, orienta);
    }

    private void init(int _xmax, int _ymax, int _orienta) {
        orienta = _orienta;
        xmax = _xmax;
        ymax = _ymax;
        switch (orienta) {
            case   0:       // x + y * xmax
                xmax_new = xmax;
                ymax_new = ymax;

                x_start = 0;
                x_add   = +1;
                y_start = 0;
                y_add   = +xmax;

                index = calcIndex();   // 0;
                break;

            case  90:       // ymax - y - 1 + x * ymax
                xmax_new = ymax;
                ymax_new = xmax;

                x_start = 0;
                x_add   = +ymax;
                y_start = ymax - 1;
                y_add   = -1;

                index = calcIndex();   // ymax - 1;
                break;

            case 180:       // xmax - x - 1 + (ymax - y - 1) * xmax
                xmax_new = xmax;
                ymax_new = ymax;

                x_start = xmax - 1;
                x_add   = -1;
                y_start = ymax - 1;
                y_add   = -xmax;

                index = calcIndex();  // xmax * ymax - 1;
                break;

            case 270:       // y + (xmax - x - 1) * ymax
                xmax_new = ymax;
                ymax_new = xmax;

                x_start = xmax - 1;
                x_add   = -ymax;
                y_start = 0;
                y_add   = +1;

                index = calcIndex();   // (xmax - 1) * ymax;
                break;
        }
    }

    private int calcIndex() {
        int xx = x_start;
        int yy = y_start;
        int yy_add = Math.abs(y_add);

        if (orienta == 90 || orienta == 270) {
            xx = y_start;
            yy = x_start;
            yy_add = Math.abs(x_add);
        }

        return xx + yy * yy_add;
    }

    public int getXstart() {
        return x_start;
    }

    public int getXadd() {
        return x_add;
    }

    public int getYstart() {
        return y_start;
    }

    public int getYadd() {
        return y_add;
    }

    public int getIndex() {
        return index;
    }

    public int getPosition(int x, int y) {
        return (index + y * y_add + x * x_add);
    }
}

實(shí)現(xiàn) YUV 轉(zhuǎn) RGB 并旋轉(zhuǎn) RGB 圖片。


private void decodeYUV420SP(int[] rgb, byte[] yuv420sp, int width, int height, int orienta) {
    final int frameSize = width * height;

    int uvp, u, v;
    int y1192, y, r, g, b;

    TwoDimensionalMatrixRotate twoDimMatrixRotate = new TwoDimensionalMatrixRotate(width, height, orienta);

    final int x_add = twoDimMatrixRotate.getXadd();
    final int y_add = twoDimMatrixRotate.getYadd();
    final int index = twoDimMatrixRotate.getIndex();
    int flag = index;
    for (int j = 0, yp = 0; j < height; ++j, flag=index+j*y_add) {
        uvp = frameSize + (j >> 1) * width;
        u = v = 0;
        for (int i = 0; i < width; ++i, ++yp, flag+=x_add) {
            y = (0xff & ((int) yuv420sp[yp])) - 16;
            if (y < 0) {
                y = 0;
            }
            if ((i & 1) == 0) {
                v = (0xff & yuv420sp[uvp++]) - 128;
                u = (0xff & yuv420sp[uvp++]) - 128;
            }

            y1192 = 1192 * y;
            r = (y1192 + 1634 * v);
            g = (y1192 -  833 * v - 400 * u);
            b = (y1192 + 2066 * u);

            if (r < 0) { r = 0; } else if (r > 262143) { r = 262143; }
            if (g < 0) { g = 0; } else if (g > 262143) { g = 262143; }
            if (b < 0) { b = 0; } else if (b > 262143) { b = 262143; }

            rgb[flag] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);
        }
    }
}

原理:

NV21 (YUV420SP)轉(zhuǎn) RGB 是一行一行的存儲(chǔ) RGB 像素點(diǎn)。

只需要更改存儲(chǔ)的順序,就可以實(shí)現(xiàn)同步的 RGB 旋轉(zhuǎn)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 由于H.264等壓縮算法都是在YUV的顏色空間上進(jìn)行的,所有在進(jìn)行壓縮前,首先要進(jìn)行顏色空間的轉(zhuǎn)換。如果攝像頭采集...
    眷卿三世閱讀 13,789評(píng)論 2 6
  • 一、文章說(shuō)明 上周開(kāi)始寫(xiě)直播相關(guān)的文章,寫(xiě)了一篇手機(jī)直播總覽的文章,沒(méi)想到得到大家很多贊和關(guān)注,在此感謝大家支持。...
    風(fēng)從影閱讀 20,250評(píng)論 33 133
  • 文章參考: 圖文詳解YUV420數(shù)據(jù)格式 YUV主要采樣格式理解 YUV格式詳解 百度百科和維基百科 概述 本文基...
    Felix_lin閱讀 3,835評(píng)論 0 5
  • 從簡(jiǎn)書(shū) (平水韻) 汗青成簡(jiǎn)書(shū)心得,堅(jiān)守日更貪墨多。 網(wǎng)海懸珠覓同道,錚規(guī)唱和共研磨。 從QQ達(dá)人到微信達(dá)人,再想...
    聞笛柳閱讀 385評(píng)論 4 6
  • 我們天天盼著秋游,今天,秋游終于來(lái)了!我們秋游的地點(diǎn)是環(huán)城北路,聽(tīng)說(shuō)路有點(diǎn)遠(yuǎn),反正我管它遠(yuǎn)不遠(yuǎn)呢,只要可以...
    江妍妍08閱讀 292評(píng)論 0 3

友情鏈接更多精彩內(nèi)容