【Opencv】在Visual Studio 2022和UE5上配置OpenCV的详细步骤

一、下载并安装OpenCV
访问OpenCV官网:首先,你需要访问OpenCV的官方网站(OpenCV官网),在“Releases”部分找到适合你的操作系统的版本进行下载。对于Windows用户,通常会选择Windows预编译的二进制文件。
下载并安装:下载适合你系统的OpenCV版本后,按照安装向导进行安装。注意选择一个不包含中文和特殊字符的路径,以避免潜在的问题。
二、配置系统环境变量
打开系统属性:在Windows搜索栏中输入“系统属性”,然后选择“打开”以进入系统属性界面。
编辑环境变量:点击“高级”选项卡下的“环境变量”按钮。在“系统变量”区域找到名为“Path”的变量,选择它并点击“编辑”。
添加OpenCV路径:点击“新建”并添加OpenCV的bin目录路径到你的Path变量中。这个路径通常类似于C:\opencv\build\x64\vc16\bin(注意替换为你的实际安装路径)。
保存并重启:点击“确定”保存更改,并重启你的计算机以确保环境变量生效。
三、在Visual Studio中配置项目属性
创建或打开项目:在Visual Studio 2022中创建一个新的C++项目或打开一个现有的项目。
配置项目属性:
右键点击项目名称,选择“属性”。
在左侧导航栏中,选择“VC++目录”。
在“包含目录”中添加OpenCV的include目录路径,如C:\opencv\build\include和C:\opencv\build\include\opencv2。
在“库目录”中添加OpenCV的lib目录路径,如C:\opencv\build\x64\vc16\lib(注意根据你的Visual Studio版本和OpenCV构建配置选择正确的目录)。
配置链接器:
在项目属性中,选择“链接器”->“输入”。
在“附加依赖项”中添加你需要的OpenCV库文件,如opencv_worldXXXd.lib(XXX是版本号,d表示debug版本,对于release版本则不需要d)。注意,如果你没有使用opencv_world这样的统一库,而是分别链接了不同的模块,那么你需要添加相应模块的库文件。
四、编写和测试代码
编写代码:在你的C++项目中编写使用OpenCV的代码。例如,一个简单的读取并显示图片的代码示例如下:

#include <opencv2/opencv.hpp>  
using namespace cv;  
 
int main() {  
    Mat img = imread("G:\\111111111111111111111111111\\213213.jpg"); // 替换为你的图片路径  
    if (img.empty()) {  
        std::cerr << "Error: Loading image" << std::endl;  
        return -1;  
    }  
    imshow("Image Display", img);  
    waitKey(0);  
    return 0;  
}

编译并运行:编译你的项目并运行它。如果一切配置正确,你应该能够看到你的图片在一个窗口中显示。
注意
确保你的OpenCV版本与你的Visual Studio版本兼容。
如果你在配置过程中遇到任何问题,检查你的路径设置是否正确,特别是环境变量和项目属性中的路径。
如果你使用的是预编译的OpenCV库,确保它们是为你的Visual Studio版本和Windows SDK版本构建的。如果不是,你可能需要从源代码自行编译OpenCV。

2cv::imshow(“Original Image”, img); 严重性 代码 说明 项目 文件 行 禁止显示状态 详细信息 错误 LNK2019 无法解析的外部符号 “void __cdecl cv::imshow(class std::basic_string<char,struct std::char_traits,class std::allocator > const &,class cv::debug_build_guard::_InputArray const &)” (?imshow@cv@@YAXAEBV? b a s i c s t r i n g @ D U ? basic_string@DU? basicstring@DU?char_traits@D@std@@V?$allocator@D@2@@std@@AEBV_InputArray@debug_build_guard@1@@Z),函数 main 中引用了该符号 opencv1 G:\VS2022_programs\Opencv_0726_VS2022\opencv1\opencv1\opencv1.obj 1

答:错误 LNK2019 表示链接器无法找到在代码中引用的某个函数或符号的实现。在你的情况下,链接器无法找到 cv::imshow 函数的实现,这通常是因为OpenCV库没有被正确地链接到你的项目中。

