作者: Sam (甄峰) sam_code@hotmail.com
USB Camera在通过V4L2接口获取Camera数据时,有多种图像格式可选择。但最常用的却是YUV和MJPEG.
又因为YUV图片所占空间大,在超过640x480情况下,会超过USB数据传输带宽。
所以只能使用MJPEG.
现在就谈谈MJPEG相关内容。
1. 视频压缩格式:
1.1:JPEG (Joint Photographic Experts Group)压缩技术是所有图像压缩技术的基础。
它适合静态图像的压缩,直接处理整幅画面,压缩倍数为20-80倍,分辨率没有选择的余地。在传输中,必须要等整个压缩档传输完成才可以解压,这就造成传输时间较长。它是帧内压缩。
1.2. MJPEG(Motion JPEG):
在JPEG基础上发展起来的动态图像压缩技术,也是帧内压缩,只单独的对某一帧进行压缩,而基本不考虑视频流中不同帧之间的变化。其压缩后的图像还可以任意剪切。
Motion JPEG, 即动态JPEG.
按一定帧数使用JPEG算法压缩视频信号,完成动态视频的压缩。MJPEG图像流的单元就是一帧一帧的JPEG画片。
因为每帧可以任意存取,所以MJPEG常用于视频编辑系统。
1.3. MPEG:
其实是一个标准。
其中MPEG-4. 它会使用帧间数据。压缩比很高。应用广泛。
2. libjpeg-turbo:
jpeg, Mjpeg的压缩和解压,比较耗费CPU。
所以就有了libjpeg-turbo库,它可以更快的压缩和解压jpeg数据。
因为是帧内压缩,所以可以对JPEG数据进行各种处理,如放大/缩小,翻转,剪切,镜像等。
2.1: libjpeg-turbo 对JPEG的压缩和解压:
libjpeg-turbo提供压缩(Compress)和解压(Decompress)接口。
同时,它还有个概念----Transform.
2.1.1: 压缩:
给定RGB data. 把它压缩成指定jpeg文件。
A. 打开一个压缩实例:
tjhandle tjInitCompress(void)
B. 把给定pixel,w,h pitch等信息的数据,压缩成jpeg(给定sample,质量)数据。
int tjCompress2(tjhandle handle, const unsigned char
*srcBuf,
int width, int pitch, int height, int
pixelFormat,
unsigned char **jpegBuf, unsigned long
*jpegSize,
int jpegSubsamp, int jpegQual, int flags)
C. 销毁实例:
int tjDestroy(tjhandle handle)
2.1.2:解压:
把给定的JPEG数据,解压成RGB数据:
这个过程,只是简单的解压,或者仅仅是图片大小变化。
A. 打开一个解码实例
tjInstance = tjInitDecompress();
B. 通过读取到的jpeg数据,来分析文件头,获取图像信息(长宽,sample, colour信息等)
int tjDecompressHeader3(tjhandle handle,
const unsigned char
*jpegBuf,
unsigned long jpegSize, int
*width,
int *height, int
*jpegSubsamp,
int *jpegColorspace)
jpegBuf是jpeg数据。
C. 解压到指定格式,指定长宽数据:
int tjDecompress2(tjhandle handle, const unsigned char
*jpegBuf,
unsigned long jpegSize,
unsigned char *dstBuf,
int width, int pitch, int
height, int pixelFormat,
int flags)
width, height: 目标图像长宽。
pixelFormat: 目标图像格式, enum TJPF
中定义,如RGBX。
此时,dstBuf中的内容,就是解压过的,指定大小,深度,和图像格式的图片数据了。
如果指定为RGBX,则直接存文件即为BMP文件。
D. 销毁实例:
int tjDestroy(tjhandle handle)
2.1.3:Transform:
Transform是干什么呢,Sam觉得是因为要实质修改JPEG数据,重新排列。
比如剪切,翻转,镜像。这些动作叫做Transform.
A. 打开一个transform实例:
tjhandle tjInitTransform(void)
B. Transform转换:
tjtransform xform;
//指定transform的参数,如裁剪区域
想要裁剪:
xform.r.x = iX; //左上角位置
xform.r.y = iY;
xform.r.h , xform.r.w //区域高度。
xform.options |= TJXOPT_CROP;
//指定要剪切。
int tjTransform(tjhandle handle, const unsigned char
*jpegBuf,
unsigned long jpegSize, int n,
unsigned char **dstBufs, unsigned long
*dstSizes,
tjtransform *t, int flags)
dstBufs中保存这transform后的数据。
C. 可选: 获取新的jpeg数据信息:
DLLEXPORT int tjDecompressHeader3(tjhandle handle,
const unsigned char
*jpegBuf,
unsigned long jpegSize, int
*width,
int *height, int
*jpegSubsamp,
int *jpegColorspace)
D. 后续可以随意处理jpeg数据了。如解压。
E. 销毁:
int tjDestroy(tjhandle handle)
2.2: libjpeg-turbo对图像文件的处理:
unsigned char *tjLoadImage(const char *filename, int
*width,
int align, int *height, int *pixelFormat,
int flags)
int tjSaveImage(const char *filename, unsigned char
*buffer,
int width, int pitch, int height, int
pixelFormat,
int flags)
2.3:获取放大缩小factor:
libjpet-turbo并不可以随意比例放大缩小,而是指定了一系列(16个)比例系数。
可以先获取这个列表:
scalingFactors =
tjGetScalingFactors(&numScalingFactors);
if(scalingFactors == NULL)
{
printf("\nGet Scaling Factor Error.\n");
return -1;
}
printf("\nThere are [%d] ScalingFactors\n",
numScalingFactors);
for(int i = 0; i < numScalingFactors; i++)
{
printf("\t Numerator/Denominator is:[%d/%d]\n",
scalingFactors[i].num, scalingFactors[i].denom);
}
此时就可以得到turbo-jpeg给定的Scaling Factor.