Click here to Skip to main content
15,884,472 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I searched in C++, but unfortunately wasn't able to find any information on how I can integrate the following function using the external “C” declspec (dllexport) and call this function in C++. Here's what I tried:

C++
extern "C" declspec(dllexport) std::vector<std::vector<double>> 
cdecl PrepareFaceBank(std::string Path)


But unfortunately, I received the following error. I have no idea where to go from here. Thank you very much for your help in advance.

C++
extern "C" declspec(dllexport) std::vector<std::vector<double>> 
cdecl PrepareFaceBank(std::string Path)
{
    try
    {
        //load model (if it has been loaded anywhere else, just comment it)
        FaceModule = torch::jit::load(FaceModulePath);

        std::cout << "Model loaded successfully" << std::endl;
        //Disable grad for high performance because this is a pretrained model
        torch::NoGradGuard no_grad;
        //an array to save all persons tensor in it
        std::vector<torch::Tensor> embeddings;
        //iterate through facebank directory
        for (const auto& name : get_folderPath(Path))
        {
            std::cout << "name :" << name.filename() << ": " << '\n';
            
            //array to save all of the photos of each person
            std::vector<torch::Tensor> embs;
            //clear before iterating through all photos of each person
            embs.clear();
            //int a = 0;
            for (const auto& fileName : get_filenames(name))
            {
                //std::cout <<'\t' << fileName << std::endl;

                Mat image = imread(fileName);
                
                /* Display if needed:
                cv::namedWindow("Display window");// Create a window for display.
                cv::imshow("Display window", image);
                cv::waitKey(0);
                */
                
                embs.push_back(ProcessFrame(image));
                //empty cache 
                image.release();
                //how many photos each person has
                //std::cout << '\t' << a++ << std::endl;
            }

            //number of photos in database for this person
            //std::cout << "embs size: " << embs.size() << "\n";
            //convert vector to tensorlist and then calculate the Mean value 
            //for all of the photos of each person
            torch::Tensor embedding; // 1*512
            torch::TensorList tensor_list{ embs };
            embedding = torch::mean(torch::cat(tensor_list), 0);
            
            embeddings.push_back(embedding);
        }
        std::vector<double> EachPersonVec;
        std::vector<std::vector<double> > retValue;
        for (const auto& n : embeddings)
        {            
            EachPersonVec.clear();
            for (int i = 0; i < 512; i++)
            {
                EachPersonVec.push_back(n[i].item().to<double>());
            }
            
            retValue.push_back(EachPersonVec);
        }
        //number of persons in database
        std::cout << "embeddings size : " << embeddings.size() << "\n";
        
        return retValue;
    }
    catch (const std::exception& e)
    {
        std::cout << e.what() << std::endl;
    }
}


What I have tried:

C++
extern "C" declspec(dllexport) std::vector<std::vector<double>> cdecl PrepareFaceBank(std::string Path)
Posted
Updated 25-Jan-22 1:39am
v3
Comments
Richard MacCutchan 24-Jan-22 5:29am    
What error do you see and where is the C# code that is supposed to use this function?
Member 14980057 24-Jan-22 5:47am    
Severity Code Description Project File Line Suppression State
Error C2526 'PrepareFaceBank': C linkage function cannot return C++ class 'std::vector<std::vector<double,std::allocator<double>>,std::allocator<std::vector<double,std::allocator<double>>>>' detect-camera-demo D:\Project\Face\libfacedetection\example\Trian.cpp 233
Richard MacCutchan 24-Jan-22 8:31am    
Well that is quite clear. You cannot return C++ class types from standard C code. You also cannot pass those objects to a C# program.
Member 14980057 24-Jan-22 12:09pm    
Thanks, so what can I do? I must use std :: vector <std ::="" vector="" <double="">> in C # because my goal is to create a 512 vector and call it in C #. Can I convert a Jason file?

The purpose of this code that I wrote is to come to identify faces for people that the user wants to teach or add people to the folder photos so that I can recognize them later.
Richard MacCutchan 24-Jan-22 12:13pm    
The basic issue is that you cannot use C++ classes to pass data back to C# programs. So whatever the application and the library are doing, you need to find a data format that both can understand. You can find more useful information at Platform Invoke (P/Invoke) | Microsoft Docs[^].

You shouldnt return complex data between the runtimes but plain data types or byte arrays. Read my article with sample code to understand the basics and get it going.
 
Share this answer
 
Comments
Member 14980057 24-Jan-22 6:34am    
@KarstenK Thanks . I've done this before, but I will probably need to return the function I call in C # like std :: vector <std ::="" vector="" <double=""> Can you suggest a way? Thank you
As has already been said, simple data types are required for the transfer to a C - DLL.So you have to copy everything.
This is somewhat annoying and you also need a function at the end that cleans up the stuff.

C++
typedef struct FACESTRUCT {
    size_t n;
    FACESTRUCT *next;
    double *dat;
} FACETYPE;

extern "C" __declspec(dllexport) FACETYPE* PrepareFaceBankC(char* path);

std::vector<std::vector<double>> cdecl PrepareFaceBank(std::string Path);

FACETYPE* PrepareFaceBankC(char* path)
{
    std::vector<std::vector<double>> facebank;
    std::string mypath(path);
	FACETYPE *myhead = NULL, *mylst, *tmp;

	// first call the original function
    facebank = PrepareFaceBank(mypath);

	// then copy the result to simple datatypes
    size_t n = (facebank.size());  // number of elements in the vector

    for (size_t i = 0; i < n; i++) {
        // fetch next record 
        std::vector<double> mydat = facebank.at(i);
        // get mem to copy it
        tmp = (FACETYPE*)malloc(sizeof(FACETYPE) * n);
        tmp->next = NULL;
        tmp->n = mydat.size();

        // get mem for array of double
        tmp->dat = (double*)malloc(sizeof(double) * tmp->n);

        for (size_t k = 0; k < tmp->n; k++) {
            tmp->dat[k] = mydat.at(k);   // copy over double
        }

        if (myhead == NULL) {
            myhead = tmp; mylst = tmp;
        }
        else {
            mylst->next = tmp; mylst = tmp;
        }
    }
    return myhead;
}

This is just a rough draft to show how it might be done...
 
Share this answer
 
v4
Comments
Member 14980057 25-Jan-22 9:44am    
@merano99 thanks a lot . It is possible to write the full code of the function I wrote. I wanted to execute but unfortunately I did not know what to do.
merano99 25-Jan-22 10:37am    
I've just adjusted my suggestion a bit so that it compiles without errors.
Member 14980057 25-Jan-22 10:47am    
Thank you. Do I have to delete my function called PrepareFaceBank and replace your code with the following link or not? Do you have another suggestion?

https://gist.github.com/problemSolvingProgramming/70dbcfbbfe97e91241bcb8a47ae02579
merano99 25-Jan-22 14:59pm    
What does the compiler say?
Everything is required except for the one line with PrepareFaceBank(std::string Path). The prototype should actually be somewhere. However, it is not in the linked document.
In addition, you should write a function yourself that frees up the memory. For testing, it should run like this.
Member 14980057 26-Jan-22 0:46am    
Thanks but unfortunately I am a beginner I do not know exactly what to do I might ask you to send me an example of how to free up memory and write a function for this.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900