Android Camera2 Image轉Mat

Android Camera2獲取的圖片為android.media.Image,opencv使用時需要轉成Mat煞檩。

Yuv420轉Mat

Android官方推薦使用yuv420圖片格式

import android.annotation.TargetApi;
import android.media.Image;
import android.os.Build;

import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.imgproc.Imgproc;

import java.nio.ByteBuffer;

@TargetApi(Build.VERSION_CODES.KITKAT)
public class Yuv420 {

    // 復制uv通道數(shù)據(jù)
    private static void copy(ByteBuffer data, ByteBuffer uv, int yl) {
        int l = uv.remaining();
        int quarter = yl / 4;
        int half = yl / 2;
        if (l == quarter) {
            // 魅族M8,長度剛好是y的四分之一浙炼,直接寫入菌仁。
            data.put(uv);
        } else if (quarter < l && l <= half) {
            // 華為榮耀,實際讀取到的長度是y的(1 / 2 - 1)
            for (int i = 0; i < l; i++) {
                byte b = uv.get();
                if (i % 2 == 0) {
                    data.put(b);
                }
            }
        } else if (l > half) {
            // 未發(fā)現(xiàn)此種情況汽煮,先預留著
            for (int i = 0; i < l; i++) {
                byte b = uv.get();
                if (i % 4 == 0) {
                    data.put(b);
                }
            }
        }
    }

    public static Mat yuv420(Image image) {
        // yuv420圖片有三個通道,按順序下來分別對應YUV
        // 轉換需要把三個通道的數(shù)據(jù)按順序合并在一個數(shù)組里棚唆,
        // 即全部Y逗物,隨后全部U,再隨后全部是V瑟俭,
        // 再由此數(shù)組生成Yuv420的Mat翎卓,
        // 之后可以利用opencv將其轉為其他格式
        Image.Plane[] plans = image.getPlanes();
        ByteBuffer y = plans[0].getBuffer();
        ByteBuffer u = plans[1].getBuffer();
        ByteBuffer v = plans[2].getBuffer();
        // 此處需要把postition移到0才能讀取
        y.position(0);
        u.position(0);
        v.position(0);
        int yl = y.remaining();
        // yuv420即4個Y對應1個U和一個V,即4:1:1的關系摆寄,長度剛好是Y的1.5倍
        ByteBuffer data = ByteBuffer.allocateDirect(yl * 3 / 2);
        // y通道直接全部插入
        data.put(y);
        copy(data, u, yl);
        copy(data, v, yl);
        // 生成Yuv420格式的Mat
        int rows = image.getHeight();
        int cols = image.getWidth();
        return new Mat(rows * 3 / 2, cols, CvType.CV_8UC1, data);
    }

    public static Mat rgb(Image image) {
        Mat yuvMat = yuv420(image);
        int rows = image.getHeight();
        int cols = image.getWidth();
        // RGB三通道失暴,保存采用CV_8UC3
        Mat rgbMat = new Mat(rows, cols, CvType.CV_8UC3);
        // 通過cv::cvtColor將yuv420轉換為rgb格式
        Imgproc.cvtColor(yuvMat, rgbMat, Imgproc.COLOR_YUV2RGB_I420);
        // Mat是jni本地對象,釋放對象是良好的習慣
        yuvMat.release();
        return rgbMat;
    }

    public static Mat gray(Image image) {
        Mat yuvMat = yuv420(image);
        int rows = image.getHeight();
        int cols = image.getWidth();
        // 灰色只有一個通道微饥,保存采用CV_8UC1
        Mat grayMat = new Mat(rows, cols, CvType.CV_8UC1);
        // 通過cv::cvtColor將yuv420轉換為灰色圖片
        Imgproc.cvtColor(yuvMat, grayMat, Imgproc.COLOR_YUV2GRAY_I420);
        yuvMat.release();
        return grayMat;
    }
}

JPEG轉Mat

實際測試Camera2也能輸出JPEG格式

import android.annotation.TargetApi;
import android.media.Image;
import android.os.Build;

import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;

import java.nio.ByteBuffer;

@TargetApi(Build.VERSION_CODES.KITKAT)
public class Jpeg {

    private static Mat jpeg(Image image) {
        Image.Plane plan = image.getPlanes()[0];
        ByteBuffer data = plan.getBuffer();
        data.position(0);
        // 從通道讀取的圖片為JPEG逗扒,并不能直接使用,
        // 將其保存在一維數(shù)組里
        return new Mat(1, data.remaining(), CvType.CV_8U, data);
    }

    public static Mat rgb(Image image) {
        Mat jpeg = jpeg(image);
        // 通過cv::imdecode將其解析為彩色圖
        Mat mat = Imgcodecs.imdecode(jpeg, Imgcodecs.CV_LOAD_IMAGE_COLOR);
        jpeg.release();
        return mat;
    }

    public static Mat gray(Image image) {
        Mat jpeg = jpeg(image);
        // 通過cv::imdecode將其解析為灰色圖
        Mat mat = Imgcodecs.imdecode(jpeg, Imgcodecs.CV_LOAD_IMAGE_GRAYSCALE);
        jpeg.release();
        return mat;
    }
}

參考:Android Camera系列3 - Image中獲得YUV數(shù)據(jù)及YUV格式理解

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末欠橘,一起剝皮案震驚了整個濱河市矩肩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌肃续,老刑警劉巖黍檩,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件叉袍,死亡現(xiàn)場離奇詭異,居然都是意外死亡刽酱,警方通過查閱死者的電腦和手機喳逛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來棵里,“玉大人润文,你說我怎么就攤上這事〉盍” “怎么了典蝌?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長头谜。 經(jīng)常有香客問我骏掀,道長,這世上最難降的妖魔是什么乔夯? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮款侵,結果婚禮上末荐,老公的妹妹穿的比我還像新娘。我一直安慰自己新锈,他們只是感情好甲脏,可當我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著妹笆,像睡著了一般块请。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上拳缠,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天墩新,我揣著相機與錄音,去河邊找鬼窟坐。 笑死海渊,一個胖子當著我的面吹牛,可吹牛的內容都是我干的哲鸳。 我是一名探鬼主播臣疑,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼徙菠!你這毒婦竟也來了讯沈?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤婿奔,失蹤者是張志新(化名)和其女友劉穎缺狠,沒想到半個月后问慎,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡儒老,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年蝴乔,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片驮樊。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡薇正,死狀恐怖,靈堂內的尸體忽然破棺而出囚衔,到底是詐尸還是另有隱情挖腰,我是刑警寧澤,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布练湿,位于F島的核電站猴仑,受9級特大地震影響,放射性物質發(fā)生泄漏肥哎。R本人自食惡果不足惜辽俗,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望篡诽。 院中可真熱鬧崖飘,春花似錦任内、人聲如沸切蟋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽达椰。三九已至翰蠢,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間啰劲,已是汗流浹背梁沧。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蝇裤,地道東北人趁尼。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像猖辫,于是被迫代替她去往敵國和親酥泞。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,914評論 2 355