在Cygwin下,链接器找不到cv::VideoCapture::VideoCapture() 吗?
我在用OpenCV库在Cygwin下写一个非常简单的程序来打开一个视频文件时,遇到了一个链接时错误。链接器无法找到具有正确签名的VideoCapture构造函数。
下面是源代码:
#include <iostream>
#include <filesystem>
#include <opencv2/opencv.hpp>
using namespace std;
int main(int argc, char *argv[])
{
if (!filesystem::exists(argv[1])) {
cerr << "Video file not found: " << argv[1] << "\n";
return 1;
}
cv::VideoCapture cap(argv[1]);
if (cap.isOpened()) {
cap.release();
cout << "OK!\n";
} else {
cerr << argv[1] << ": can't open video for reading\n";
}
}
编译过程没有报错:
$ g++ -c -g opencvread.cpp -o opencvread.o
随后在链接阶段出现错误:
$ g++ -g -L/usr/lib opencvread.o -lopencv_videoio -o opencvread
/usr/lib/gcc/x86_64-pc-cygwin/13/../../../../x86_64-pc-cygwin/bin/ld: opencvread.o: in function `main':
/cygdrive/c/Users/xtolchinskii/src/exsta/test/opencvread.c++:16:(.text+0xdd): undefined reference to `cv::VideoCapture::VideoCapture(std::string const&, int)'
collect2: error: ld returned 1 exit status
一些验证显示:
$ ls -1 /usr/lib/libopencv*video*.a
/usr/lib/libopencv_video.dll.a
/usr/lib/libopencv_videoio.dll.a
/usr/lib/libopencv_videostab.dll.a
$ nm -CA /usr/lib/libopencv*.a | grep -i 'videocapture(.*string.*,.*int.*)'
/usr/lib/libopencv_videoio.dll.a:d000117.o:0000000000000000 T cv::VideoCapture::VideoCapture(cv::String const&, int)
/usr/lib/libopencv_videoio.dll.a:d000113.o:0000000000000000 T cv::VideoCapture::VideoCapture(cv::String const&, int)
因此看起来OpenCV需要一个 cv::String,而不是一个 std::string。然而,将源代码中的video capture初始化改为如下:
cv::String path = cv::String(argv[1]);
cv::VideoCapture cap(path);
……仍然会出现相同的链接时错误。
同样地,将初始化改为显式使用API模型,而不依赖他们的包装器:
cv::VideoCapture cap(path, cv::CAP_ANY);
OpenCV 3.4.1
Cygwin 3.6.9 x64
我意识到可用的OpenCV的最新版本是5,但在Cygwin上这显然是可用的最新版本(安装OpenCV,而不是从头编译OpenCV)。
有什么想法可以解决这个问题吗?
解决方案
看起来你在混用OpenCV的版本。你的库可能来自版本3.4.1,但你的编译器找到了来自4.0或更高版本的头文件。(也许OpenCV之前已经被安装,你没有意识到?)你需要与库相同版本的头文件。
在早期版本中,OpenCV将它自己的字符串类型定义为 cv::String。对于 4.0.0版本,这个类型被删去,改为 std::string。类型 cv::String 仍然被定义,但现在它是 std::string 的别名。(将名称作为别名保留意味着不需要在代码中逐处更新使用该类型的地方。)由于你的编译器把构造函数的签名记录为涉及 std::string,显然它在 opencv2/core/cvstd.hpp 中看到了这个别名,因此这个头文件来自4.0版本或更高版本。
与之形成对比的是,你的库仍然将 cv::String 作为一个独立的类型,因此来自4.0之前的版本,可能是你安装的那个版本3.4.1。这是头文件版本之间的冲突,从而导致链接错误。也许遇到链接错误恰恰是件好事。如果链接成功,版本不匹配可能会导致离奇且难以诊断的崩溃。
检查你的包含路径。你系统上可能有两套OpenCV头文件,一套是3.4.1,另一套是较新版本(至少4.0)。确保编译器只找到3.4.1的头文件。你也可以检查系统中是否有其他位置的库。如果找到了第二组OpenCV库,提升OpenCV版本可能比你想象的要简单。