这里有几个步骤可以帮助你解决这个问题:

确认OpenCV库文件已被添加到项目中:
确保你已经将OpenCV的库文件(.lib 文件)添加到了项目的链接器输入中。这通常在项目的属性设置中的“链接器”->“输入”->“附加依赖项”中完成。
检查库文件的路径:
在项目的属性中,确保“VC++目录”->“库目录”中包含了OpenCV库文件的路径。这样,链接器就能在这些目录中查找库文件。
确认使用的是正确的库文件:
如果你使用的是OpenCV的Debug版本,那么你需要链接到带有d后缀的库文件(例如opencv_world451d.lib),而对于Release版本,则应该链接不带d后缀的库文件(例如opencv_world451.lib)。
检查项目配置:
确保你的项目配置(Debug或Release)与你链接的库文件配置相匹配。
重新生成项目:
在Visual Studio中,尝试清理并重新生成你的项目。这可以通过“生成”菜单中的“清理解决方案”和“重新生成解决方案”来完成。
检查OpenCV的安装:
如果以上步骤都不能解决问题,可能需要检查你的OpenCV安装是否完整或是否有损坏。你可以尝试重新安装OpenCV,或者从其他来源获取库文件。
检查Visual Studio的版本和更新:
确保你的Visual Studio和所有相关的组件都已更新到最新版本。
检查项目设置中的字符集:
在某些情况下,如果你的项目设置为使用多字节字符集(MBCS),而OpenCV库是使用Unicode字符集编译的,这也可能导致链接问题。尝试将项目的字符集设置为“使用Unicode字符集”。
如果以上步骤仍然无法解决问题,你可能需要查看更详细的错误信息或日志,以获取更多关于为什么链接器无法找到 cv::imshow 的线索。此外,确保你的OpenCV版本与你的Visual Studio版本兼容。如果你使用的是较新版本的Visual Studio,可能需要从源代码编译OpenCV或使用预编译的二进制文件,这些二进制文件是为较新版本的Visual Studio编译的。
如果是UE5进行配置,那么除了上面的步骤(除去链接库更改外,还需要更改.Build.cs文件),如下:

// Copyright Epic Games, Inc. All Rights Reserved.

using System.IO;
using UnrealBuildTool;

public class Ceshi_0726 : ModuleRules
{
	public Ceshi_0726(ReadOnlyTargetRules Target) : base(Target)
	{
		PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
	
		PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });
        // 假设你的静态库头文件在 Source/ThirdParty/MyLib/Include 下  
        // 静态库文件在 Source/ThirdParty/MyLib/Lib 目录下(假设为Windows平台)  
        string ThirdPartyPath = Path.GetFullPath(Path.Combine(ModuleDirectory, "..", "ThirdParty"));
        string LibIncludePath = Path.Combine(ThirdPartyPath, "MyLib", "Include");
        string LibPath = Path.Combine(ThirdPartyPath, "MyLib", "Lib", Target.Platform.ToString());
        // 添加包含目录  
        PublicIncludePaths.AddRange(new string[] { LibIncludePath });
        PublicIncludePaths.AddRange(new string[] { LibIncludePath ,"opencv2"});
        PublicIncludePaths.AddRange(new string[] { LibIncludePath, "opencv2" ,"core"});
        PublicIncludePaths.AddRange(new string[] { LibIncludePath, "opencv2", "core" , "cuda" });
        // 静态库文件,注意这里假设库文件名为 MyLib.lib(Windows平台)  
        // 对于其他平台,如Linux或Mac,你可能需要调整文件名和路径  
        if (Target.Platform == UnrealTargetPlatform.Win64)
        {
            PublicAdditionalLibraries.Add(Path.Combine(LibPath, "StaticLib1.lib"));
           // PublicAdditionalLibraries.Add(Path.Combine(LibPath, "opencv1.lib"));
            PublicAdditionalLibraries.Add(Path.Combine(LibPath, "opencv_world4100d.lib"));
           // PublicAdditionalLibraries.Add(Path.Combine(LibPath, "opencv_world4100d.lib"));
        }

        // 如果有多个静态库或不同平台的库,可以按上述方式继续添加  

        // Uncomment if you are using Slate UI  
        // PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });  

        // Uncomment if you are using online features  
        // PrivateDependencyModuleNames.Add("OnlineSubsystem");  

        // 注意:对于动态链接库(DLLs),你可能需要使用PublicLibraryPaths和PublicDelayLoadDLLs  


        PrivateDependencyModuleNames.AddRange(new string[] {  });

		// Uncomment if you are using Slate UI
		// PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
		
		// Uncomment if you are using online features
		// PrivateDependencyModuleNames.Add("OnlineSubsystem");

		// To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true
	}
}

