2014-01-21 222 views
1

我在js中有YUV圖像字節數組(UINtArray),是否可以將它轉換爲RGB?或如何在畫布上繪製?Javascript將YUV轉換爲RGB

這裏是鏈接它使用webGL畫布,通過填充紋理/但我需要使用2D上下文畫布做到這一點。我知道它可能會變慢,但無論如何。 https://github.com/mbebenita/Broadway/blob/master/Player/canvas.js

var lumaSize = width * height, 
    chromaSize = lumaSize >> 2; 
webGLCanvas.YTexture.fill(buffer.subarray(0, lumaSize)); 
webGLCanvas.UTexture.fill(buffer.subarray(lumaSize, lumaSize + chromaSize)); 
webGLCanvas.VTexture.fill(buffer.subarray(lumaSize + chromaSize, lumaSize + 2 * chromaSize)); 
webGLCanvas.drawScene(); 

更新:圖像YUV字節也I420格式,因爲我看到

UPDATE2:我發現例如在C++中,我認爲會的工作,但你可以幫我將它轉化成js的?

static int getR(int y, int u, int v) 
{ 
    return clamp(y + (int) (1.402f * (v - 128))); 
} 

static int getG(int y, int u, int v) 
{ 
    return clamp(y - (int) (0.344f * (u - 128) + 0.714f * (v - 128))); 
} 

static int getB(int y, int u, int v) 
{ 
    return clamp(y + (int) (1.772f * (u - 128))); 
} 

static int getY(int r, int g, int b) 
{ 
    return (int) (0.299f * r + 0.587f * g + 0.114f * b); 
} 

static int getU(int r, int g, int b) 
{ 
    return (int) (-0.169f * r - 0.331f * g + 0.499f * b + 128); 
} 

static int getV(int r, int g, int b) 
{ 
    return (int) (0.499f * r - 0.418f * g - 0.0813f * b + 128); 
} 

static int clamp(int value) 
{ 
    return Math::Min(Math::Max(value, 0), 255); 
} 

static void ConvertI420ToRGB24(SSourcePicture *yuvImage, unsigned char *rgbData) 
{ 
    int yPadding = yuvImage->iStride[0] - yuvImage->iPicWidth; 
    int uPadding = yuvImage->iStride[1] - (yuvImage->iPicWidth/2); 
    int vPadding = yuvImage->iStride[2] - (yuvImage->iPicWidth/2); 

    int yi = 0; 
    int ui = 0; 
    int vi = 0; 
    int rgbi = 0; 
    for (int ypos = 0; ypos < yuvImage->iPicHeight; ypos++) 
    { 
     for (int xpos = 0; xpos < yuvImage->iPicWidth; xpos++) 
     { 
      int y = yuvImage->pData[0][yi] & 0xFF; 
      int u = yuvImage->pData[1][ui] & 0xFF; 
      int v = yuvImage->pData[2][vi] & 0xFF; 

      int r = getR(y, u, v); 
      int g = getG(y, u, v); 
      int b = getB(y, u, v); 

      if (BitConverter::IsLittleEndian) 
      { 
       rgbData[rgbi++] = (unsigned char) b; 
       rgbData[rgbi++] = (unsigned char) g; 
       rgbData[rgbi++] = (unsigned char) r; 
      } 
      else 
      { 
       rgbData[rgbi++] = (unsigned char) r; 
       rgbData[rgbi++] = (unsigned char) g; 
       rgbData[rgbi++] = (unsigned char) b; 
      } 

      yi++; 
      if (xpos % 2 == 1) 
      { 
       ui++; 
       vi++; 
      } 
     } 

     yi += yPadding; 

     if (ypos % 2 == 0) 
     { 
      ui -= (yuvImage->iPicWidth/2); 
      vi -= (yuvImage->iPicWidth/2); 
     } 
     else 
     { 
      ui += uPadding; 
      vi += vPadding; 
     } 
    } 
} 
+1

在JS中實現它時面臨的具體問題是什麼?你可以發佈你迄今爲止的任何嘗試嗎? – z33m

+0

這裏是我嘗試過的所有convertion函數,http://jsfiddle.net/QsL6b/我所有我得到的或空的畫布或圖像不繪製,如果我將它轉換爲基礎並在圖像中設置src。謝謝 –

回答

0

