【问题标题】:Compressing IplImage to JPEG using libjpeg in OpenCV在 OpenCV 中使用 libjpeg 将 IplImage 压缩为 JPEG
【发布时间】:2010-11-29 10:14:57
【问题描述】:

所以我有这个问题。 我有一个 IplImage,我想将其压缩为 JPEG 并对其进行处理。我使用 libjpeg。 我找到了很多“通读示例和文档”的答案,并做到了。并为此成功编写了一个函数。

FILE* convert2jpeg(IplImage* frame) 
{
FILE* outstream = NULL;
outstream=malloc(frame->imageSize*frame->nChannels*sizeof(char))

unsigned char *outdata = (uchar *) frame->imageData;
struct jpeg_error_mgr jerr;
struct jpeg_compress_struct cinfo;
int row_stride;
JSAMPROW row_ptr[1];

jpeg_create_compress(&cinfo);
jpeg_stdio_dest(&cinfo, outstream);

cinfo.image_width = frame->width;
cinfo.image_height = frame->height;
cinfo.input_components = frame->nChannels;
cinfo.in_color_space = JCS_RGB;

jpeg_set_defaults(&cinfo);
jpeg_start_compress(&cinfo, TRUE);
row_stride = frame->width * frame->nChannels;

while (cinfo.next_scanline < cinfo.image_height) {
    row_ptr[0] = &outdata[cinfo.next_scanline * row_stride];
    jpeg_write_scanlines(&cinfo, row_ptr, 1);
}

jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);

return outstream;
}

现在这个函数直接来自示例(分配内存的部分除外,但我需要它,因为我没有写入文件),但它仍然不起作用。 它死在 jpeg_start_compress(&cinfo, TRUE); 部分?

有人可以帮忙吗?

