-
-
Notifications
You must be signed in to change notification settings - Fork 56.2k
export img decoders/encoders #8511
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
export img decoders/encoders #8511
Conversation
efa3ea7
to
02eee62
Compare
|
02eee62
to
61aab2f
Compare
this builds on opencv#8492 and opencv#8511 to add a new method, .orientation(), to ImageDecoder. The JPEG subclass now overrides this to do jpeg-specific exif tag reading we also now export a method, OrientationTransform, which uses this orientation value to do the actual matrix operations
New OpenCV public API should not contain complex classes with "virtual" methods. This is needed to avoid ABI (application binary interface) violations and producing hacks like this - just want to add new method. Please follow "pImpl design pattern" instead. Example: Please avoid(or minimize) using of STL objects in interfaces (std::vector/std::map/std::string/etc) - this may raise ABI problems which is very hard to debug (especially for newbie C++ developers): #6198 #5227 #6165 |
@alalek 👍 Good stuff. I think I thought I was accomplishing the pimpl pattern by making the virtual base class and returning |
@alalek What would you think about leaving ImageEncoder's write params arg as Actually, for that matter, imencode also uses As far as I can tell those are the only places in this patch where STL types are exposed in the ABI. |
Probably we can try to use InputArray wrapper instead of "std::vector& params" (the latest changes support C++
I believe |
@alalek is it possible to run the tests locally? i tried pulling down the sample data but i wasn't really sure where it needs to go or how to invoke it, so i'm dependent on the tester here to check for now :( |
@alalek Ok, nevermind, I put together a small test program. |
@alalek So this passes the tests, but I'm not so good at opencv-fu, and I needed to allocate a new Mat and then copy that Mat back to the destination vector in Is there a way around that that we can avoid? I have briefly tried using OutputArray but I'm not really sure how to do the operations I need to on it, including when it's of type |
@brian-armstrong-discord There is some conflicts with master branch. Please rebase this patch to actual master branch. Something like these:
BTW, We prefer to have patches with single commit to eliminate intermediate "fixup" commits from git history. Sometimes it is better to squash your commits before rebase to upstream code ( Rebased branch for reference:
|
172aa54
to
c2e329e
Compare
c2e329e
to
ca5afce
Compare
@alalek Looks like the conflicts are gone now |
Hi @alalek Have you had a chance to look at this recently? |
Hi @brian-armstrong-discord ! |
@alalek @brian-armstrong-discord I also found the idea -to get the header data- very promising. If one might ask, what's the state so far? P.S. It doesn't seem like you need some help, but if you are - feel free to text me :)
|
Hi @alalek Any updates in this PR? I would love to put this work behind me finally :) Anecdotally, this patch is working well in production. I know you will likely have some more requests on the interface of it, though. |
@Turim an imreadheader would, among other issues, force us to re-read the header bytes when we go to decode. it also opens the possibility of imread() and imreadheader() doing different things. this would be a brittle approach to the solution. i'm open to using enums, but internally opencv uses strings, and it made sense to me to make this change as lightweight as possible. |
@brian-armstrong-discord ,
Can I ask you to be more specific? In competition 'enum vs strings' where's the pros of the string usage? |
@Turim You're more than welcome to try whatever you think will work well. I'd like to stick with the approach that's in this PR because the Decoder and Encoder classes do the same work that was being done before and offer the user a relatively clean interface. |
@alalek Do you think there's any hope for this PR? I'm wondering where I should set my expectations. |
i want to share my humble thoughts about this PR personally i think a new class using existing decoders and encoders internally can be a good candidate to the solution |
Sorry for huge delay! Current interface is very questionable (for example,
Perhaps, we could start with simple set of functions, for example:
I believe it is able to handle declared set of problems from the PR description. |
@alalek , IMHO
I think the case could be mantained for the imgcodecs to be more clean. Nowadays the only what a imgcodecs' user can is try to load the image via, say, imread and check the retval. But in the prod code it's just sort of gambling with user's memory (i.e. working set) - every try to load image, say, 10000x10000 or even bigger leads to a memory consumption peak with empty retval. Am I right that you prefer not to add struct/classes?
As for mentioned imquery() - yes, it gives you the option to distinguish JPEG from TIFF, but the image size is an open question still - so you basically don't know if there any way to load it. P.S. @brian-armstrong-discord I apologize for I've just mentioned yet another interface for the case. Quite unsure should I create a separate discussion for that. Feel free to provide the feedback on that. |
In case of
I prefer to handle the most universal cases and I prefer not to add some rarely used hacks (like
Check amount of useful information between "bool" result and "exception" with message and potentially stack-trace to the reason of problem. |
@alalek , thanks for clarifying.
You're correct, my mistake.
AFAIK imreadmulti() supports it and, I presume, it's the only goal. |
Should I go ahead and just abandon this? The |
Are there any plans to add something like imquery? We'd love to get off this fork, especially now that opencv has changed substantially. |
jenkins cn please retry a build |
Hi, I think this pull request covers my GSoC proposal :). Before the coding period started, I was doing some research and found myself here. I am going to do a meeting with my mentor about this topic but after seeing lots of people discuss this topic, I wanted to hear about you if you are still interested. After re-read your comments, I came to this conclusion. I think we should provide an API for reading image header-only using the approach c-like interface. If the user knows about the image data, he would not use this API to confirm. Only users would use this API who do not know about its image details. So for these users, re-reading the header should not be a problem. Because their concerns are probably about limited memory. They could sacrifice some CPU time to verify that their software is not going to die in the middle of the process. I think it should be something like this int imreadheader(String const& file, int flags, <Struct Header Info>);
int imreadheader(String const& file, int flags, <Struct Header Info>, Mat &img, int width, int height); // Read image to the img if image size within the given limits The second function does a different thing than what it says but I think it is good to provide this API. Please let me know what you think about this :). This pull request is opened in 2017 but is still open. So I did not bother to create a new one since there exists one on this topic. I hope this won't be a problem. |
Having imreadheader or similar calls for reading of the image header are not enough. |
/** Query image parameters
@sa cv::imread
Throws exception if image is not supported.
@param filename Name of file to be loaded
@param flags Flag that can take values of cv::ImreadModes
@param[out] type (optional) type of decoded cv::Mat returned by cv::imtead
@param[out] decoderName (optional) name of used image decoder for cv::imread
@returns size of image
*/
Size imquery(const cv::String& filename, int flags = IMREAD_COLOR,
CV_OUT int* type = NULL, CV_OUT cv::String* decoderName = NULL); You suggested this in 2017. I think I can implement this and overload the imread_ method. But somehow I can't escape from these lines in imread. // in imread_ function
ImageDecoder decoder;
#ifdef HAVE_GDAL
if(flags != IMREAD_UNCHANGED && (flags & IMREAD_LOAD_GDAL) == IMREAD_LOAD_GDAL ){
decoder = GdalDecoder().newDecoder();
}else{
#endif
decoder = findDecoder( filename );
#ifdef HAVE_GDAL
}
#endif We can overload the imread function to read image data using the result of imquery call. bool imread(String const& filename, int type, String const& decoderName, int flags, Size size) {
ImageDecoder decoder;
// Add a new method to ImageDecoder to find appropiate decoder by decoderName?
#ifdef HAVE_GDAL
if(flags != IMREAD_UNCHANGED && (flags & IMREAD_LOAD_GDAL) == IMREAD_LOAD_GDAL ){
decoder = GdalDecoder().newDecoder();
}else{
#endif
decoder = findDecoder( filename );
#ifdef HAVE_GDAL
}
#endif
/// if no decoder was found, return nothing.
if( !decoder ){
return 0;
}
int scale_denom = 1;
if( flags > IMREAD_LOAD_GDAL )
{
if( flags & IMREAD_REDUCED_GRAYSCALE_2 )
scale_denom = 2;
else if( flags & IMREAD_REDUCED_GRAYSCALE_4 )
scale_denom = 4;
else if( flags & IMREAD_REDUCED_GRAYSCALE_8 )
scale_denom = 8;
}
/// set the scale_denom in the driver
decoder->setScale( scale_denom );
/// set the filename in the driver
decoder->setSource( filename );
mat.create( size.height, size.width, type );
// read the image data
bool success = false;
try
{
success = decoder->readData(mat);
}
catch (const cv::Exception& e)
{
std::cerr << "imread_('" << filename << "'): can't read data: " << e.what() << std::endl << std::flush;
}
catch (...)
{
std::cerr << "imread_('" << filename << "'): can't read data: unknown exception" << std::endl << std::flush;
}
if (!success)
{
mat.release();
return false;
}
if( decoder->setScale( scale_denom ) > 1 ) // if decoder is JpegDecoder then decoder->setScale always returns 1
{
resize( mat, mat, Size( size.width / scale_denom, size.height / scale_denom ), 0, 0, INTER_LINEAR_EXACT);
}
/// optionally rotate the data if EXIF orientation flag says so
if (!mat.empty() && (flags & IMREAD_IGNORE_ORIENTATION) == 0 && flags != IMREAD_UNCHANGED )
{
ApplyExifOrientation(decoder->getExifTag(ORIENTATION), mat);
}
return true; What do you think about it? I think the function name We need a new function |
This pull request changes the image codecs API so that
findDecoder
andfindEncoder
are available to users. This allows users to inspect the header of an image before decoding it so that they can decide whether they want to decode the image before they do so. For example, the image might describe itself as being 1000000 x 1000000 pixels, in which case openCV will go ahead and allocate an extremely large buffer to hold this image. This new API gives the user the ability to decide they don't want to do that.In addition, this patch attempts to comment the API a little and make it safer to use by doing bounds checking in
readData
so that a too-small buffer given toreadData
will not yield some kind of bad write outside array bounds.