Project

General

Profile

Opening an OpenCV cv::Mat image using open(buff,length) on the fly.

Added by Yogesh Khedar almost 5 years ago

Hi,
I need to open a cv::Mat image into Exiv2 using the Exiv2::ImageFactory::open(buf, length) function but it throws an error that Image is of unknown type. I am attaching the test file. This file was adapted from one of the message thread on this forum. I am not able to find it again :(. I have following question:

1. How does Exiv2 checks for the image type? If I figure this out then probably I can convert the cv::Mat image in the relevant format.

Would really appreciate any help.

Regards,
khedar


Replies (5)

RE: Opening an OpenCV cv::Mat image using open(buff,length) on the fly. - Added by Robin Mills almost 5 years ago

Exiv2 supports about 15 common image formats such as TIFF, JPEG and PNG. I don't know cv::Mat. You may be able to convert to a supported format.

519 rmills@rmillsmbp:~/gnu/exiv2/trunk $ wc src/*image.cpp
   159    580   5169 src/bmpimage.cpp
   303    904   9797 src/cr2image.cpp
  1435   4740  50557 src/crwimage.cpp
  1192   5373  56884 src/epsimage.cpp
   141    462   4282 src/gifimage.cpp
  1054   3580  36550 src/image.cpp
   938   3200  39759 src/jp2image.cpp
  1349   5739  58025 src/jpgimage.cpp
   183    594   5686 src/mrwimage.cpp
   285    813   8890 src/orfimage.cpp
   349   1133  11531 src/pgfimage.cpp
   736   2793  30608 src/pngimage.cpp
   712   3095  31737 src/psdimage.cpp
   160    533   5169 src/rafimage.cpp
   282    792   9169 src/rw2image.cpp
   176    626   5986 src/tgaimage.cpp
  2316  10223 106761 src/tiffimage.cpp
   805   2787  30822 src/webpimage.cpp
 12575  47967 507382 total
520 rmills@rmillsmbp:~/gnu/exiv2/trunk $ 
You can add new image format handler by deriving a new class (such as MatImage) from class Image. You need to implement functions such as open(), readMetadata() and writeMetadata(). Without knowing anything about cv::Mat, I don't know how much effort is involved. Last August, Ben and I cooperated to add webp support. It was about 4 weeks work (each) to add 1000 lines of C++ code, plus test files and test suite updates.

RE: Opening an OpenCV cv::Mat image using open(buff,length) on the fly. - Added by Yogesh Khedar almost 5 years ago

Thanks Robin for your suggestion. Writing a format handler for cv::Mat seems a daunting task. For now I solved the problem by first converting the cv::Mat into a jpeg buffer using OpenCV's imencode(....) function. Then used this buffer to open Exiv2 image on the fly. Attached is the modified code for reference.
I still one problem left though. While writing the buffer to a new file I tried two ways, both are able to write the new file but only one writes the ExifTags.
Method 1 works but I need to open and close the same file twice. I want to avoid that.

// 1. Writing to disk
// Create a new file for writing.
FILE * file1 = ::fopen("mm2.jpg", "w");
::fclose(file1);
// Now open using FileIo for writing.
Exiv2::FileIo file("mm2.jpg");
file.open();
file.write(image->io());

So i tried method 2. But it does not write ExifTags

// 2. Writing to disk
// This works but does not write metatags.
// FILE * file = ::fopen("mm.jpg", "w");
//::fwrite(&cvbuff[0], image->io().size(), 1, file);
//::fclose(file);

is it related to resizing of buffer before writing, which FileIo might be doing. Will explore it further but any suggestions will be helpful.

Thanks,
khedar

RE: Opening an OpenCV cv::Mat image using open(buff,length) on the fly. - Added by Robin Mills almost 5 years ago

I hadn't heard of OpenCV until yesterday. Gosh, it's massive. I'm not too sure what Computer Vision is all about, however it looks as though an OpenCV "image" is more like PDF which is a container for geometric and other entities. It's nothing like JPEG, TIFF and the like which are bitmaps. Metadata in most of the image formats that Exiv2 supports are actually TIFF files embedded in the bitmap header. Supporting OpenCV from Exiv2 looks like a massive, and possibly impossible task. Converting to JPEG and embedding the metadata seems a better strategy.

I'm not too certain what image represents in your code. Perhaps you should call:

image->writeMetadata();
before ::write();::close().

I'm on vacation at the moment (in beautiful New Zealand) and about to have breakfast. I'll try to find time to look at your code this evening. In general you shouldn't need to use ::fmumble calls as the BasicIo classes are designed to hide those while supporting remoteIo such as HTTP. I suspect a little simplification and you'll achieve your desired result.

RE: Opening an OpenCV cv::Mat image using open(buff,length) on the fly. - Added by Yogesh Khedar almost 5 years ago

"image" is an instance of Exiv2::Image class and I am calling the image->writeMetadata(); before the code snippets in my previous post. I was worried about the additional overhead of creating the file and then opening it again with BasicIo and that is the reason I wanted Method 2 to work but it seems the overhead is negligible. I checked the CPU and Memory usage of the process and they were well below 2% which seems to be pretty reasonable. And I don't think I will be using my camera at fps settings higher than the current one.

Enjoy your vacations :)

RE: Opening an OpenCV cv::Mat image using open(buff,length) on the fly. - Added by Robin Mills almost 5 years ago

Ah right. I've looked at the attached code and understand what you're doing. I'm sure the code ::fopen/::close() code will execute almost instantly. I think the API Exiv2::ImageFactory::createIo(path) can replace

    // 1. Writing to disk
    // Create a new file for writing.
    FILE * file1 = ::fopen("mm2.jpg", "w");
    ::fclose(file1);
    Exiv2::FileIo file("mm2.jpg");
    file.open();

I think your method 2. Writing to disk doesn't work because you're writing the raw bytes from cvbuff to file. Is there any metadata in cvbuff? Who knows, it's raw data from CVOpen. image->io().size() is an integer. You need to write the image body that contains the metadata. And that's what you're doing with your method 1. Writing to disk.

Combining all of this, can you try the following:

    std::string path="mm.jpg";

    FILE* file = ::fopen(path);
    ::fwrite(&cvbuff[0], 1,cvbuff.size(),file);
    ::fclose(file);

    Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path);
    image->readMetata();
    Exiv2::ExifData &exifData = image->exifData();
    exifData["Exif.Image.Model"] = "A long model name to make the Exif metadata grow";
    image->writeMetadata();
    image->close();
I'm sure this isn't the best fix for this - however I'm confident you'll correct it and reveal your perfect solution.

For sure, you can avoid opening the file with ::fopen etc and use MemIo object instead. The difference in performance (as you have observed) is probably negligible.

    (1-5/5)