C++ 在内存缓冲区或文件指针中使用的 OpenCV

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/801199/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 17:21:18  来源:igfitidea点击:

OpenCV to use in memory buffers or file pointers

c++memoryopencv

提问by The Unknown

The two functions in openCV cvLoadImage and cvSaveImage accept file path's as arguments.

openCV cvLoadImage 和 cvSaveImage 中的两个函数接受文件路径作为参数。

For example, when saving a image it's cvSaveImage("/tmp/output.jpg", dstIpl)and it writes on the disk.

例如,当保存图像时,它是cvSaveImage("/tmp/output.jpg", dstIpl)并写入磁盘。

Is there any way to feed this a buffer already in memory? So instead of a disk write, the output image will be in memory.

有什么办法可以将这个缓冲区提供给内存中已经存在的缓冲区吗?因此,输出图像将在内存中,而不是磁盘写入。

I would also like to know this for both cvSaveImage and cvLoadImage (read and write to memory buffers). Thanks!

我也想知道这对于 cvSaveImage 和 cvLoadImage(读取和写入内存缓冲区)。谢谢!



My goal is to store the Encoded (jpeg) version of the file in Memory. Same goes to cvLoadImage, I want to load a jpeg that's in memory in to the IplImage format.

我的目标是将文件的编码 (jpeg) 版本存储在内存中。cvLoadImage 也是如此,我想将内存中的 jpeg 加载为 IplImage 格式。

采纳答案by M456

There are a couple of undocumented functions in the SVN version of the libary:

库的 SVN 版本中有几个未记录的函数:

CV_IMPL CvMat* cvEncodeImage( const char* ext, 
                              const CvArr* arr, const int* _params )

CV_IMPL IplImage* cvDecodeImage( const CvMat* _buf, int iscolor )

Latest check in message states that they are for native encoding/decoding for bmp, png, ppm and tiff (encoding only).

最新签入消息指出它们用于 bmp、png、ppm 和 tiff(仅编码)的本机编码/解码。

Alternatively you could use a standard image encoding library (e.g. libjpeg) and manipulate the data in the IplImage to match the input structure of the encoding library.

或者,您可以使用标准图像编码库(例如 libjpeg)并操作 IplImage 中的数据以匹配编码库的输入结构。

回答by codeDr

This worked for me

这对我有用

// decode jpg (or other image from a pointer)
// imageBuf contains the jpg image
    cv::Mat imgbuf = cv::Mat(480, 640, CV_8U, imageBuf);
    cv::Mat imgMat = cv::imdecode(imgbuf, CV_LOAD_IMAGE_COLOR);
// imgMat is the decoded image

// encode image into jpg
    cv::vector<uchar> buf;
    cv::imencode(".jpg", imgMat, buf, std::vector<int>() );
// encoded image is now in buf (a vector)
    imageBuf = (unsigned char *) realloc(imageBuf, buf.size());
    memcpy(imageBuf, &buf[0], buf.size());
//  size of imageBuf is buf.size();

I was asked about a C version instead of C++:

有人问我 C 版本而不是 C++:

#include <opencv/cv.h>
#include <opencv/highgui.h>

int
main(int argc, char **argv)
{
    char *cvwin = "camimg";

    cvNamedWindow(cvwin, CV_WINDOW_AUTOSIZE);

    // setup code, initialization, etc ...
    [ ... ]

    while (1) {      
        // getImage was my routine for getting a jpeg from a camera
        char *img = getImage(fp);
        CvMat mat;

   // substitute 640/480 with your image width, height 
        cvInitMatHeader(&mat, 640, 480, CV_8UC3, img, 0);
        IplImage *cvImg = cvDecodeImage(&mat, CV_LOAD_IMAGE_COLOR);
        cvShowImage(cvwin, cvImg);
        cvReleaseImage(&cvImg);
        if (27 == cvWaitKey(1))         // exit when user hits 'ESC' key
        break;
    }

    cvDestroyWindow(cvwin);
}

回答by jdt141

I'm assuming you're working in linux. From libjpeg.doc:

我假设你在 linux 中工作。来自 libjpeg.doc:

The rough outline of a JPEG compression operation is:
Allocate and initialize a JPEG compression object
Specify the destination for the compressed data (eg, a file)
Set parameters for compression, including image size & colorspace

jpeg_start_compress(...);
while (scan lines remain to be written)
jpeg_write_scanlines(...);

jpeg_finish_compress(...);
Release the JPEG compression object