但是由于opencv的代码需要一个while(1),所以放到UE里并不适用,不如在外部将opencv项目写成一个udp服务器,把UE项目写成udp客户端。

下面的代码是udp传输面部位置的代码:

#include <opencv2/opencv.hpp>  
#include <iostream>  
#include <memory>
#include <winsock2.h>  
#include <string>  
#include <thread>        // 用于多线程  
#include <chrono>        // 用于时间操作  
#include <mutex>
#include <ws2tcpip.h>
std::mutex mtx;  // 用于保护 abcd 和 pShared

#pragma comment(lib, "ws2_32.lib") // 链接Winsock库  
#define PORT 7509  
#define BUFSIZE 1024  
#define SEND_INTERVAL 1000  // 发送间隔时间,单位毫秒  
WSADATA wsaData;
SOCKET sock;
struct sockaddr_in serverAddr, clientAddr, clientAddr2;
int bytesReceived;
char buffer[BUFSIZE];
int addrLen;
class EMA {
private:
    double alpha;
    double previous;

public:
    EMA(double a) : alpha(a), previous(0.0) {}

    double update(double newValue) {
        double ema = alpha * newValue + (1 - alpha) * previous;
        previous = ema;
        return ema;
    }
};

void sendMessageContinuously(SOCKET sock, sockaddr_in clientAddr, std::shared_ptr<std::string> pShared) {
    sockaddr_in destAddr;
    memset(&destAddr, 0, sizeof(destAddr)); // 初始化结构体  
    destAddr.sin_family = AF_INET;
    destAddr.sin_port = htons(7503); // 假设你希望发送到这个端口  
    // 使用inet_pton将IP地址字符串转换为二进制形式  
    if (inet_pton(AF_INET, "127.0.0.1", &destAddr.sin_addr) <= 0) {
        // 处理错误  
      //  std::cerr << "Invalid address/Address not supported\n";
        return;
    }

    while (true) {
        
        addrLen = sizeof(clientAddr);
        //sendto(sock, pShared->c_str(), pShared->length(), 0, (struct sockaddr*)&clientAddr, addrLen);//这个要加上接收哪个才有用
        //sendto(sock, pShared->c_str(), pShared->length(), 0, (struct sockaddr*)&clientAddr, sizeof(clientAddr));//这个不用收,但是地址是0.0.0.0
        sendto(sock, pShared->c_str(), pShared->length(), 0, (struct sockaddr*)&destAddr, sizeof(destAddr));
        //  std::cout << "Continuous message sent.:::"<< pShared->c_str() <<std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
}


int main() {

    EMA xEMA(0.1);  // 假设alpha为0.1  
    EMA yEMA(0.1);

    // 初始化摄像头  
    cv::VideoCapture capture(0);
    // 检查摄像头是否成功打开  
    if (!capture.isOpened()) {
        std::cerr << "Error: Unable to open camera\n";
        return -1;
    }
    // 加载人脸检测的Haar级联分类器  
    cv::CascadeClassifier face_cascade;
    //   if (!face_cascade.load("E:\\Program Files\\Opencv\\opencv\\build\\etc\\haarcascades\\haarcascade_frontalface_default.xml")) {
    if (!face_cascade.load("E:\\Program Files\\Opencv\\opencv\\sources\\data\\haarcascades_cuda\\haarcascade_frontalface_default.xml")) {
        std::cerr << "Error: Unable to load face cascade classifier\n";
        return -1;
    }
    // 创建一个窗口  
    cv::namedWindow("Camera Feed with Faces", cv::WINDOW_AUTOSIZE);
    cv::Mat frame, gray;




    // 初始化Winsock  
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
        std::cerr << "Winsock初始化失败,错误代码: " << WSAGetLastError() << std::endl;
        return 1;
    }

    // 创建UDP socket  
    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) {
        std::cerr << "创建socket失败,错误代码: " << WSAGetLastError() << std::endl;
        WSACleanup();
        return 1;
    }
    std::cout << "Socket创建成功。\n";

    // 设置服务器地址结构  
    clientAddr.sin_family = AF_INET;
    clientAddr.sin_addr.s_addr = INADDR_ANY;
    clientAddr.sin_port = htons(7503);

    // 设置服务器地址结构  
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = INADDR_ANY;
    serverAddr.sin_port = htons(7500);

    // 绑定socket  
    if (bind(sock, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
        std::cerr << "绑定失败,错误代码: " << WSAGetLastError() << std::endl;
        closesocket(sock);
        WSACleanup();
        return 1;
    }

    std::cout << "绑定成功。\n";
    const char* p;
    //std::shared_ptr<std::string> pShared = std::make_shared<std::string>("p$x:12.234632$y:54.812842$z:60.3453\n");
    std::shared_ptr<std::string> pShared = std::make_shared<std::string>("p$x:20$y:54$z:60.3453\n");


    // 创建并启动发送线程  
    std::thread senderThread(sendMessageContinuously, sock, clientAddr, pShared);

    int abc = 0;
   // int x, y;
    double x, y;
   
    
    while (true) {



        // 从摄像头捕获一帧  
        capture >> frame;

        // 如果帧是空的,跳出循环  
        if (frame.empty()) {
            std::cerr << "Error: Couldn't receive a frame (stream end?). Exiting ..." << std::endl;
            break;
        }

        // 转换为灰度图,因为人脸检测通常在灰度图上进行  
        cvtColor(frame, gray, cv::COLOR_BGR2GRAY);

        // 检测人脸  
        std::vector<cv::Rect> faces;
        face_cascade.detectMultiScale(gray, faces, 2, 3, 0 | cv::CASCADE_SCALE_IMAGE, cv::Size(30, 30));


        // 在原图上绘制矩形框  
        for (size_t i = 0; i < faces.size(); i++) {
            cv::rectangle(frame, faces[0], cv::Scalar(255, 0, 0), 2, 8, 0);
            //  std::cout << "Face #" << i + 1 << ": Left=" << faces[i].x << ", Top=" << faces[i].y << std::endl;

            std::stringstream ss;

            x = xEMA.update(faces[i].x * (-0.2) + 160);
            y = yEMA.update(faces[i].y * (-0.416667) + 125);
            //y = faces[0].y * (-0.416667) + 125;
            //x = faces[0].x * (-0.2) + 160;
           
         /*
          if (faces[i].y * (-0.416667) + 125 - y > 10) { y = y + 10; }
                 else if (faces[i].y * (-0.416667) + 125 - y <  10) { y = y - 10; }
                 if (faces[i].x * (-0.2) + 160 - x> 10) { x = x + 10; }
                 else if (faces[i].x * (-0.2) + 160 - x < 10) { x = x - 10; }
        */
            if (x > 100) { x = 100; }
            if (x < 0) { x = 0; }
            if(y > 100) { y = 100; }
            if (y < 0) { y = 0; }
            std::lock_guard<std::mutex> lock(mtx);
            ss << "p$x:" << x << "$y:" << y << "$z:20.3453";
            *pShared = ss.str();
           

        }



    }


    // 释放摄像头资源  
    capture.release();
    // 关闭所有OpenCV窗口  
    cv::destroyAllWindows();
    // 清理  
    closesocket(sock);
    WSACleanup();
    return 0;




}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值