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

蛋卷卷- 2024-09-12 13:01:02 阅读 70

一、下载并安装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的代码。例如,一个简单的读取并显示图片的代码示例如下:

<code>#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?

basics​tring@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";code>

*pShared = ss.str();

}

}

// 释放摄像头资源

capture.release();

// 关闭所有OpenCV窗口

cv::destroyAllWindows();

// 清理

closesocket(sock);

WSACleanup();

return 0;

}



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。