Android用攝像頭的那點破事

上次講的是攝像頭的初始化,若是以爲這麼就萬事OK的話,那就大錯特錯了。接下來的東西讓人感到更加頭痛。vim

在個人這個應用裏,不須要把拍下來的圖片存儲,只須要把預覽的圖片數據處理一下就好,很天然的我只是用了onPreviewFrame調用,考慮處理傳遞進來的data數據流就是了。函數

網上不少帖子都說,而後用BitmapFactory的decodeByteArray()函數來解析圖片就好了,我試了一下,發現這真是徹頭徹尾的謊話,data字節流默認是YCbCr_420_SP(雖然能夠改,但其餘的格式未必兼容),decodeByteArray()壓根兒不認!SDK2.2以後,彷佛提供了一個YuvImage的類來轉一下(那Google一開始提供這個藉口是作什麼的?),難道就要把老機給拋棄了麼??萬萬不能啊(窮人最理解窮人們了)!post

好在這個世界老是不缺乏好人和牛人的,有人提供了這麼一段轉換的代碼:
學習

1this

2spa

3code

4orm

5圖片

6get

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

static public void decodeYUV420SP(int[] rgb, byte[] yuv420sp, int width, int height) {

    final int frameSize = width * height;

 

    for (int j = 0, yp = 0; j < height; j++) {

        int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;

        for (int i = 0; i < width; i++, yp++) {

            int 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;

            }

 

            int y1192 = 1192 * y;

            int r = (y1192 + 1634 * v);

            int g = (y1192 - 833 * v - 400 * u);

            int 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[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);

        }

    }

}

我不是很清楚這裏面的原理,可是它能在我這裏工做,暫時能夠了……而後你才能夠吧處理完的rgb[]傳給decodeByteArray()。

順便好心的把使用SDK2.2以後的也貼上吧,萬一有用呢……

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

public void onPreviewFrame(byte[] data, Camera arg1) {

    FileOutputStream outStream = null;

    try {

        YuvImage yuvimage = new YuvImage(data,ImageFormat.NV21,arg1.getParameters().getPreviewSize().width,arg1.getParameters().getPreviewSize().height,null);

        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        yuvimage.compressToJpeg(new Rect(0,0,arg1.getParameters().getPreviewSize().width,arg1.getParameters().getPreviewSize().height), 80, baos);

 

        outStream = new FileOutputStream(String.format("/sdcard/%d.jpg", System.currentTimeMillis()));        

        outStream.write(baos.toByteArray());

        outStream.close();

 

        Log.d(TAG, "onPreviewFrame - wrote bytes: " + data.length);

    } catch (FileNotFoundException e) {

        e.printStackTrace();

    } catch (IOException e) {

        e.printStackTrace();

    } finally {

    }

    Preview.this.invalidate();

}

哦,獲得的圖像旋轉了90°(彷佛有的機型設置一下setRotation(90)能夠搞定,但仍是那句話,不通用啊,何況這個是2.1以後的API)。手動轉一下吧……

1

2

3

4

5

6

Matrix matrix = new Matrix();

matrix.postRotate(90);

// 這裏的rgb就是剛剛轉換處理的東東

Bitmap bmp = Bitmap.createBitmap(rgb, 0, w, w, h, Bitmap.Config.ARGB_4444);

Bitmap nbmp = Bitmap.createBitmap(bmp,

         0, 0, bmp.getWidth(),  bmp.getHeight(), matrix, true);

終於正常了~~~

考慮到須要作識別,天然得先把它轉成灰度圖像,經典心理公式Gray = R*0.299 + G*0.587 + B*0.114出場了,可是手機的計算速度不那麼快,這樣的浮點運算仍是儘可能避免吧~ 因而考慮Gray = (R*299 + G*587 + B*114 + 500) / 1000或者Gray = (R*30 + G*59 + B*11 + 50) / 100。可是除法老是仍是不夠快,用移位吧……Gray = (R*19595 + G*38469 + B*7472) >> 16,稍微小一點,用Gray = (R*38 + G*75 + B*15) >> 7也足夠了。

通過一番努力學習,把寫就的代碼興致勃勃的在手機上跑了一下,雖然不夠快結果出來了,想一想也是大負荷運算啊,自我安慰客戶應該能夠有這樣的耐心吧。

就在這個時候,我忽然想起一件很重要的事情!
我須要的是灰度圖,也就是亮度風量,而最開始的YUV,不就是亮度色度飽和度麼?!那麼Y分類不就是我須要的灰度值嗎!!我在作什麼,辛辛苦苦轉成RGB,再轉成亮度,吃飽了撐着不是。想到這裏我馬上用頭撞牆九九一百八十一次,一悼念我那白白死去的腦細胞的在天之靈。馬上重寫,刪除大量代碼,快多了,效果也好~~ 鄙視一下兩小時前的本身!




static public void decodeYUV420SP(int[] rgb, byte[] yuv420sp, int width, int height) {

    final int frameSize = width * height;    

    for (int j = 0, yp = 0; j < height; j++) {

    int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;

    for (int i = 0; i < width; i++, yp++) {

    int 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;

    }

   

    int y1192 = 1192 * y;

    int r = (y1192 + 1634 * v);

    int g = (y1192 - 833 * v - 400 * u);

    int 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[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);

    }

    }

   }

相關文章
相關標籤/搜索