Chyba ve funkci "input" v cv::Mat formátu v C# a C++ použijte zařazování

0

Otázka

Mám DLL v C++, jehož funkce vstup je cv::Mat. To dává chybu, když se snažím volat tuto funkci s rámem zadání, které jsem obdržel od opencvsharp jako Mat v jazyce C#. Jak mohu opravit tento problém?

Jak mohu zápas Mat v C++ a Mat v C#, aby se zabránilo chybám?

Musím změnit funkci C++ nebo musím udělat ještě něco v C# pro přístup k datům uvnitř Mat jako vstup do C++ funkce?

C++ funkce:

extern "C" __declspec(dllexport)  vector<std::string> __cdecl ProcessFrame(cv::Mat image);



     vector<std::string> ProcessFrame(cv::Mat image)
    {
        int k = 0;
        cv::Mat croppedimage;
        cv::Mat finalcropped;
        string filename;
        Mat result_image;
        vector<string> listName;
        Module module = torch::jit::load("D:/Project/libfacedetection/example/converted.pt");


        int* pResults = NULL;


        unsigned char* pBuffer = (unsigned char*)malloc(DETECT_BUFFER_SIZE);
        if (!pBuffer)
        {
            fprintf(stderr, "Can not alloc buffer.\n");
            return listName;
        }


        TickMeter cvtm;
        cvtm.start();


        pResults = facedetect_cnn(pBuffer, (unsigned char*)(image.ptr(0)), image.cols, image.rows, (int)image.step);


        int face_num = (pResults ? *pResults : 0);

        if (*pResults != 0)
        {
            result_image = image.clone();

            for (int i = 0; i < face_num; i++)
            {
                try
                {
                    short* p = ((short*)(pResults + 1)) + 142 * i;
                    int confidence = p[0];
                    int x = p[1];
                    int y = p[2];
                    int w = p[3];
                    int h = p[4];

                    char sScore[256];


                    if (confidence >= 95)
                    {

                        //////////////////////////////////////////////////////////////////////////////
                        ////////////// Rotate and Crop
                        //////////////////////////////////////////////////////////////////////////////

                        short angle = Face_rotate(p);

                        cv::Rect rc = AlignCordinates(x, y, w, h, result_image.cols, result_image.rows);

                        cv::Rect myroi(x, y, w, h);
                        cv::Rect newroi((x - rc.x) / 2, (y - rc.y) / 2, w, h);

                        croppedimage = result_image(rc);
                        //imshow("1", croppedimage);

                        croppedimage = croppedimage.clone();
                        croppedimage = rotate(croppedimage, (angle));


                        //imshow("Rotate", croppedimage);


                        croppedimage = croppedimage(newroi).clone();

                        finalcropped = Mat(112, 112, croppedimage.type());
                        //imshow("dst", croppedimage);


                        cv::resize(croppedimage, finalcropped, finalcropped.size());
                        //imshow("resize", finalcropped);
                        Mat flipimage;
                        flip(finalcropped, flipimage, 1);



                        torch::Tensor img_tensor = torch::from_blob(finalcropped.data, { finalcropped.rows,finalcropped.cols ,3 }, torch::kByte);
                        torch::Tensor img_tensor_flip = torch::from_blob(flipimage.data, { flipimage.rows, flipimage.cols, 3 }, torch::kByte);

                        //torch::Tensor img_tensor_final = img_tensor + img_tensor_flip;

                        img_tensor = img_tensor.to(at::kFloat).div(255).unsqueeze(0);
                        img_tensor = img_tensor.sub_(0.5);
                        img_tensor = img_tensor.permute({ 0,3,1,2 });

                        img_tensor_flip = img_tensor_flip.to(at::kFloat).div(255).unsqueeze(0);
                        img_tensor_flip = img_tensor_flip.sub_(0.5);
                        img_tensor_flip = img_tensor_flip.permute({ 0,3,1,2 });



                        at::Tensor output_org = module.forward({ img_tensor }).toTensor();
                        at::Tensor output_flip = module.forward({ img_tensor_flip }).toTensor();

                        std::vector<double> out;


                        for (int i = 0; i < 512; i++)
                        {
                            out.push_back(output_org[0][i].item().to<double>() + output_flip[0][i].item().to<double>());
                        }

                        out = l2_norm(out);




                        std::ifstream file("D:/Project/libfacedetection/example/facebank.json");
                        json object = json::parse(file);




                        double min_dis = 1000;
                        std::string min_name;

                        for (auto& x : object.items()) {
                            auto dataSize = std::size(x.value());

                            std::vector<double> vec1 = x.value();



                            double res = cosine_similarity_vectors(vec1, out);
                            res = (res * -1) + 1;
                            //double res = distance(vec1, out);


                            if (res <= min_dis) {
                                min_dis = res;
                                min_name = x.key();
                            }
                        }




                        std::cout << "One Frame   " << min_name << " " << min_dis << std::endl;


                        if (min_dis < 0.8) {

                            listName.push_back(min_name);
                        }
                        else
                        {
                            listName.push_back("Unknown");
                        }
                    }

                    else
                    {
                        listName.push_back("conf_low");

                    }


                }
                catch (const std::exception& ex)
                {
                    cout << "NASHOD" << endl;

                    //std::cout << ex.what();
                }



            }
        }


        else
        {
            listName.push_back("No_Body");
        }
        cvtm.stop();



        //printf("time = %gms\n", cvtm.getTimeMilli());
        //printf("%d faces detected.\n", (pResults ? *pResults : 0));
        free(pBuffer);

        return listName;
    }