【问题讨论】:

    标签: compression opencv jpeg libjpeg


    【解决方案1】:

    我已经能够使用他们网站上提供的最新 jpeglib 找到解决方案。 新方法:jpeg_mem_dest(&cinfo, outbuffer, outlen);

    bool ipl2jpeg(IplImage *frame, unsigned char **outbuffer, long unsigned int *outlen) {
    unsigned char *outdata = (uchar *) frame->imageData;
    struct jpeg_compress_struct cinfo = {0};
    struct jpeg_error_mgr jerr;
    JSAMPROW row_ptr[1];
    int row_stride;
    
    *outbuffer = NULL;
    *outlen = 0;
    
    cinfo.err = jpeg_std_error(&jerr);
    jpeg_create_compress(&cinfo);
    jpeg_mem_dest(&cinfo, outbuffer, outlen);
    
    cinfo.image_width = frame->width;
    cinfo.image_height = frame->height;
    cinfo.input_components = frame->nChannels;
    cinfo.in_color_space = JCS_RGB;
    
    jpeg_set_defaults(&cinfo);
    jpeg_start_compress(&cinfo, TRUE);
    row_stride = frame->width * frame->nChannels;
    
    while (cinfo.next_scanline < cinfo.image_height) {
        row_ptr[0] = &outdata[cinfo.next_scanline * row_stride];
        jpeg_write_scanlines(&cinfo, row_ptr, 1);
    }
    
    jpeg_finish_compress(&cinfo);
    jpeg_destroy_compress(&cinfo);
    
    return true;
    
    }
    

    【讨论】:

      【解决方案2】:

      我使用下面的内存到内存压缩代码让它工作。

      #include <stdio.h>
      #include "jpeg/jpeglib.h"
      
          /*
      This a custom destination manager for jpeglib that
      enables the use of memory to memory compression.
      
      See IJG documentation for details.
      */
      typedef struct {
      struct jpeg_destination_mgr pub; /* base class */
      JOCTET* buffer; /* buffer start address */
      int bufsize; /* size of buffer */
      size_t datasize; /* final size of compressed data */
      int* outsize; /* user pointer to datasize */
      int errcount; /* counts up write errors due to
      buffer overruns */
      } memory_destination_mgr;
      
      typedef memory_destination_mgr* mem_dest_ptr;
      
      /* ------------------------------------------------------------- */
      /* MEMORY DESTINATION INTERFACE METHODS */
      /* ------------------------------------------------------------- */
      
      
      /* This function is called by the library before any data gets written */
      METHODDEF(void)
      init_destination (j_compress_ptr cinfo)
      {
      mem_dest_ptr dest = (mem_dest_ptr)cinfo->dest;
      
      dest->pub.next_output_byte = dest->buffer; /* set destination buffer */
      dest->pub.free_in_buffer = dest->bufsize; /* input buffer size */
      dest->datasize = 0; /* reset output size */
      dest->errcount = 0; /* reset error count */
      }
      
      /* This function is called by the library if the buffer fills up
      
      I just reset destination pointer and buffer size here.
      Note that this behavior, while preventing seg faults
      will lead to invalid output streams as data is over-
      written.
      */
      METHODDEF(boolean)
      empty_output_buffer (j_compress_ptr cinfo)
      {
      mem_dest_ptr dest = (mem_dest_ptr)cinfo->dest;
      dest->pub.next_output_byte = dest->buffer;
      dest->pub.free_in_buffer = dest->bufsize;
      ++dest->errcount; /* need to increase error count */
      
      return TRUE;
      }
      
      /* Usually the library wants to flush output here.
      
      I will calculate output buffer size here.
      Note that results become incorrect, once
      empty_output_buffer was called.
      This situation is notified by errcount.
      */
      METHODDEF(void)
      term_destination (j_compress_ptr cinfo)
      {
      mem_dest_ptr dest = (mem_dest_ptr)cinfo->dest;
      dest->datasize = dest->bufsize - dest->pub.free_in_buffer;
      if (dest->outsize) *dest->outsize += (int)dest->datasize;
      }
      
      /* Override the default destination manager initialization
      provided by jpeglib. Since we want to use memory-to-memory
      compression, we need to use our own destination manager.
      */
      GLOBAL(void)
      jpeg_memory_dest (j_compress_ptr cinfo, JOCTET* buffer, int bufsize, int* outsize)
      {
      mem_dest_ptr dest;
      
      /* first call for this instance - need to setup */
      if (cinfo->dest == 0) {
      cinfo->dest = (struct jpeg_destination_mgr *)
      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
      sizeof (memory_destination_mgr));
      }
      
      dest = (mem_dest_ptr) cinfo->dest;
      dest->bufsize = bufsize;
      dest->buffer = buffer;
      dest->outsize = outsize;
      /* set method callbacks */
      dest->pub.init_destination = init_destination;
      dest->pub.empty_output_buffer = empty_output_buffer;
      dest->pub.term_destination = term_destination;
      }
      
      /* ------------------------------------------------------------- */
      /* MEMORY SOURCE INTERFACE METHODS */
      /* ------------------------------------------------------------- */
      
      /* Called before data is read */
      METHODDEF(void)
      init_source (j_decompress_ptr dinfo)
      {
      /* nothing to do here, really. I mean. I'm not lazy or something, but...
      we're actually through here. */
      }
      
      /* Called if the decoder wants some bytes that we cannot provide... */
      METHODDEF(boolean)
      fill_input_buffer (j_decompress_ptr dinfo)
      {
      /* we can't do anything about this. This might happen if the provided
      buffer is either invalid with regards to its content or just a to
      small bufsize has been given. */
      
      /* fail. */
      return FALSE;
      }
      
      /* From IJG docs: "it's not clear that being smart is worth much trouble"
      So I save myself some trouble by ignoring this bit.
      */
      METHODDEF(void)
      skip_input_data (j_decompress_ptr dinfo, INT32 num_bytes)
      {
      /* There might be more data to skip than available in buffer.
      This clearly is an error, so screw this mess. */
      if ((size_t)num_bytes > dinfo->src->bytes_in_buffer) {
      dinfo->src->next_input_byte = 0; /* no buffer byte */
      dinfo->src->bytes_in_buffer = 0; /* no input left */
      } else {
      dinfo->src->next_input_byte += num_bytes;
      dinfo->src->bytes_in_buffer -= num_bytes;
      }
      }
      
      /* Finished with decompression */
      METHODDEF(void)
      term_source (j_decompress_ptr dinfo)
      {
      /* Again. Absolute laziness. Nothing to do here. Boring. */
      }
      
      GLOBAL(void)
      jpeg_memory_src (j_decompress_ptr dinfo, unsigned char* buffer, size_t size)
      {
      struct jpeg_source_mgr* src;
      
      /* first call for this instance - need to setup */
      if (dinfo->src == 0) {
      dinfo->src = (struct jpeg_source_mgr *)
      (*dinfo->mem->alloc_small) ((j_common_ptr) dinfo, JPOOL_PERMANENT,
      sizeof (struct jpeg_source_mgr));
      }
      
      src = dinfo->src;
      src->next_input_byte = buffer;
      src->bytes_in_buffer = size;
      src->init_source = init_source;
      src->fill_input_buffer = fill_input_buffer;
      src->skip_input_data = skip_input_data;
      src->term_source = term_source;
      /* IJG recommend to use their function - as I don't know ****
      about how to do better, I follow this recommendation */
      src->resync_to_restart = jpeg_resync_to_restart;
      }
      

      并在您的主要压缩功能中将 jpeg_stdio_dest 替换为

      int numBytes = 0; //size of jpeg after compression
      char * storage = new char[150000]; //storage buffer
      JOCTET *jpgbuff = (JOCTET*)storage; //JOCTET pointer to buffer
      jpeg_memory_dest(&cinfo,jpgbuff,150000,&numBytes);
      

      150000 是一个静态大小的缓冲区,您可能会有超过它的图像,因此请相应地分配。

      【讨论】:

        【解决方案3】:

        我得到了内存压缩工作。见下文

        #define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite’able size */
        
        /* Expanded data destination object for memory output */
        
        typedef struct {
        struct jpeg_destination_mgr pub; /* public fields */
        
        unsigned char ** outbuffer; /* target buffer */
        unsigned long * outsize;
        unsigned char * newbuffer; /* newly allocated buffer */
        JOCTET * buffer; /* start of buffer */
        size_t bufsize;
        } my_mem_destination_mgr;
        
        typedef my_mem_destination_mgr * my_mem_dest_ptr;
        
        void
        init_mem_destination (j_compress_ptr cinfo)
        {
        /* no work necessary here */
        }
        
        boolean
        empty_mem_output_buffer (j_compress_ptr cinfo)
        {
        size_t nextsize;
        JOCTET * nextbuffer;
        my_mem_dest_ptr dest = (my_mem_dest_ptr) cinfo->dest;
        
        /* Try to allocate new buffer with double size */
        nextsize = dest->bufsize * 2;
        nextbuffer = (JOCTET *)malloc(nextsize);
        
        if (nextbuffer == NULL)
        ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10);
        
        memcpy(nextbuffer, dest->buffer, dest->bufsize);
        
        if (dest->newbuffer != NULL)
        free(dest->newbuffer);
        
        dest->newbuffer = nextbuffer;
        
        dest->pub.next_output_byte = nextbuffer + dest->bufsize;
        dest->pub.free_in_buffer = dest->bufsize;
        
        dest->buffer = nextbuffer;
        dest->bufsize = nextsize;
        
        return TRUE;
        }
        
        void
        term_mem_destination (j_compress_ptr cinfo)
        {
        my_mem_dest_ptr dest = (my_mem_dest_ptr) cinfo->dest;
        
        *dest->outbuffer = dest->buffer;
        *dest->outsize = dest->bufsize – dest->pub.free_in_buffer;
        }
        
        void
        jpeg_mem_dest (j_compress_ptr cinfo,
        unsigned char ** outbuffer, unsigned long * outsize)
        {
        my_mem_dest_ptr dest;
        
        if (outbuffer == NULL || outsize == NULL) /* sanity check */
        ERREXIT(cinfo, JERR_BUFFER_SIZE);
        
        /* The destination object is made permanent so that multiple JPEG images
        * can be written to the same buffer without re-executing jpeg_mem_dest.
        */
        if (cinfo->dest == NULL) { /* first time for this JPEG object? */
        cinfo->dest = (struct jpeg_destination_mgr *)
        (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
        sizeof(my_mem_destination_mgr));
        }
        
        dest = (my_mem_dest_ptr) cinfo->dest;
        dest->pub.init_destination = init_mem_destination;
        dest->pub.empty_output_buffer = empty_mem_output_buffer;
        dest->pub.term_destination = term_mem_destination;
        dest->outbuffer = outbuffer;
        dest->outsize = outsize;
        dest->newbuffer = NULL;
        
        if (*outbuffer == NULL || *outsize == 0) {
        /* Allocate initial buffer */
        dest->newbuffer = *outbuffer = (unsigned char*)malloc(OUTPUT_BUF_SIZE);
        if (dest->newbuffer == NULL)
        ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10);
        *outsize = OUTPUT_BUF_SIZE;
        }
        
        dest->pub.next_output_byte = dest->buffer = *outbuffer;
        dest->pub.free_in_buffer = dest->bufsize = *outsize;
        }
        //*******************************************************************************************
        

        要使用它,请在 main 中执行类似的操作

        /************/
        
        unsigned long outlen;
        unsigned char *outbuffer;
        
        jpeg_mem_dest (&cinfo,&outbuffer,&outlen );
        printf(“outlen is %lu\n”,(long unsigned int)outlen);
        

        【讨论】:

          【解决方案4】:

          在与 libJpeg 斗争了 2 天(指针、内存步进和拉毛)之后,我放弃了并使用了所有最喜欢的保存到磁盘-加载到内存的方法,所以如果有人感兴趣,这里是该方法:

          char* convert2jpeg(IplImage* frame, int* frame_size) {
          
          FILE* infile = NULL;
          struct stat fileinfo_buf;
          
          if (cvSaveImage(name_buf, frame) < 0) {
              printf("\nCan't save image %s", name_buf);
              return NULL;
          }
          
          if (stat(name_buf, &fileinfo_buf) < 0) {
              printf("\nPLAYER [convert2jpeg] stat");
              return NULL;
          }
          
          *frame_size = fileinfo_buf.st_size;
          char* buffer = (char *) malloc(fileinfo_buf.st_size + 1);
          
          if ((infile = fopen(name_buf, "rb")) == NULL) {
              printf("\nPLAYER [convert2jpeg] fopen %s", name_buf);
              free(buffer);
              return NULL;
          }
          
          fread(buffer, fileinfo_buf.st_size, 1, infile);
          fclose(infile);
          
          return buffer;
          }
          

          我希望有人觉得这很有用。我希望 OpenCV 开发人员的某个人看到这个线程并在 OpenCV 中实现直接缓冲 JPEG 转换,让我们免于痛苦和 1 保存/加载到磁盘操作。

          【讨论】:

            猜你喜欢
            • 2011-07-23
            • 1970-01-01
            • 2013-04-29
            • 2010-10-16
            • 2015-06-20
            • 2010-10-22
            • 2013-06-06
            • 2017-04-07
            相关资源
            最近更新 更多