环境
- jpeg库: jpegsr9a 下载地址:http://www.ijg.org/
- 编译环境: vs2015
- Opencv 3.4.2
一、RGB数组来自BMP文件,直接输出在文件系统上
1.1 代码
void bmptojpg24(const char *strSourceFileName, constchar *strDestFileName)
{
BITMAPFILEHEADER bfh; // bmp文件头
BITMAPINFOHEADER bih; // bmp头信息
RGBQUAD rq[256]; // 调色板
int i=0,j=0;
int nAdjust;// 用于字节对齐
int nAdjust24;// 用于字节对齐
BYTE *data=NULL;//new BYTE[bih.biWidth*bih.biHeight];
BYTE *pData24= NULL;//newBYTE[bih.biWidth*bih.biHeight];
int nComponent= 0;
// 打开图像文件
FILE *f= fopen(strSourceFileName,"rb");
if (f==NULL)
{
printf("Open file error!\n");
return;
}
// 读取文件头
fread(&bfh,sizeof(bfh),1,f);
// 读取图像信息
fread(&bih,sizeof(bih),1,f);
// 8位字节对齐
nAdjust = bih.biWidth%4;
if (nAdjust)nAdjust = 4-nAdjust;
// 24位字节对齐
nAdjust24 = bih.biWidth*3%4;
if (nAdjust24)nAdjust24 = 4-nAdjust24;
switch (bih.biBitCount)
{
case 8:
if (bfh.bfOffBits-1024<54)
{
fclose(f);
return;
}
data= new BYTE[(bih.biWidth+nAdjust)*bih.biHeight];
pData24 = new BYTE[(bih.biWidth*3+nAdjust24)*bih.biHeight];
// 定位调色板,并读取调色板
fseek(f,bfh.bfOffBits-1024,SEEK_SET);
fread(rq,sizeof(RGBQUAD),256,f);
// 读取位图
fread(data,bih.biWidth*bih.biHeight,1,f);
fclose(f);
nComponent = 3;
for (j=0;j<bih.biHeight;j++) {
for (i=0;i<bih.biWidth;i++)
{
pData24[j*(bih.biWidth*3+nAdjust24)+i*3] = rq[data[j*(bih.biWidth+nAdjust)+i]].rgbRed;
pData24[j*(bih.biWidth*3+nAdjust24)+i*3+1] = rq[data[j*(bih.biWidth+nAdjust)+i]].rgbGreen;
pData24[j*(bih.biWidth*3+nAdjust24)+i*3+2] = rq[data[j*(bih.biWidth+nAdjust)+i]].rgbBlue;
}
}
break;
case 24:
{
data= new BYTE[(bih.biWidth*3+nAdjust24)*bih.biHeight];
pData24 = new BYTE[(bih.biWidth*3+nAdjust24)*bih.biHeight];
fseek(f,bfh.bfOffBits,SEEK_SET);
fread(data,(bih.biWidth*3+nAdjust24)*bih.biHeight,1,f);
fclose(f);
for (j=0;j<bih.biHeight;j++){
for (i = 0;i<bih.biWidth;i++)
{
pData24[j*(bih.biWidth*3+nAdjust24)+i*3]= data[j*(bih.biWidth*3+nAdjust24)+i*3+2];
pData24[j*(bih.biWidth*3+nAdjust24)+i*3+1]= data[j*(bih.biWidth*3+nAdjust24)+i*3+1];
pData24[j*(bih.biWidth*3+nAdjust24)+i*3+2]= data[j*(bih.biWidth*3+nAdjust24)+i*3];
}
}
nComponent = 3;
break;
}
default:
fclose(f);
return;
}
// 以上图像读取完毕
cout<<"nAdjust24 = "<<nAdjust24<<endl;
if(IsMemory)
{
IMGSTRUCT BMP;
BMP.Img= pData24;
BMP.height= bih.biHeight;
BMP.width= bih.biWidth;
BMP.nChannel= nComponent;
//cout<<"pData24 is "<<strlen(pData24)<<endl;
unsigned char *lpDstBuf = new BYTE[(bih.biWidth*3+nAdjust24)*bih.biHeight];
memset(lpDstBuf,0,(bih.biWidth*3+nAdjust24)*bih.biHeight);
unsigned long dwDstBufSize ;
int quality= 60;
//cout<<"lpDstBuf is"<<strlen(lpDstBuf)<<endl;
WriteJPEGtoMemory(&BMP,lpDstBuf,dwDstBufSize,quality);
f=fopen(strDestFileName,"wb");
if (f==NULL)
{
delete [] data;
//delete [] pDataConv;
return;
}
fwrite(lpDstBuf,dwDstBufSize,1,f);
fclose(f);
delete [] data;
delete [] pData24;
delete [] lpDstBuf;
}
else
{
struct jpeg_compress_structjcs;
struct jpeg_error_mgrjem;
jcs.err= jpeg_std_error(&jem);
jpeg_create_compress(&jcs);
f=fopen(strDestFileName,"wb");
if (f==NULL)
{
delete [] data;
//delete [] pDataConv;
return;
}
jpeg_stdio_dest(&jcs, f);
jcs.image_width= bih.biWidth; // 为图的宽和高,单位为像素
jcs.image_height= bih.biHeight;
jcs.input_components= nComponent; // 1,表示灰度图,如果是彩色位图,则为
if (nComponent==1)
jcs.in_color_space = JCS_GRAYSCALE;//JCS_GRAYSCALE表示灰度图,JCS_RGB表示彩色图像
else
jcs.in_color_space = JCS_RGB;
jpeg_set_defaults(&jcs);
jpeg_set_quality(&jcs, 60, true);
jpeg_start_compress(&jcs, TRUE);
JSAMPROW row_pointer[1]; // 一行位图
int row_stride; // 每一行的字节数
row_stride = jcs.image_width*nComponent; // 如果不是索引图,此处需要乘以
// 对每一行进行压缩
while (jcs.next_scanline < jcs.image_height) {
row_pointer[0] = & pData24[(jcs.image_height-jcs.next_scanline-1)* (row_stride+nAdjust24)];
jpeg_write_scanlines(&jcs, row_pointer,1);
}
jpeg_finish_compress(&jcs);
jpeg_destroy_compress(&jcs);
fclose(f);
delete [] data;
delete [] pData24;
}
}
1.2 注意
代码中红色标记的代码:
由于BMP图片格式的原因,读入的RGB颜色顺序是BGR形式的,需要调整为RGB顺序:
pData24[j*(bih.biWidth*3+nAdjust24)+i*3]= data[j*(bih.biWidth*3+nAdjust24)+i*3+2];
pData24[j*(bih.biWidth*3+nAdjust24)+i*3+1]= data[j*(bih.biWidth*3+nAdjust24)+i*3+1];
pData24[j*(bih.biWidth*3+nAdjust24)+i*3+2]= data[j*(bih.biWidth*3+nAdjust24)+i*3];
由于BMP格式中,图片原点是存放在右下角的,所以需要将它颠倒为正序。
row_pointer[0] = & pData24[(jcs.image_height-jcs.next_scanline-1) *(row_stride+nAdjust24)];
二、RGB数组来自opencv,直接输出在内存
2.1 代码
//直接将bayer格式的图片转化为RGB顺序
cvCvtColor(param.img, dst,CV_BayerBG2RGB);
//申请输出空间并且初始化
unsigned char * out = new unsignedchar[size.width*size.height*3];
memset(out,0,size.width*size.height*3);
//JPEG长度
unsigned long dwDstBufSize ;
//图像质量
int quality = 95;
// quality = 100,1024*768的RGB图片压缩后是500KB左右
// quality = 95,1024*768的RGB图片压缩后是200KB左右
IMGSTRUCT BMP;
BMP.Img = (unsigned char*)dst->imageData;
BMP.height =size.height;
BMP.width = size.width;
BMP.nChannel = 3;
//out中存放是压缩以后jpeg文件的起始地址,dwDstBufSize是文件的长度
WriteJPEGtoMemory(&BMP,out,dwDstBufSize,quality);
// 将pbuf中图像数据JPEG编码到内存中, 与WriteJPEG的主要区别:用jpeg_mem_dest()替换jpeg_stdio_dest()
bool WriteJPEGtoMemory(IMGSTRUCT *pbuf,unsigned char *lpDstBuf, unsignedlong & dwDstBufSize,int quality)
{
if (pbuf== NULL) {
// MessageBox(NULL,"WriteJPEGtoMemory() -- 传入的图像结构体指针为NULL!", "错误", MB_ICONHAND);
return FALSE;
}
if (pbuf->height <= 0 || pbuf->width <= 0 || pbuf->Img <= NULL){
//MessageBox(NULL, "WriteJPEGtoMemory()-- 图像参数有误!", "错误", MB_ICONHAND);
return FALSE;
}
int nbits;
//定义压缩信息
struct jpeg_compress_structcinfo;
//定义错误信息
struct my_error_mgrjerr;
//为JPEG文件压缩对象分配内存并对其初始化
cinfo.err= jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
if (setjmp(jerr.setjmp_buffer)){
jpeg_destroy_compress(&cinfo);
return FALSE;
}
jpeg_create_compress(&cinfo);
//确定要用于输出压缩的jpeg的数据空间
jpeg_mem_dest(&cinfo, &lpDstBuf,&dwDstBufSize);
//设置压缩参数
cinfo.image_width = pbuf->width;
cinfo.image_height= pbuf->height;
if (pbuf->nChannel == 1) {
cinfo.input_components = nbits= 1;
cinfo.in_color_space = JCS_GRAYSCALE;
}
else if(pbuf->nChannel== 3) {
cinfo.input_components = nbits= 3;
cinfo.in_color_space = JCS_RGB;
}
else {
//MessageBox(NULL,"WriteJPEGFile() -- 传入图像结构体颜色通道不正确!", "错误", MB_ICONHAND);
jpeg_destroy_compress(&cinfo);
return FALSE;
}
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, quality,TRUE );
//开始压缩
jpeg_start_compress(&cinfo, TRUE);
//JSAMPROW outRow[1];
BYTE * outRow;
int i= 0;
//unsigned char *outRow;
while (cinfo.next_scanline < cinfo.image_height) {
outRow = pbuf->Img +(cinfo.next_scanline * pbuf->width * nbits);
(void)jpeg_write_scanlines(&cinfo, &outRow,1);
i++;
//cout<<"i = "<<i<<endl;
}
cout<<"Memory~"<<endl;
//完成压缩
jpeg_finish_compress(&cinfo);
//释放压缩对象
jpeg_destroy_compress(&cinfo);
outRow = NULL;
return TRUE;
}
2.2 说明
由于这里是直接调用opencv的函数,将输入的RGB数组顺序调整正确了。所以在压缩的时候,直接使用
outRow = pbuf->Img + (cinfo.next_scanline* pbuf->width * nbits);
不用在调整顺序了。
在内存中取出这张的图片的时候,可以直接保存成文件。代码如下:
f=fopen(strDestFileName,"wb");
if (f==NULL)
{
delete [] data;
//delete [] pDataConv;
return;
}
fwrite(out,dwDstBufSize,1,f);
fclose(f);