4

After many experiments, I found that reading color jpg file in C++ (OpenCV):

auto temp(cv::imread("xxx.jpg");

is different from reading the same file using C# bitmap :

var temp=new bitmap("xxx.jpg");

the results are diffrent. There is notable diffrence if I applied some algorithm on them both like GoodFeatureToTrack.

The question is: How can adoapt the way of C# bitmap loading in the OpenCV. So, I got the same result if I load my image directly in the native part or from the C# Wrapper.

Thanks

EDIT:

This code is a c++ function that take some struct that contain an image that was loaded in a manged program (c#) and then load the same image in opencv and compare them.. there is a different!

    extern "C" _declspec (dllexport) void test_diff(authenticator_reference_structure* referecnces){
    auto image(cv::imread("white.jpg"));

    cv::imshow("opencv", image);
    auto wrpped(referecnces->references->images->image.getMat());

    cv::imshow("C#", wrapped);
    cv::Mat ss;
    cv::absdiff(image, wrapped, ss);

    cv::threshold(ss, ss, 1, 255, CV_THRESH_BINARY);
    cv::imshow("Diff", ss);
    cv::waitKey();

}

the thresholded diffrences image

Humam Helfawi
  • 19,566
  • 15
  • 85
  • 160
  • 1
    What type of image? Grayscale? Colour? Have you tried passing different flags to `imread`? – Roger Rowland Sep 14 '15 at 14:35
  • Color images "different flags" for what ? – Humam Helfawi Sep 14 '15 at 14:36
  • 1
    You can use `CV_LOAD_IMAGE_ANYDEPTH` for 16 or 32-bit images, or `CV_LOAD_IMAGE_GRAYSCALE` to convert to grayscale. The default is `CV_LOAD_IMAGE_COLOR` which will result in a 3-channel image. Do your images have an alpha channel maybe? – Roger Rowland Sep 14 '15 at 14:42
  • I do not think that it contains alpha channel...However, I am going to try CV_LOAD_IMAGE_ANYDEPTH – Humam Helfawi Sep 14 '15 at 14:43
  • I tried it. it does not return 3-channels. I need the result to be 3 Channels (color) – Humam Helfawi Sep 14 '15 at 14:45
  • It's strange that you see such differences - there should be nothing significant unless one is doing an implicit grayscale conversion or somethng, which doesn't seem to be what you're seeing. Are you sure the problem is the *loading* of the image and not somewhere later? Can you show a minimal code example that has the problem? – Roger Rowland Sep 14 '15 at 14:49
  • In the worst case: What about writing a wrapper load the image in opencv use it from C# where you would create a bitmap with it, or load the image in C# using the bitmap and then access its data from C++ to create an OpenCV Mat. This way you will use the same loading library in both parts and the results should be the same. I imagine that your final goal is to compare the performance of some code both in C++ or C# so the image loading mechanism is not an issue. – rkachach Sep 24 '15 at 11:00

2 Answers2

3

Maybe you can use getImage() instead of getMat()?

A similar question is being addressed here (using openCV in C# not C++)
http://www.emgu.com/forum/viewtopic.php?t=188

alle_meije
  • 2,424
  • 1
  • 19
  • 40
  • You mean to include the EMGU in my c# application and use its image loader? it is possibe solution but I do not want to add EMGU to my c# application just for this purpose.. – Humam Helfawi Sep 21 '15 at 11:21
  • Opencv is included in the native part however it is not on the managed part – Humam Helfawi Sep 22 '15 at 07:56
  • You can just install emgu separately, include the header and link against it. You had (presumably) not included OpenCV in your project either? See http://www.emgu.com/wiki/index.php/Main_Page#Architecture_Overview -- for many things you call it instead of OpenCV (see http://www.emgu.com/wiki/index.php/Tutorial) – alle_meije Sep 22 '15 at 07:58
  • sorry, was still editing. but then C## will also be on the native part (it's Windows specific) so that should not change the managed depencies either? – alle_meije Sep 22 '15 at 08:00
  • My c# part does not have any thibg to fo with image processing. It just load an.image and pass it to the native c++ library – Humam Helfawi Sep 22 '15 at 08:11
  • My point is that the raw matrix `wrapped` are the values read by OpenCV (or emgu which is OpenCV for C#). The reason that the image shown on the screen has different values is probably available from the extra info that `getMat()` doesn't provide but `getImage()` does. So if you use the output of `getImage()`, either from OpenCV or emgu then your `wrapper` is probably the same as `image`? If you show us the images `opencv`, `C#` and `Diff` that may help. – alle_meije Sep 22 '15 at 10:19
  • Sorry but GetMat() is a method that I have wrote... it just about converting byte code into MAT nothing happeing there... about the diffrence I am going to edit the question – Humam Helfawi Sep 22 '15 at 10:27
  • Ah. OpenCV also has a `getMat()` function I assumed it was that. Leads me to think that either your getMat has a bug (no code so cannot comment) or the difference that you see comes from JPEG compression. I would not be surprised if those strips were multiples of 8x8 squares (hallmark JPEG feature) – alle_meije Sep 22 '15 at 11:31
  • Yes it seems like that cause I have just tried PNGs and every thing was correct and there is no differences at all – Humam Helfawi Sep 22 '15 at 11:33
  • 1
    Problem solved? You can test by making a jpeg from the PNG with the quality setting at 100%. I think that still does the DCT but does not discard any coefficients. Other than that jpeg decoding produces artifacts like those in your `Diff`picture. – alle_meije Sep 22 '15 at 11:39
  • @HumamHelfawi: you might wanna read some of this thread: https://groups.google.com/forum/#!topic/rec.photo.digital/yAxoW9HyHPQ/discussion – Amro Sep 22 '15 at 11:51
3

As others pointed out, if you want to read the image in OpenCV unmodified, set the flags to -1 in the C++ function, as in:

cv::Mat img = cv::imread("xxx.jpg", -1);

or use the defined enum value:

cv::Mat img = cv::imread("xxx.jpg", cv::IMREAD_UNCHANGED);

Also note that JPEG images are not guaranteed to be decoded bit-exactly the same by different decoders! It is preferable to use a lossless format like PNG instead (see #4148, #4046, ...).

Amro
  • 123,847
  • 25
  • 243
  • 454
  • @HumamHelfawi: see my note about lossy JPEG decoding – Amro Sep 22 '15 at 10:36
  • yes I did.. but changing the whole encoding is not an option or even I am not authorized to that in my current project – Humam Helfawi Sep 22 '15 at 10:37
  • what I meant is that when you want to compare your different implementations of the algorithm, use PNG images in the tests (which are lossless, think of them like ZIP files) – Amro Sep 22 '15 at 10:39
  • I see, it seems that the no easy solution .. I have to change the encoding or adding a library to the manged part.. thanks anyway:) – Humam Helfawi Sep 22 '15 at 10:40
  • @HumamHelfawi umm, both OpenCV `imread` (which uses `libpng` among others) and C# `System.Drawing.Bitmap` (which wraps GDI+) support decoding PNG out of the box... I don't see how it would be difficult to just switch input images from JPG to PNG! – Amro Sep 22 '15 at 10:48
  • I have library of millions jpg images that is distributed over the world it is hard to change them all! Oh! just a minute are you meaning some run-time conversation while reading it ???? – Humam Helfawi Sep 22 '15 at 10:51
  • 1
    If I understood this right, you have developed your algorithm in C# (some sort of feature detection) and you wanted to compare it to a C++ implementation. What I'm saying is that you should use PNG instead of JPEG images **for the comparison only**, to rule it out as a possibility in case you're seeing differences between the two implementations. Obviously there's no point in converting your 1M set of images, these are already stored and compressed in a lossy format, I'm just talking about the testing phase. – Amro Sep 22 '15 at 10:59
  • mmmm not exactly.. I developed my algorithm in native c++ and I want to use it on various platforms (iOS,Andriod and windows...). about windows part, the front-end is a c# application that I have to load the image using it. so it is not a testing problem – Humam Helfawi Sep 22 '15 at 11:04
  • ok I see. So let me get this right, you've now narrowed it down to having difference between 1) loading an image directly using `cv::imread` 2) loading an image in managed C#, passing the pointer to the raw data to native C++, which wraps it inside a `cv::Mat` header. Is that right? Can you test if that happens for both JPEG and PNG images? If that's the case, I would next look for bugs in the marshalling part of your code (your `getMat` method).. Also pay attention to the data types of the images involved (are your images 8-bit vs 16-bit, do you perform any grayscale to RGB conversion, ..) – Amro Sep 22 '15 at 11:25
  • PNGs are 100% the same – Humam Helfawi Sep 22 '15 at 11:30
  • 1
    @HumamHelfawi: aha, that's what I've initially suspected :) Different libraries will decode JPEG image slightly differently.. Nothing you can do about it. If you want bit-exactness, you have to consider other codecs. Besides if your algorithm you've developed give widely different results when you feed it images with these kind of differences, then IMO it's a problem.. You should loosen up the parameters a bit (like smoothing the input images, or using a slightly bigger window sizes when doing image filtering, that sort of things...) – Amro Sep 22 '15 at 11:39