我不知道很多關於你的話題,我會嘗試更多的後來搞清楚,但我發現了兩個鏈接的Userful可以幫助。

應該告訴你如何轉換YUV圖像RGB(這是在Java中,我將嘗試轉換這個版本): http://www.41post.com/3470/programming/android-retrieving-the-camera-preview-as-a-pixel-array

應該告訴你如何繪製RGB圖像: getPixel from HTML Canvas?

+0

感謝@CubanAzcuy的迴應。是的,我嘗試了一些轉換的例子,但要運氣好畫,也許我會錯過一些東西。要繪製然後rgb字節不是問題,因爲我也可以將其轉換爲base64並繪製爲圖像。希望你能成功兌換。 –

1

這裏是將yuv轉換成rgb的JS代碼。

function yuv2rgb(y,u,v){ 
    y=parseInt(y); 
    u=parseInt(u); 
    v=parseInt(v); 
    r=clamp(Math.floor(y+1.4075*(v-128)),0,255); 
    g=clamp(Math.floor(y-0.3455*(u-128)-(0.7169*(v-128))),0,255); 
    b=clamp(Math.floor(y+1.7790*(u-128)),0,255); 
    return({r:r,g:g,b:b}); 
} 

function clamp(n,low,high){ 
    if(n<low){return(low);} 
    if(n>high){return(high);} 
} 

可以使用VAR imgData = ctx.createImageData(canvas.width,canvas.height)來創建一個 「從劃痕」 像素陣列可以喂RGB值到。

後你建立你的像素陣列,您可以在繪製與ctx.putImageData(imgData)畫布

+0

對不起,但它不工作:(我認爲,因爲我不需要簡單的YUV,但IYUV –

+0

你忘了鉗「b」字段。 – peterh

0

假設你的YUV陣列爲每像素3個字節你可以複製和轉換緩衝器以帆布這樣的:

var width = 800, /// the dimension of the YUV buffer 
    height = 600, 
    canvas = document.getElementById('myCanvasId'), 
    ctx = canvas.getContext('2d'), 

    idata,   /// image data for canvas 
    buffer,   /// the buffer itself 
    len,   /// cached length of buffer 
    yuvBuffer = ... /// your YUV buffer here 

    i = 0,   /// counter for canvas buffer 
    p = 0,   /// counter for YUV buffer 
    y, u, v;  /// cache the YUV bytes 

/// make sure canvas is of same size as YUV image: 
canvas.width = width; 
canvas.height = height; 

/// create an image buffer for canvas to copy to 
idata = ctx.createImageData(width, height); 
buffer = idata.data; 
len = buffer.length; 

現在我們可以遍歷緩衝器和轉換,因爲我們去:

/// iterate buffers 
for(; i < len; i += 4, p += 3) { 

    /// get YUV bytes 
    y = yuvBuffer[p]; 
    u = yuvBuffer[p + 1] - 128; 
    v = yuvBuffer[p + 2] - 128; 

    /// convert to RGB and copy to canvas buffer 
    buffer[i]  = y + v * 1.402 + 0.5; 
    buffer[i + 1] = y - u * 0.344 - v * 0.714 + 0.5; 
    buffer[i + 2] = y + u * 1.772 + 0.5; 
} 

/// update canvas with converted buffer 
ctx.putImageData(idata, 0, 0); 

我們不需要夾緊值作爲緩衝畫布是默認Uint8ClampedArray,所以瀏覽器將爲我們做好夾持工作併爲我們節省幾個CPU週期。舍入時加0.5。

如果您的YUV緩衝區是原始4:2:0格式,那麼它會比較乏味,因爲您必須考慮交錯等因素。但是對於YUV分量值本身,您可以使用上面的轉換方法來獲取RGB。

希望這會有所幫助。

+0

反正我得到白色帆布 –

+0

@TomWhite是什麼格式是YUV緩衝區?它是「標準化」到8:8:8還是數據原始4:2:0?有關如何處理420個原始緩衝區的更多詳細信息,請參閱此文章:https://en.wikipedia.org/wiki/YUV#Y.27UV420p_.28and_Y.27V12_or_YV12.29_to_RGB888_conversion – K3N

+0

我已將yuv圖像的緩衝區編碼爲base64,此處它http://jsfiddle.net/4FWF9/ –