takuya-takeuchi / DlibDotNet

Dlib .NET wrapper written in C++ and C# for Windows, MacOS, Linux and iOS
MIT License
492 stars 135 forks source link

Error using Marshal.Copy method #112

Closed omdxp closed 5 years ago

omdxp commented 5 years ago

Summary of your issue

Well, I was trying your example WebcamFacePose and then I got an error while using Marshal.Copy method that it said: "Argument 1 : cannot convert from 'System.Array' to 'int[]'"

Environment

.NET Framework 4.6.1

takuya-takeuchi commented 5 years ago

It is similar with #87?

takuya-takeuchi commented 5 years ago

@Omar-Belghaouti Does it occur everytime?

If the 1st argument of Marshal.Copy is Int32[], 2nd argment must be Int32. https://docs.microsoft.com/ja-jp/dotnet/api/system.runtime.interopservices.marshal.copy?view=netframework-4.6.1

But in https://github.com/takuya-takeuchi/DlibDotNet/blob/master/examples/WebcamFacePose/Program.cs#L52 , 1st is IntPtr and 2nd is byte[]. It should occur compile error before executing.

omdxp commented 5 years ago

No it's not throwing an exception, it's not running at all. When I use temp.Data as an argument it get me that error above.

The thing is I have a program written in python that use dlib library to detect hand with a trained model as below:

import dlib
import cv2

detector = dlib.simple_object_detector('hand.svm')

cv2.namedWindow('frame', cv2.WINDOW_NORMAL)

cap = cv2.VideoCapture(0)
rscale = 2.0

while (True):
    ret, frame = cap.read()
    width, height, _ = frame.shape

    ft = cv2.resize(frame, (int(frame.shape[1] / rscale), int(frame.shape[0] / rscale)))
    dets = detector(ft)

    for d in dets:
        cv2.rectangle(frame, (int(d.left()*rscale),
                              int(d.top()*rscale)),
                              (int(d.right()*rscale),
                              int(d.bottom()*rscale)),
                              (255, 0, 0), 5)

    cv2.imshow('frame', frame)

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

And I want to do it with DlibDotNet

omdxp commented 5 years ago

Is this a way to avoid that error?

var temp = new Mat();
                    capture.Read(temp);

                    byte[] data = (byte[])temp.Data;
                    var array = new byte[temp.Width * temp.Height * temp.ElementSize];

                    int size = Marshal.SizeOf(data[0]) * data.Length;

                    IntPtr pnt = Marshal.AllocHGlobal(size);

                    try
                    {
                        Marshal.Copy(data, 0, pnt, data.Length);

                        Marshal.Copy(pnt, array, 0, array.Length);
                    }
                    finally
                    {
                        Marshal.FreeHGlobal(pnt);
                    }
takuya-takeuchi commented 5 years ago
byte[] data = (byte[])temp.Data;

Is it correct? It must be compile error.

omdxp commented 5 years ago

No it execute normally

takuya-takeuchi commented 5 years ago

Wait. What is Mat? I think Mat does not have ElementSize.

omdxp commented 5 years ago

I forgot to tell you that I'm using EmguCV wrapper not OpenCVSharp

takuya-takeuchi commented 5 years ago

Ops, I have never used EmguCV. But EmguCV.Mat look like to have DataPointer property. http://www.emgu.com/wiki/files/3.1.0/document/html/a4426997-e646-4f87-8ce7-793a6c62fc1b.htm

It may help you.

Marshal.Copy(temp.DataPointer, array, 0, array.Length);
omdxp commented 5 years ago

Thank you, I'll try it and tell you the results

takuya-takeuchi commented 5 years ago

Or http://www.emgu.com/wiki/files/3.1.0/document/html/3fbad597-8949-3c0e-1477-a41a6f3a330c.htm

omdxp commented 5 years ago

I tried the first method temp.DataPointer and it works fine

omdxp commented 5 years ago

Could you add an example of hand detection using DlibDotNet the way as I did it in Python?

omdxp commented 5 years ago

Both methods works fine

takuya-takeuchi commented 5 years ago

I may be able to write sample code to detect hand. But

Where did you get hand.svm file from? If license of model file is unknown, I can not accept your request?

omdxp commented 5 years ago

Here's the link : https://github.com/TahaAnwar/opensource It is the file "myhanddetector2.svm"

takuya-takeuchi commented 5 years ago

simple_object_detector is object_detector<scan_fhog_pyramid<pyramid_down<6>>>. You can refere examples\FHogObjectDetector\Program.cs.

// Then you can recall it using the deserialize() function.
using (var tmp = new ScanFHogPyramid<PyramidDown, DefaultFHogFeatureExtractor>(6))
using (var detector2 = new ObjectDetector<ScanFHogPyramid<PyramidDown, DefaultFHogFeatureExtractor>>(tmp))
    detector2.Deserialize("face_detector.svm");
omdxp commented 5 years ago

Okay thanks, I'll try it. I really appreciate your help

omdxp commented 5 years ago

Here's what 's happening, when I used Deserialize method, the Operator method gives me this compile error:

The type arguments for method 'ObjectDetector<ScanFHogPyramid<PyramidDown, DefaultFHogFeatureExtractor>>.Operator<U>(Matrix<U>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

What should the type argument be?

takuya-takeuchi commented 5 years ago

ObjectDetector<ScanFHogPyramid<PyramidDown, DefaultFHogFeatureExtractor>>.Operator(Matrix matrix) accept Matrix. U should be struct. eg; byte, int , RgbPixel.

detector2.Operator(new Matrix<byte>());

You can pass image data.

omdxp commented 5 years ago

It's done. I don't know if this is the perfect code for this but can you take look?

capture = new VideoCapture(0);
using (var win = new ImageWindow())
                {
                    using (var tmp = new ScanFHogPyramid<PyramidDown, DefaultFHogFeatureExtractor>(6))
                    using (var detector = new ObjectDetector<ScanFHogPyramid<PyramidDown, DefaultFHogFeatureExtractor>>(tmp))
                    {
                        detector.Deserialize("hand.svm");
                        while (!win.IsClosed())
                        {
                            var temp = new Mat();
                            capture.Read(temp);

                            var array = new byte[temp.Width * temp.Height * temp.ElementSize];
                            Marshal.Copy(temp.DataPointer, array, 0, array.Length);

                            using (var cimg = Dlib.LoadImageData<RgbPixel>(array, (uint)temp.Height, (uint)temp.Width, (uint)(temp.Width * temp.ElementSize)))
                            {
                                // Detect hands
                                var dets = detector.Operator(new DlibDotNet.Matrix<RgbPixel>(cimg));

                                // Display it all on the screen
                                win.ClearOverlay();
                                win.SetImage(cimg);
                                win.AddOverlay(dets, new RgbPixel { Red = 255 });
                            }

                        }
                    }
                }
omdxp commented 5 years ago

But I noticed something, it is very slow comparing to my python program. Why is that?

takuya-takeuchi commented 5 years ago
var dets = detector.Operator(new DlibDotNet.Matrix<RgbPixel>(cimg));

you should use using statement for Matrix.

takuya-takeuchi commented 5 years ago

You did not use GPU? DlibDotNet.Native does not use Intel MKL. Python dlib could use it. So if use on cpu, DlibDotNet works on low performance. Please refer https://github.com/takuya-takeuchi/DlibDotNet/issues/35.

You can build DlibDotNet.Native by using Intel MKL.

omdxp commented 5 years ago

Yes, I've used it on CPU, Thanks for your help.