關於c#呼叫usb攝像頭的回撥碼流解碼問題
阿新 • • 發佈:2019-01-09
最近,想用c#呼叫電腦攝像頭,參考了“赤色火焰”的部落格http://www.cnblogs.com/mgod/archive/2008/06/18/1224351.html,但對碼流解碼方面的介紹沒有,上網搜也沒有找到。於是,開始分析FrameCallBack中的VideoData的碼流結構發現其解析度是640*480,排列方式是YCbYCr,一行的排列是Y0CbY1CrY2CbY3CrY4CbY5Cr...,採用從左到右 從上到下的排列方式。其中YCbYCr表示左右相鄰的兩個畫素,這兩個畫素的Y值不同,共用Cb和Cr,例如:Y0CbY1Cr解碼是應為:Y0CbCr、Y1CbCr。
根據,YCbYCr轉RGB公式:
r = 1.164 * (y - 16) + 1.596 * (cr - 128);
g = 1.164 * (y - 16) - 0.391 * (cb - 128) - 0.813 * (cr - 128);
b = 1.164 * (y - 16) + 2.018 * (cb - 128);
編寫解碼函式,再呼叫解碼函式
private double[] ycbcrToRGB(byte y, byte cb, byte cr) { double[] rgb = new double[3]; rgb[0] = 1.164 * (y - 16) + 1.596 * (cr - 128); rgb[1] = 1.164 * (y - 16) - 0.391 * (cb - 128) - 0.813 * (cr - 128); rgb[2] = 1.164 * (y - 16) + 2.018 * (cb - 128); rgb[0] = Math.Min(Math.Max(0, rgb[0]), 255); rgb[1] = Math.Min(Math.Max(0, rgb[1]), 255); rgb[2] = Math.Min(Math.Max(0, rgb[2]), 255); return rgb; }
protected unsafe void wc_RecievedFrame(byte[] data) { int w = 320, h = 480; Bitmap bi = new Bitmap(w * 2, h); BitmapData bData = bi.LockBits(new Rectangle(0, 0, w * 2, h), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb); for (int i = 0; i < w; i++) { for (int j = 0; j < h; j++) { byte* pRef = (byte*)bData.Scan0 + bData.Stride * j + i * 2 * 3; int index = i * 4 + j * w * 4; byte Y0 = data[index]; byte cb = data[index + 1]; byte cr = data[index + 3]; byte Y1 = data[index + 2]; double[] rgb0 = ycbcrToRGB(Y0, cb, cr); double[] rgb1 = ycbcrToRGB(Y1, cb, cr); pRef[0] = (byte)rgb0[2]; pRef[1] = (byte)rgb0[1]; pRef[2] = (byte)rgb0[0]; pRef[3] = (byte)rgb1[2]; pRef[4] = (byte)rgb1[1]; pRef[5] = (byte)rgb1[0]; } } bi.UnlockBits(bData); pictureBox1.Image = bi; }