JPEG 压缩操作的大致轮廓是:
分配和初始化 JPEG 压缩对象
指定压缩数据的目的地(例如,文件)
设置压缩参数,包括图像大小和色彩空间

jpeg_start_compress(...);
而(扫描线仍有待写入)
jpeg_write_scanlines(...);

jpeg_finish_compress(...);
释放JPEG压缩对象

The real trick for doing what you want to do is providing a custom "data destination (or source) manager" which is defined in jpeglib.h:

做你想做的事情的真正技巧是提供一个在 jpeglib.h 中定义的自定义“数据目标(或源)管理器”:

struct jpeg_destination_mgr {
  JOCTET * next_output_byte;    /* => next byte to write in buffer */
  size_t free_in_buffer;        /* # of byte spaces remaining in buffer */

  JMETHOD(void, init_destination, (j_compress_ptr cinfo));
  JMETHOD(boolean, empty_output_buffer, (j_compress_ptr cinfo));
  JMETHOD(void, term_destination, (j_compress_ptr cinfo));
};

Basically set that up so your source and/or destination are the memory buffers you want, and you should be good to go.

基本上设置好你的源和/或目标是你想要的内存缓冲区,你应该很高兴。

As an aside, this post could be a lot better but the libjpeg62 documentation is, quite frankly, superb. Just apt-get libjpeg62-dev and read libjpeg.doc and look at example.c. If you run into problems and can't get something to work, just post again and I'm sure someone will be able to help.

顺便说一句,这篇文章可能会好很多,但坦率地说,libjpeg62 文档非常棒。只需 apt-get libjpeg62-dev 并阅读 libjpeg.doc 并查看 example.c。如果您遇到问题并且无法解决问题,请再次发帖,我相信有人会提供帮助。

回答by enthusiasticgeek

All you need to load files from the memory buffer is a different src manager (libjpeg). I have tested the following code in Ubuntu 8.10.

从内存缓冲区加载文件所需的只是一个不同的 src 管理器 (libjpeg)。我已经在 Ubuntu 8.10 中测试了以下代码。

/******************************** First define mem buffer function bodies **************/
<pre>
/*
 * memsrc.c
 *
 * Copyright (C) 1994-1996, Thomas G. Lane.
 * This file is part of the Independent JPEG Group's software.
 * For conditions of distribution and use, see the accompanying README file.
 *
 * This file contains decompression data source routines for the case of
 * reading JPEG data from a memory buffer that is preloaded with the entire
 * JPEG file.  This would not seem especially useful at first sight, but
 * a number of people have asked for it.
 * This is really just a stripped-down version of jdatasrc.c.  Comparison
 * of this code with jdatasrc.c may be helpful in seeing how to make
 * custom source managers for other purposes.
 */

/* this is not a core library module, so it doesn't define JPEG_INTERNALS */
//include "jinclude.h"
include "jpeglib.h"
include "jerror.h"


/* Expanded data source object for memory input */

typedef struct {
  struct jpeg_source_mgr pub;   /* public fields */

  JOCTET eoi_buffer[2];     /* a place to put a dummy EOI */
} my_source_mgr;

typedef my_source_mgr * my_src_ptr;


/*
 * Initialize source --- called by jpeg_read_header
 * before any data is actually read.
 */

METHODDEF(void)
init_source (j_decompress_ptr cinfo)
{
  /* No work, since jpeg_memory_src set up the buffer pointer and count.
   * Indeed, if we want to read multiple JPEG images from one buffer,
   * this *must* not do anything to the pointer.
   */
}


/*
 * Fill the input buffer --- called whenever buffer is emptied.
 *
 * In this application, this routine should never be called; if it is called,
 * the decompressor has overrun the end of the input buffer, implying we
 * supplied an incomplete or corrupt JPEG datastream.  A simple error exit
 * might be the most appropriate response.
 *
 * But what we choose to do in this code is to supply dummy EOI markers
 * in order to force the decompressor to finish processing and supply
 * some sort of output image, no matter how corrupted.
 */

METHODDEF(boolean)
fill_input_buffer (j_decompress_ptr cinfo)
{
  my_src_ptr src = (my_src_ptr) cinfo->src;

  WARNMS(cinfo, JWRN_JPEG_EOF);

  /* Create a fake EOI marker */
  src->eoi_buffer[0] = (JOCTET) 0xFF;
  src->eoi_buffer[1] = (JOCTET) JPEG_EOI;
  src->pub.next_input_byte = src->eoi_buffer;
  src->pub.bytes_in_buffer = 2;

  return TRUE;
}


