一、下载并安装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>usingnamespace cv;intmain(){
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);return0;}
编译并运行:编译你的项目并运行它。如果一切配置正确,你应该能够看到你的图片在一个窗口中显示。
注意
确保你的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#pragmacomment(lib,"ws2_32.lib")// 链接Winsock库 #definePORT7509#defineBUFSIZE1024#defineSEND_INTERVAL1000// 发送间隔时间,单位毫秒
WSADATA wsaData;
SOCKET sock;structsockaddr_in serverAddr, clientAddr, clientAddr2;int bytesReceived;char buffer[BUFSIZE];int addrLen;classEMA{private:double alpha;double previous;public:EMA(double a):alpha(a),previous(0.0){}doubleupdate(double newValue){double ema = alpha * newValue +(1- alpha)* previous;
previous = ema;return ema;}};voidsendMessageContinuously(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.0sendto(sock, pShared->c_str(), pShared->length(),0,(structsockaddr*)&destAddr,sizeof(destAddr));// std::cout << "Continuous message sent.:::"<< pShared->c_str() <<std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));}}intmain(){
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;return1;}// 创建UDP socket if((sock =socket(AF_INET, SOCK_DGRAM,0))== INVALID_SOCKET){
std::cerr <<"创建socket失败,错误代码: "<<WSAGetLastError()<< std::endl;WSACleanup();return1;}
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,(structsockaddr*)&serverAddr,sizeof(serverAddr))== SOCKET_ERROR){
std::cerr <<"绑定失败,错误代码: "<<WSAGetLastError()<< std::endl;closesocket(sock);WSACleanup();return1;}
std::cout <<"绑定成功。\n";constchar* 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();return0;}
版权归原作者 蛋卷卷- 所有, 如有侵权,请联系我们删除。