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;
原理同上