/*
 * Skip data --- used to skip over a potentially large amount of
 * uninteresting data (such as an APPn marker).
 *
 * If we overrun the end of the buffer, we let fill_input_buffer deal with
 * it.  An extremely large skip could cause some time-wasting here, but
 * it really isn't supposed to happen ... and the decompressor will never
 * skip more than 64K anyway.
 */

METHODDEF(void)
skip_input_data (j_decompress_ptr cinfo, long num_bytes)
{
  my_src_ptr src = (my_src_ptr) cinfo->src;

  if (num_bytes > 0) {
    while (num_bytes > (long) src->pub.bytes_in_buffer) {
      num_bytes -= (long) src->pub.bytes_in_buffer;
      (void) fill_input_buffer(cinfo);
      /* note we assume that fill_input_buffer will never return FALSE,
       * so suspension need not be handled.
       */
    }
    src->pub.next_input_byte += (size_t) num_bytes;
    src->pub.bytes_in_buffer -= (size_t) num_bytes;
  }
}


/*
 * An additional method that can be provided by data source modules is the
 * resync_to_restart method for error recovery in the presence of RST markers.
 * For the moment, this source module just uses the default resync method
 * provided by the JPEG library.  That method assumes that no backtracking
 * is possible.
 */


/*
 * Terminate source --- called by jpeg_finish_decompress
 * after all data has been read.  Often a no-op.
 *
 * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
 * application must deal with any cleanup that should happen even
 * for error exit.
 */

METHODDEF(void)
term_source (j_decompress_ptr cinfo)
{
  /* no work necessary here */
}


/*
 * Prepare for input from a memory buffer.
 */

GLOBAL(void)
jpeg_memory_src (j_decompress_ptr cinfo, const JOCTET * buffer, size_t bufsize)
{
  my_src_ptr src;

  /* The source object is made permanent so that a series of JPEG images
   * can be read from a single buffer by calling jpeg_memory_src
   * only before the first one.
   * This makes it unsafe to use this manager and a different source
   * manager serially with the same JPEG object.  Caveat programmer.
   */
  if (cinfo->src == NULL) { /* first time for this JPEG object? */
    cinfo->src = (struct jpeg_source_mgr *)
      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
                  SIZEOF(my_source_mgr));
  }

  src = (my_src_ptr) cinfo->src;
  src->pub.init_source = init_source;
  src->pub.fill_input_buffer = fill_input_buffer;
  src->pub.skip_input_data = skip_input_data;
  src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
  src->pub.term_source = term_source;

  src->pub.next_input_byte = buffer;
  src->pub.bytes_in_buffer = bufsize;
}

Then the usage is pretty simple. You may need to replace SIZEOF() with sizeof(). Find a standard decompression example. Just replace "jpeg_stdio_src" with "jpeg_memory_src". Hope that helps!

那么使用就很简单了。您可能需要用 sizeof() 替换 SIZEOF()。查找标准解压示例。只需将“jpeg_stdio_src”替换为“jpeg_memory_src”。希望有帮助!

回答by Mr Fooz

This is an indirect answer...

这是一个间接的答案......

In the past, I've directly used libpngand libjpegdirectly to do this. They have a low-level enough API that you can use memory buffers instead of file buffers for reading and writing.

过去,我直接使用libpnglibjpeg来做到这一点。它们具有足够低级别的 API,您可以使用内存缓冲区而不是文件缓冲区进行读取和写入。

回答by Meh Nada

Here's an example in Delphi. It converts a 24bit bitmap for use with OpenCV

这是 Delphi 中的一个示例。它转换 24 位位图以与 OpenCV 一起使用

function BmpToPIplImageEx(Bmp: TBitmap): pIplImage;
Var
  i: Integer;
  offset: LongInt;
  dataByte: PByteArray;  
Begin
  Assert(Bmp.PixelFormat = pf24bit, 'PixelFormat must be 24bit');
  Result := cvCreateImageHeader(cvSize(Bmp.Width, Bmp.Height), IPL_DEPTH_8U, 3);
  cvCreateData(Result);
  for i := 0 to Bmp.height - 1 do
  Begin        
    offset   := longint(Result.imageData) + Result.WidthStep * i;
    dataByte := PByteArray(offset);    
    CopyMemory(dataByte, Bmp.Scanline[i], Result.WidthStep);
  End;
End;