2009-04-29 37 views
15

Hai hàm trong đường dẫn tệp cvLoadImage và cvSaveImage chấp nhận là đối số.OpenCV để sử dụng trong bộ nhớ đệm hoặc tệp con trỏ

Ví dụ: khi lưu hình ảnh, đó là cvSaveImage ("/ tmp/output.jpg", dstIpl) và ghi trên đĩa.

Có cách nào để nạp bộ đệm này đã có trong bộ nhớ không? Vì vậy, thay vì ghi đĩa, hình ảnh đầu ra sẽ nằm trong bộ nhớ.

Tôi cũng muốn biết điều này cho cả cvSaveImage và cvLoadImage (đọc và ghi vào bộ nhớ đệm). Cảm ơn!


Mục tiêu của tôi là lưu trữ phiên bản được mã hóa (jpeg) của tệp trong Bộ nhớ. Tương tự với cvLoadImage, tôi muốn tải một jpeg có trong bộ nhớ vào định dạng IplImage.

+1

Bạn muốn ghi hình ảnh vào bộ nhớ? Nhưng dstIpl đã có trong bộ nhớ, chính xác bạn đang hy vọng đạt được điều gì? Bạn có thể truy cập dữ liệu hình ảnh với dstIpl-> imageData hoặc -> dữ liệu hoặc một cái gì đó. – mpen

+0

Tương tự như vậy, bạn có thể thao tác bộ đệm dữ liệu của iplImage để tải một hình ảnh đã có trong bộ nhớ ... chỉ cần có định dạng BGR. – mpen

+0

Tôi nghĩ rằng poster gốc muốn mã hóa hình ảnh nhưng lưu một đĩa đọc/ghi. – M456

Trả lời

14

Có một vài chức năng không có giấy tờ trong phiên bản SVN của THƯ VIỆN:

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

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

kiểm tra mới nhất trong thông điệp khẳng định rằng họ là để mã hóa bản địa/giải mã cho bmp, png, ppm và tiff (chỉ mã hóa).

Hoặc bạn có thể sử dụng thư viện mã hóa hình ảnh chuẩn (ví dụ: libjpeg) và thao tác dữ liệu trong IplImage để khớp với cấu trúc đầu vào của thư viện mã hóa.

+7

XIN VUI LÒNG không dựa vào các chức năng không có giấy tờ, bạn sẽ tạo ra một cơn ác mộng duy trì cho chính mình. Lý do họ không được ghi nhận là bởi vì các nhà thiết kế ** không mong đợi họ vẫn ổn định theo thời gian **. Họ có thể biến mất với phiên bản tiếp theo! –

+3

Tôi nghĩ rằng cảnh báo được ngụ ý với bất kỳ phiên bản phát triển nào. Ngoài ra, tài liệu luôn luôn là một vấn đề với OpenCV nhiều chức năng ổn định vẫn không có giấy tờ. – M456

0

Đây là một câu trả lời gián tiếp ...

Trong quá khứ, tôi đã trực tiếp sử dụng libpnglibjpeg trực tiếp để làm điều này. Họ có API cấp thấp đủ để bạn có thể sử dụng bộ nhớ đệm thay vì bộ đệm tệp để đọc và ghi.

+0

Nếu bạn downvote, xin vui lòng để lại một bình luận giải thích tại sao câu trả lời này là sai. Bằng cách đó, nó có thể được cải thiện. –

1

Tôi giả sử bạn đang làm việc trong linux. Từ libjpeg.doc:

Đề cương sơ bộ một JPEG hoạt động nén là:
Phân bổ và khởi tạo một nén JPEG đối tượng
Xác định điểm đến cho dữ liệu nén (ví dụ, một tập tin)
Đặt thông số để nén, bao gồm kích thước hình ảnh & colorspace

jpeg_start_compress (...);
trong khi (dòng quét vẫn được viết)
jpeg_write_scanlines (...);

jpeg_finish_compress (...);
phát hành đối tượng nén JPEG

Bí quyết thực sự cho làm những gì bạn muốn làm là cung cấp một tùy chỉnh "điểm đến dữ liệu (hoặc nguồn) quản lý" được định nghĩa trong 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)); 
}; 

Về cơ bản, hãy thiết lập để nguồn và/hoặc đích của bạn là bộ nhớ đệm bạn muốn, và bạn nên làm tốt.

Là một sang một bên, bài đăng này có thể tốt hơn rất nhiều nhưng tài liệu libjpeg62 là, khá thẳng thắn, tuyệt vời. Chỉ cần apt-get libjpeg62-dev và đọc libjpeg.doc và xem example.c. Nếu bạn gặp sự cố và không thể làm việc gì đó, chỉ cần đăng lại và tôi chắc chắn ai đó sẽ có thể trợ giúp.

0

Tất cả những gì bạn cần để tải tệp từ bộ nhớ đệm là trình quản lý src khác (libjpeg). Tôi đã thử nghiệm mã sau trong 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; 
} 

Sau đó, việc sử dụng khá đơn giản. Bạn có thể cần phải thay thế SIZEOF() bằng sizeof(). Tìm một ví dụ giải nén tiêu chuẩn. Chỉ cần thay thế "jpeg_stdio_src" bằng "jpeg_memory_src". Hy vọng rằng sẽ giúp!

15

này làm việc cho tôi

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

Tôi đã được hỏi về một phiên bản C thay vì 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

là nó không phải là ý định mà imdecode nên giải mã hình ảnh, vậy tại sao imageBuf cần phải được đặt trong một cv :: mat? Tôi gặp vấn đề mà tôi có một unsigned char * chứa dữ liệu thô tôi nạp trên dây (một hình ảnh tiff của nó), nhưng sau khi doign imdecode trên dữ liệu thô Mat là có mat.data == 0 và không có lỗi nào được đưa ra. –

+0

@pksorensen imageBuf cần phải được đưa vào một Mat để nó có thể được chấp nhận như một tham số cho imdecode() trừ khi có phép thuật C++ có thể biến nó thành InputArray mà imdecode() muốn. Lý do không giải mã ảnh TIFF của bạn sẽ là (1) Mat được truyền vào hàng imgdecode * cols nhỏ hơn 1, (2) hỗ trợ TIFF không được biên dịch vào thư viện OpenCV của bạn hoặc (3) bộ giải mã TIFF không nhận ra đệm hình ảnh dưới dạng hình ảnh TIFF hợp lệ. – codeDr

0

Dưới đây là một ví dụ trong Delphi. Nó chuyển đổi bitmap 24 bit để sử dụng với 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; 
Các vấn đề liên quan