2009-04-29 14 views
15

Las dos funciones en openCV cvLoadImage y cvSaveImage aceptan la ruta del archivo como argumentos. Por ejemplo, cuando se guarda una imagen, es cvSaveImage ("/ tmp/output.jpg", dstIpl) y se escribe en el disco.OpenCV para usar en búferes de memoria o punteros de archivo

¿Hay alguna manera de alimentar esto un búfer que ya está en la memoria? Entonces, en lugar de escribir un disco, la imagen de salida estará en la memoria.

También me gustaría saber esto para cvSaveImage y cvLoadImage (leer y escribir en memorias intermedias de memoria). ¡Gracias!


Mi objetivo es almacenar la versión codificada (jpeg) del archivo en la memoria. Lo mismo ocurre con cvLoadImage, quiero cargar un jpeg que está en la memoria en el formato IplImage.

+1

¿Desea escribir la imagen en la memoria? Pero dstIpl ya está en la memoria, ¿qué es exactamente lo que espera lograr? Puede acceder a los datos de imagen con dstIpl-> imageData o -> datos o algo. – mpen

+0

Del mismo modo, podría manipular el búfer de datos de iplImage para cargar una imagen que ya está en la memoria ... solo tiene que estar en formato BGR. – mpen

+0

Creo que el póster original quiere codificar la imagen pero guarda un disco de lectura/escritura. – M456

Respuesta

14

Hay un par de funciones no documentadas en la versión SVN del libary:

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

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

última hora de entrada mensaje indica que son para la codificación nativa/decodificación para bmp, png, ppm y TIFF (que codifica solamente)

Alternativamente, podría utilizar una biblioteca de codificación de imágenes estándar (por ejemplo, libjpeg) y manipular los datos en la imagen Ipl para que coincida con la estructura de entrada de la biblioteca de codificación.

+7

NO confíe en las funciones no documentadas, creará una pesadilla de mantenimiento para usted. La razón por la que no están documentados es porque los diseñadores ** no esperan que se mantengan estables en el tiempo **. ¡Podrían desaparecer con la próxima versión! –

+3

Creo que la advertencia está implícita en cualquier versión de desarrollo. Además, la documentación siempre ha sido un problema con OpenCV, muchas de las funciones estables aún no están documentadas. – M456

0

Ésta es una respuesta indirecta ...

En el pasado, he utilizado directamente libpng y libjpeg directamente a hacer esto. Tienen una API de bajo nivel suficiente para que puedas usar memorias intermedias de memoria en lugar de búferes de archivos para leer y escribir.

+0

Si votó negativamente, por favor deje un comentario explicando por qué esta respuesta es incorrecta. De esa forma se puede mejorar. –

1

Supongo que estás trabajando en Linux. De libjpeg.doc:

El esbozo de una operación compresión JPEG es:
Asignar e inicializar una compresión JPEG objeto
especificar el destino de los datos comprimidos (por ejemplo, un archivo)
Conjunto parámetros de compresión, incluyendo el tamaño de la imagen & espacio de color

jpeg_start_compress (...);
while (las líneas de escaneo quedan por escribir)
jpeg_write_scanlines (...);

jpeg_finish_compress (...);
lanzamiento el objeto de compresión JPEG

El verdadero truco para hacer lo que quieres hacer es proporcionar una costumbre "destino de datos (o fuente) manager" que se define en 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)); 
}; 

Básicamente configure eso para que su fuente y/o destino sean los búferes de memoria que desea, y debería estar listo para continuar.

Como nota aparte, esta publicación podría ser mucho mejor, pero la documentación de libjpeg62 es, francamente, excelente. Solo tienes que obtener libjpeg62-dev y leer libjpeg.doc y mirar example.c. Si tiene problemas y no puede hacer que algo funcione, solo publique nuevamente y estoy seguro de que alguien podrá ayudarlo.

0

Todo lo que necesita para cargar archivos desde el búfer de memoria es un administrador src diferente (libjpeg). He probado el siguiente código en 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; 
} 

Entonces el uso es bastante simple. Es posible que deba reemplazar SIZEOF() con sizeof(). Encuentre un ejemplo de descompresión estándar. Simplemente reemplace "jpeg_stdio_src" por "jpeg_memory_src". ¡Espero que ayude!

15

Esto funcionó para mí

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

me preguntó acerca de una versión de C en lugar de 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); 
} 
+0

¿no es la intención que imdecode decodifique la imagen, entonces, ¿por qué imageBuf necesita ser colocado en un cv :: mat? Estoy teniendo problemas donde tengo un char * sin firmar que contiene los datos sin procesar que cargué sobre el cable (es una imagen tiff), pero después de hacer el ajuste de imdecode en los datos sin formato el Mat tiene su mat.data == 0 y no se han dado errores. –

+0

@pksorensen imageBuf debe colocarse en un Mat para que pueda ser aceptado como un parámetro para imdecode() a menos que haya magia C++ que pueda convertirlo en InputArray que imdecode() desee. Las razones para no decodificar su imagen TIFF serían (1) el Mat pasado a imgdecode rows * cols fue menor que 1, (2) el soporte TIFF no se compiló en su biblioteca OpenCV o (3) que el decodificador TIFF no reconoció su buffer de imagen como una imagen TIFF válida. – codeDr

0

He aquí un ejemplo en Delphi. Convierte un mapa de bits de 24 bits para su uso con 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; 
Cuestiones relacionadas