OpenCV中将RGB数组在内存中压缩成JPEG文件

环境

  1. jpeg库: jpegsr9a  下载地址:http://www.ijg.org/
  2. 编译环境: vs2015
  3. 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

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 = "<

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);


 

你可能感兴趣的:(OpenCV中将RGB数组在内存中压缩成JPEG文件)