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
geotag.cpp (1.42 KB) geotag.cpp |
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
geotag2.cpp (1.34 KB) geotag2.cpp |
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.