I'm trying to compile a simple program using OpenCV 4.6.0 in C++ (I'm on Ubuntu 20.04 and that's the default installation) that reads an image, runs a BRISK feature detection, and displays the keypoints' locations on the image using imshow. I can do proprocessing, compilation, and assembly into a .o file no problem, but g++ has so far flatly refused to do the linking step.
I was originally getting an undefined reference error for every OpenCV function call, but after much pain and trial-and-error, including uninstalling and reinstalling OpenCV multiple times (following the instructions at https://docs.opencv.org/4.x/d7/d9f/tutorial_linux_install.html#tutorial_linux_install_detailed_basic_verify), I realized that for some reason, g++ will only link to OpenCV libraries when explicitly told to do so with -l. I have now written a bash script to manually link every single OpenCV library I can find in /usr/local/lib. The script is called opencv_linker, and it contains the following:
#!/bin/bash
g++ $@ -lopencv_core -lopencv_highgui -lopencv_imgcodecs -lopencv_imgproc -lopencv_calib3d -lopencv_dnn -lopencv_features2d -lopencv_flann -lopencv_gapi -lopencv_ml -lopencv_objdetect -lopencv_photo -lopencv_stitching -lopencv_videoio -lopencv_video
I run it from the command line as
./opencv_linker brisk_test.cpp -I/usr/local/include/opencv4
(I will turn this into a makefile eventually, but for now I'm just trying to get OpenCV to work at all. Also, I'm sure I don't strictly need all of these libraries for what I'm doing, but I don't have a good reference for which libraries include which functions, so I'm taking the brute force route.)
Running the above in the command line gives the following error:
usr/bin/ld: /tmp/ccdVMcvM.o: in function `main':
<path_to_directory>/brisk_test.cpp:19: undefined reference to `cv::Mat::Mat()'
collect2: error: ld returned 1 exit status
I have also tried running g++ brisk_test.cpp -I/usr/local/include/opencv4 `pkg-config --libs opencv4`
, which I think is equivalent. Same result. Swapping the order of the -I argument and the pkg-config argument didn't change anything.
I've run out of ideas as to what to do to eliminate this last undefined reference. I don't understand why g++ would be unable to find cv::Mat::Mat() in any of the OpenCV libraries (unless there's another library somewhere that I just don't know about). I've searched for answers online, and nothing I've found has addressed the problem -- the answers to this post and this post didn't solve the problem, and this post doesn't have an answer. If anyone has any ideas as to what might be going on, I will be eternally grateful.
EDIT: I don't think the order in which I'm linking the libraries is an issue (but I could be wrong). Everything online about the order in which to link the libraries just says to use `pkg-config --cflags --libs opencv4`
(sometimes without --cflags), and apparently that should take care of the ordering? I've tried the following six commands:
g++ -g brisk_test.cpp -I/usr/local/include/opencv4 `pkg-config --libs opencv4`
g++ -g brisk_test.cpp `pkg-config --libs opencv4` -I/usr/local/include/opencv4
g++ -g brisk_test.cpp -I/usr/local/include/opencv4 `pkg-config --cflags --libs opencv4`
g++ -g brisk_test.cpp `pkg-config --cflags --libs opencv4` -I/usr/local/include/opencv4
g++ -g `pkg-config --cflags opencv4` brisk_test.cpp `pkg-config --libs opencv4` -I/usr/local/include/opencv4
g++ -g `pkg-config --cflags opencv4` brisk_test.cpp -I/usr/local/include/opencv4 `pkg-config --libs opencv4`
All of them gave me the same error message as above.
EDIT 2: Here's the output of nm -CD /usr/local/lib/libopencv_core.so | grep Mat::Mat
:
$ nm -CD /usr/local/lib/libopencv_core.so | grep Mat::Mat
00000000001c2580 T cv::Mat::Mat(int, int, int)
00000000001c12e0 T cv::Mat::Mat(int, int, int, void*, unsigned long)
00000000001c25d0 T cv::Mat::Mat(int, int, int, cv::Scalar_<double> const&)
00000000001c2440 T cv::Mat::Mat(int, int const*, int)
00000000001c2ab0 T cv::Mat::Mat(int, int const*, int, void*, unsigned long const*)
00000000001c2490 T cv::Mat::Mat(int, int const*, int, cv::Scalar_<double> const&)
00000000001c2640 T cv::Mat::Mat(cv::Size_<int>, int)
00000000001c14e0 T cv::Mat::Mat(cv::Size_<int>, int, void*, unsigned long)
00000000001c2690 T cv::Mat::Mat(cv::Size_<int>, int, cv::Scalar_<double> const&)
00000000001c1790 T cv::Mat::Mat(cv::Mat&&)
00000000001c19e0 T cv::Mat::Mat(cv::Mat const&)
00000000001c3630 T cv::Mat::Mat(cv::Mat const&, cv::Range const*)
00000000001c38a0 T cv::Mat::Mat(cv::Mat const&, cv::Range const&, cv::Range const&)
00000000001c2800 T cv::Mat::Mat(cv::Mat const&, cv::Rect_<int> const&)
00000000001c3cb0 T cv::Mat::Mat(cv::Mat const&, std::vector<cv::Range, std::allocator<cv::Range> > const&)
00000000001c2740 T cv::Mat::Mat(std::vector<int, std::allocator<int> > const&, int)
00000000001c34e0 T cv::Mat::Mat(std::vector<int, std::allocator<int> > const&, int, void*, unsigned long const*)
00000000001c2790 T cv::Mat::Mat(std::vector<int, std::allocator<int> > const&, int, cv::Scalar_<double> const&)
00000000001c11c0 T cv::Mat::Mat()
00000000001c2580 T cv::Mat::Mat(int, int, int)
00000000001c12e0 T cv::Mat::Mat(int, int, int, void*, unsigned long)
00000000001c25d0 T cv::Mat::Mat(int, int, int, cv::Scalar_<double> const&)
00000000001c2440 T cv::Mat::Mat(int, int const*, int)
00000000001c2ab0 T cv::Mat::Mat(int, int const*, int, void*, unsigned long const*)
00000000001c2490 T cv::Mat::Mat(int, int const*, int, cv::Scalar_<double> const&)
00000000001c2640 T cv::Mat::Mat(cv::Size_<int>, int)
00000000001c14e0 T cv::Mat::Mat(cv::Size_<int>, int, void*, unsigned long)
00000000001c2690 T cv::Mat::Mat(cv::Size_<int>, int, cv::Scalar_<double> const&)
00000000001c1790 T cv::Mat::Mat(cv::Mat&&)
00000000001c19e0 T cv::Mat::Mat(cv::Mat const&)
00000000001c3630 T cv::Mat::Mat(cv::Mat const&, cv::Range const*)
00000000001c38a0 T cv::Mat::Mat(cv::Mat const&, cv::Range const&, cv::Range const&)
00000000001c2800 T cv::Mat::Mat(cv::Mat const&, cv::Rect_<int> const&)
00000000001c3cb0 T cv::Mat::Mat(cv::Mat const&, std::vector<cv::Range, std::allocator<cv::Range> > const&)
00000000001c2740 T cv::Mat::Mat(std::vector<int, std::allocator<int> > const&, int)
00000000001c34e0 T cv::Mat::Mat(std::vector<int, std::allocator<int> > const&, int, void*, unsigned long const*)
00000000001c2790 T cv::Mat::Mat(std::vector<int, std::allocator<int> > const&, int, cv::Scalar_<double> const&)
00000000001c11c0 T cv::Mat::Mat()
EDIT 3: I know which line of code is causing a problem, thanks to me having the bright idea of trying something which I really should have tried already (my bad, sorry -- I'm really not an expert at this): namely, commenting out lines of code until the program successfully compiles and links. When I reduce my program to just the following lines of code, it compiles and links successfully to produce an executable:
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/features2d.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char* argv[])
{
Mat img = imread("test_image.jpg", IMREAD_GRAYSCALE);
Ptr<BRISK> detector = BRISK::create();
std::vector<KeyPoint> keypoints;
detector->detect(img, keypoints);
return EXIT_SUCCESS;
}
What breaks the code is the addition of the next line necessary to draw keypoints: namely, g++ is unable to do the linking when I add the line
Mat img_keypoints;
before the return. I don't understand why that line would cause an issue, particularly since I am apparently able to create a Mat object in the first line. I do know that the error occurs in the linking step, though, as I am able to compile and assemble my program into a .o file, even with the problematic line of code included.
EDIT 4: Changing the code above (which works) to split the first line into two also breaks things: namely,
int main(int argc, char* argv[])
{
Mat img;
img = imread("test_image.jpg", IMREAD_GRAYSCALE);
Ptr<BRISK> detector = BRISK::create();
std::vector<KeyPoint> keypoints;
detector->detect(img, keypoints);
return EXIT_SUCCESS;
}
also gives me the same linker error.