4

I created a C DLL out of my C++ class which uses OpenCV for image manipulations and want to use this DLL in my C# application. Currently, this is how I have implemented it:

#ifdef CDLL2_EXPORTS
#define CDLL2_API __declspec(dllexport)
#else
#define CDLL2_API __declspec(dllimport)
#endif

#include "../classification.h" 
extern "C"
{
    CDLL2_API void Classify_image(unsigned char* img_pointer, unsigned int height, unsigned int width, char* out_result, int* length_of_out_result, int top_n_results = 2);
    //...
}

C# related code:

DLL Import section:

//Dll import 
[DllImport(@"CDll2.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern void Classify_Image(IntPtr img, uint height, uint width, byte[] out_result, out int out_result_length, int top_n_results = 2);

The actual function sending the image to the DLL:

//...
//main code 
private string Classify(int top_n)
{
    byte[] res = new byte[200];
    int len;
    Bitmap img = new Bitmap(txtImagePath.Text);
    BitmapData bmpData = img.LockBits(new Rectangle(0, 0, img.Width, img.Height), 
                                      ImageLockMode.ReadWrite,  
                                      PixelFormat.Format24bppRgb);
    Classify_Image(bmpData.Scan0, (uint)bmpData.Height, (uint)bmpData.Width, res, out len, top_n);
    img.UnlockBits(bmpData); //Remember to unlock!!!
    //...
}

and the C++ code in the DLL :

CDLL2_API void Classify_Image(unsigned char* img_pointer, unsigned int height, unsigned int width,
                              char* out_result, int* length_of_out_result, int top_n_results)
    {
        auto classifier = reinterpret_cast<Classifier*>(GetHandle());

        cv::Mat img = cv::Mat(height, width, CV_8UC3, (void*)img_pointer, Mat::AUTO_STEP);

        std::vector<Prediction> result = classifier->Classify(img, top_n_results);

        //...
        *length_of_out_result = ss.str().length();
    }

This works perfectly with some images but it doesn't work with others, for example when I try to imshow the image in the Classify_Image, right after being created from the data sent by C# application, I am faced with images like this :

Problematic example:

enter image description here

Fine example:

enter image description here

13
  • 1
    it looks like the stride/pitch is incorrect e.g. the step arg will align the memory such that each row fits on some byte-alignment for performance reasons. This is why the next pixel is not aligned, you need to look at what the step/stride size is and this probably needs to be passed through so that when it accesses the subsequent row it uses the correct offset in memory, I can't suggest anything else as I code purely in C++ with openCV but this is your issue here wrt the image error Commented Aug 17, 2017 at 15:11
  • 1
    I've found here something relevant: msdn.microsoft.com/en-us/library/… I don't code in c# but it looks like you should check this, it's likely it's not the same as your image width you'll find. It may be image width * num bytes per channel * num of channels + padding. The doc states the number will be 4-byte aligned Commented Aug 17, 2017 at 15:15
  • 1
    Your problematic image has a width of 1414, the image is 24-bit with 3 * 8-bit colour channels, if we calc the number of bytes: 1414 * 3 = 4242 bytes if we then divide by 4 4242/4=1060.5 you can see that we are left with 0.5 which means that the stride will be set to 4244 because 0.5 * 4 bytes = 2 bytes, please check if this is the case Commented Aug 17, 2017 at 15:25
  • 1
    You need to determine the bit depth and number of colour channels from the bitmap, normally they will be something that tells you the packing, such as yuv, rgb, greyscale for example you need to get number of bits in this case 24 and divide by the number of colour channels which would be three to get 8 bits per channel. I'm in the middle of cooking so can't post anything meaningful at the moment Commented Aug 17, 2017 at 16:56
  • 1
    I'm not sure that incrementally updating the question to present a new problem is a good thing for SO, I'd close this issue and open a new question that references this question. Besides that, where is the code that calcs GetResizeHeight? also the docs for setResolution msdn.microsoft.com/en-us/library/… state you're supposed to pass the resolution in dots per inch, rather than pixel values, this could be your confusion. Additionally you should just use openCV to resize and just pass some scaled resolution size like half height/width Commented Aug 18, 2017 at 7:56

1 Answer 1

3

Your initial issue is to do with what is called stride or pitch of image buffers. Basically for performance reasons pixel row values can be memory aligned, here we see that in your case it's causing the pixel rows to not align because the row size is not equal to the pixel row width.

The general case is:

resolution width * bit-depth (in bytes) * num of channels + padding

in your case the bitmap class state:

The stride is the width of a single row of pixels (a scan line), rounded up to a four-byte boundary

So if we look at the problematic image, it has a resolution of 1414 pixel width, this is a 8-bit RGB bitmap so if we do the maths:

1414 * 1 * 3 (we have RGB so 3 channels) = 4242 bytes

So now divide by 4-bytes:

4242 / 4 = 1060.5

So we are left with 0.5 * 4 bytes = 2 bytes padding

So the stride is in fact 4244 bytes.

So this needs to be passed through so that the stride is correct.

Looking at what you're doing, I'd pass the file as memory to your openCV dll, this should be able to call imdecode which will sniff the file type, additionally you can pass the flag cv::IMREAD_GRAYSCALE which will load the image and convert the grayscale on the fly.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks a lot. here is the new question by the way, I tried to be thorough : stackoverflow.com/questions/45753429/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.