C#:

   [DllImport("detect-camera.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern List<string> ProcessFrame(Mat image);
        private void button1_Click(object sender, EventArgs e)
        {
            Mat image = Cv2.ImRead("D:/c++/ImportCallFunction/ImportCallFunction/123.jpg");

            List<string> facelist = ProcessFrame(image);


            foreach (var item in facelist)
            {
                listBox1.Items.Add(item);
            }

Chyba:

System.Runtime.InteropServices.MarshalDirectiveException: 'Cannot marshal 'return value': Generic types cannot be marshaled.'

Error Image

c# image-processing marshalling opencv
2021-11-23 07:10:38
3
1

Chyba, které jste se setkali se nevztahuje na typ parametru cv::Mat ale návratový typ funkce, která je deklarována jako vector<std::string>.

První, poznámka o parametr typu: možná budete chtít, aby to const cv::Mat& aby se zabránilo kopírování celé matice do funkce na každý rám. Takže to bude jako:

    std::vector<std::string> ProcessFrame(const cv::Mat& image)

Budete také potřebovat funkci wrapper, který je napsán v C++/CLI a slouží jako rozhraní mezi kód C# a C++ kódu. Provádí vlastní seřaďovací požadované funkce jak pro vstupní argument a vrátí hodnotu. Všimněte si, že byste měli umístit wrapper funkce sestavit jednotku, která je kompilována s /clr (povolit C++/CLI). Původní (nativní) funkce nemusí být sestaven s /clr možnost. Obal deklarace funkce by mohla vypadat takto:

System::Collections::Generic<System::String>^ ProcessFrameWrapper(
    OpenCvSharp::Mat^ mat);

V C# kódu, budete volat funkci wrapper nyní:

    [DllImport("detect-camera.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern List<string> ProcessFrameWrapper(Mat image);
    // ...
            List<string> facelist = ProcessFrameWrapper(image);

Abychom to shrnuli, budete potřebovat tyto soubory:

DetectCamera.h:

// ...
std::vector<std::string> ProcessFrame(const cv::Mat& image);
// ... other native declarations

DetectCamera.cpp:

// ...

std::vector<std::string> ProcessFrame(const cv::Mat& image)
{
    // actual function implementation
}

// ... other function implementations

DetectCameraWrapper.h:

// ...
System::String^ ProcessFrameWrapper(OpenCvSharp::Mat^ mat);
// ... other wrapper functions ...

DetectCameraWrapper.cpp:

// ...

System::Collections::Generic<System::String>^ ProcessFrameWrapper(
    OpenCvSharp::Mat^ mat)
{
    var names = gcnew System::Collections::Generic<System::String>();
    auto matNativePtr = 
        reinterpret_cast<cv::Mat*>(marshal_as<void*>(mat->CvPtr));
    auto namesNative = ProcessFrame(*matNativePtr);
    for (const auto& nameNative : namesNative)
    {
        names->Add(marshal_as<System::String^>(nameNative));
    }
    return names;
}

// ... other wrapper function implementations

DetectCamera.cs:

    // ... 
    [DllImport("detect-camera.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern List<string> ProcessFrameWrapper(Mat image);

    private void button1_Click(object sender, EventArgs e)
    {
        Mat image = Cv2.ImRead("D:/c++/ImportCallFunction/ImportCallFunction/123.jpg");
        List<string> facelist = ProcessFrameWrapper(image);
        foreach (var item in facelist)
        {
            listBox1.Items.Add(item);
        }
    // ...

Tyto soubory mohou být organizovány ve dvou nebo tří samostatných projektů:

  • DetectCamera.cs je umístěn v C# projekt - výzva to ProjCSharp.
  • DetectCameraWrapper.cpp je umístěn v C++/CLI DLL projektu (s /clr) - hovor je ProjWrapper.
  • DetectCamera.cpp může být umístěna buď v rámci téhož projektu ProjWrapper, nebo v samostatné native library project (.lib) - hovor je ProjNative. Já doporučuji to druhé. Pokud je umístěn v samostatné knihovně (ProjNative), DLL projektu ProjWrapper musí být spojeny do knihovny ProjNative.

Důvod, proč jsem doporučujeme uvedení nativního kódu uvnitř samostatné knihovny je modularita a kodování.

2021-11-23 19:56:39

díky . Můžete mi říct více o C ++ / CLI nebo clr v aplikaci Visual Studio 2019 a kde to mám aktivovat? A to je kód, který jsem napsal pro C #, ne? Žádný problém ?
reza

@reza povolit C++/CLI (/clr) pro projekt v MSVS2019, otevřete vlastnosti projektu, zvolte All Configurations pro Configurationvyberte All Platforms pro Platform, přejděte na Configuration Properties > General v levém podokně a v pravém podokně, nastavte na 'Podporu Runtime Společný Jazyk` k /clr. HTH.
misoboute
1

Jsem ne vzpomenout na Interop a nikdy nebyl expert, i když jsem dělal hodně pokročilé věci.

Na radu od @misoboute je používat CLI , které jsem nikdy nepoužil, tak nevím. To je jistě možné, že a jak mu vysvětlil, jako je C++ pochopí obecný C# seznam a být schopen shromáždit úspěšně.

Ale zdá se mi, že to NENÍ váš problém. Chcete jednoduše vrátit spoustu řetězců. To opravdu nemusí být definován jako List<string>. To může být definováno jako string[], pole řetězec.

Tak se pokusím

[DllImport("detect-camera.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern string[] ProcessFrame(Mat image);

A pak, v mé C++ kód, vrátit pole řetězec reprezentující vektor řetězec jako pole:

Jak převést vektorové pole

Promiň, ale to je vše, co mám pro tebe. Je možné, že po tomto, budete hit jiné problémy.

2021-11-28 20:19:54
1

Máte dvě "standardní" způsobů, jak se dostat z C++ do C#.

První je C++/CLI. V tomto případě budete stavět C++/CLI knihovny, která trvá std::vectorstd::string a konverzi do Systému::vectorSystem::string. Pak můžete jej použít volně jako Systém.String[] v jazyce C#.

Druhý je COM. Tam můžete vytvořit COM rozhraní, které vrací SAFEARRAY obsahující řetězec BSTR. Toto rozhraní COM je pak vytvořena i když Systém.Runtime.InteropServices v C#. SAFEARRAY je pak Objekt [], které mohou být přejímané na jeden řetězec objektů.

Zařízení pro zatížení C rozhraní do C# je v podstatě omezeno na C. C++ se nezdaří a Pete stanoví, že "nestandardní" přístup. (To funguje velmi dobře, jen ne to, co PANÍ chce, abys udělal.)

c++ :

extern "C" __declspec(dllexport) LPSAFEARRAY ListDevices();

LPSAFEARRAY ProcessFrame(int width, int height, unsigned char* data)
{
    CComSafeArray<BSTR> a(listName.size()); // cool ATL helper that requires atlsafe.h

    std::vector<std::string>::const_iterator it;
    int i = 0;

    for (it = listName.begin(); it != listName.end(); ++it, ++i)
    {
        // note: you could also use std::wstring instead and avoid A2W conversion
        a.SetAt(i, A2BSTR_EX((*it).c_str()), FALSE);
    }

return a.Detach();

}

c#:

[DllImport("detectcameratest.dll")]
        [return: MarshalAs(UnmanagedType.SafeArray)]
        private extern static string[] ProcessFrame2(int width, int height, IntPtr data);
        private void button2_Click(object sender, EventArgs e)
        {
            Mat img = Cv2.ImRead(@"C:\Users\Subtek\source\repos\WindowsFormsApp17\WindowsFormsApp17\bin\x64\Debug\1.jpg");

            var facelist = ProcessFrame2(img.Width, img.Height, img.Data);


            foreach (var s in facelist)
            {
                listBox1.Items.Add(s);
            }
2021-11-30 11:05:07

V jiných jazycích

Tato stránka je v jiných jazycích

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................