yuv422轉RGB888儲存bmp檔案解析
uvc相機支援v4l2程式設計,採集格式若只支援yuv422,使用libjpeg等壓縮速度降低,直接儲存bmp點陣圖速度加快.
關於v4l2對於相機的初始化部分進行省略.
分為幾個關鍵步驟進行轉換:
1:初始化正常
2:將底層獲取與申請的記憶體存入快取進行mmap進行記憶體對映,核心空間的地址不能直接被使用者空間使用
struct buffer{ void *start; unsigned int length; }*buffers;
//mmap for buffers buffers = (struct buffer*)malloc(req.count*sizeof (*buffers));
buffers[n_buffers].length = buf.length; //map buffers[n_buffers].start = mmap(NULL,buf.length,PROT_READ |PROT_WRITE, MAP_SHARED, fd, buf.m.offset);inx
進行記憶體對映後,可以開始採集,取出快取中的取樣快取,該buffers結構體中儲存的為yuyv資料
3:對yuyv資料進行rgb888轉換
基本思路:
yuv422採集類似隔點取樣儲存格式編碼.若採集為800*600影象資料
實際在原始的資料中width的資料為800*2.height不變為600.
進行轉換時候.for(i=0;i<IMAGEHEIGHT;i++)
{
for(j=0;j<IMAGEWIDTH/2;j++)
{
y1 = *( pointer + (i*IMAGEWIDTH/2+j)*4+0); // u = *( pointer + (i*IMAGEWIDTH/2+j)*4 + 1); y2 = *( pointer + (i*IMAGEWIDTH/2+j)*4 + 2); //v = *( pointer + (i*IMAGEWIDTH/2+j)*4 + 3); v = *( pointer + (i*IMAGEWIDTH/2+j)*4 + 1); u = *( pointer + (i*IMAGEWIDTH/2+j)*4 + 3);
}
}
解析對於yuv422取樣,思路是將列中,每次取4個位元組,以4個位元組為單位
所以for(j=0;j<(width*2)/4;j++) 若取指定的位置的資料
i*(width*2)跳過該行之前的資料,j*4某一列的單位的資料
*pointer指向資料的起始地址,一個單位的資料4個位元組分別存放yuyv;
所以y1=*(pointer+i*(width*2)+j*4 + 0)又由於bmp中儲存g b分量是顛倒的
v = *(pointer+i*(width*2)+j*4 + 1) ,y2=*(pointer+i*(width*2)+j*4 + 2)
u = *(pointer+i*(width*2)+j*4 + 3);
再此基礎上再進行bgr的轉換,下面的公式進行了白平衡處理
b1 = (1.164*(y1-16)+1.159*(v-128)); g1 = (1.164*(y1-16)-0.392*(u-128)-0.813*(v-128)); r1 = (1.164*(y1-16)+2.018*(u-128));
b2 = (1.164*(y2-16)+1.159*(v-128)); g2 = (1.164*(y2-16)-0.392*(u-128)-0.813*(v-128)); r2 = (1.164*(y2-16)+2.018*(u-128));
由於rgb格式為3個位元組一個畫素,使用rgb轉換bmp時候.
unsigned char frame_buffer[width*height*3];
*(frame_buffer + (i*IMAGEWIDTH/2+j)*6 ) = (unsigned char)b1; *(frame_buffer + (i*IMAGEWIDTH/2+j)*6 + 1) = (unsigned char)g1; *(frame_buffer + (i*IMAGEWIDTH/2+j)*6 + 2) = (unsigned char)r1;
*(frame_buffer + (i*IMAGEWIDTH/2+j)*6 + 3) = (unsigned char)b2; *(frame_buffer + (i*IMAGEWIDTH/2+j)*6 + 4) = (unsigned char)g2; *(frame_buffer + (i*IMAGEWIDTH/2+j)*6 + 5) = (unsigned char)r2;
原理同上