tim_xyz tim_xyz - 1 month ago 11
C++ Question

What C++ OpenCV library supports the `threshold` function?

I'm new to C++ and attempting to implement the below OpenCV tutorial on thresholds.
Tutorial: http://docs.opencv.org/2.4/doc/tutorials/imgproc/threshold/threshold.html#basic-threshold

The code almost compiles except 2 functions:


  • threshold()

  • cvtColor()



If these functions are removed then I can compile and run, but that kindof defeats the purpose of the tutorial.

Error:

Undefined symbols for architecture x86_64:
"cv::cvtColor(cv::_InputArray const&, cv::_OutputArray const&, int, int)", referenced from:
_main in HelloWorld.o
"cv::threshold(cv::_InputArray const&, cv::_OutputArray const&, double, double, int)", referenced from:
Threshold_Demo(int, void*) in HelloWorld.o


My libraries via
pkg-config --libs opencv
:


-lopencv_calib3d -lopencv_contrib -lopencv_core -lopencv_features2d -lopencv_flann -lopencv_gpu -lopencv_highgui -lopencv_imgproc -lopencv_legacy -lopencv_ml -lopencv_nonfree -lopencv_objdetect -lopencv_ocl -lopencv_photo -lopencv_stitching -lopencv_superres -lopencv_ts -lopencv_video -lopencv_videostab


Tutorial Code:

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <stdlib.h>
#include <stdio.h>

using namespace cv;

/// Global variables

int threshold_value = 0;
int threshold_type = 3;;
int const max_value = 255;
int const max_type = 4;
int const max_BINARY_value = 255;

Mat src, src_gray, dst;
char* window_name = "Threshold Demo";

char* trackbar_type = "Type: \n 0: Binary \n 1: Binary Inverted \n 2: Truncate \n 3: To Zero \n 4: To Zero Inverted";
char* trackbar_value = "Value";

/// Function headers
void Threshold_Demo( int, void* );

/**
* @function main
*/
int main( int argc, char** argv )
{
/// Load an image
src = imread( argv[1], 1 );

/// Convert the image to Gray
cvtColor( src, src_gray, CV_BGR2GRAY );

/// Create a window to display results
namedWindow( window_name, CV_WINDOW_AUTOSIZE );

/// Create Trackbar to choose type of Threshold
createTrackbar( trackbar_type,
window_name, &threshold_type,
max_type, Threshold_Demo );

createTrackbar( trackbar_value,
window_name, &threshold_value,
max_value, Threshold_Demo );

/// Call the function to initialize
Threshold_Demo( 0, 0 );

/// Wait until user finishes program
while(true)
{
int c;
c = waitKey( 20 );
if( (char)c == 27 )
{ break; }
}

}


/**
* @function Threshold_Demo
*/
void Threshold_Demo( int, void* )
{
/* 0: Binary
1: Binary Inverted
2: Threshold Truncated
3: Threshold to Zero
4: Threshold to Zero Inverted
*/

threshold( src_gray, dst, threshold_value, max_BINARY_value,threshold_type );

imshow( window_name, dst );
}


I'm coming from a Ruby background where library management is much simpler. Any help debugging this at all would be very appreciated.

Edit: I'm using Eclipse editor on Mac.

Answer

I don't know an easier way to find which library you need for a given function than to use nm. So, first you need to find where the OpenCV libraries are installed, i.e. the bit after -L on your compilation command-line. As you have pkg-config, you can use:

pkg-config --libs-only-L opencv

Sample Output

-L/usr/local/Cellar/opencv3/3.1.0_4/lib

So, in the above case, you would do:

cd /usr/local/Cellar/opencv3/3.1.0_4/lib

Now you want to run nm to get all the exported symbols, with the filename, in all libraries ignoring all the ones that end in version numbers as they are mainly just symlinks anyway and they confuse the issue:

nm -g -APU *[A-Za-z].dylib | grep threshold

Sample Output

libopencv_imgproc.dylib: __ZN2cv9thresholdERKNS_11_InputArrayERKNS_12_OutputArrayEddi T 1861788 0

So that tells me you need imgproc library - which you already have. So what is going on???

The problem is that the way OpenCV was built must match the way you are linking with it so that the linker can resolve symbols.

So, if your OpenCV was built with clang++ -std=c++11 -stdlib=libstdc++ you need to build your application the same way.

Whereas if your OpenCV was built with -stdlib=libc++, you will need to use the same when linking your application.

There must be an easier way to tell how something was built (i.e. which library it links against) and maybe someone will tell me, but this works:

First, find your libopencv_imgproc.dylib:

find /usr /opt -name libopencv_imgproc.dylib 

then run nm -m on it to find which symbols are missing and where it wants to get them from:

nm -m libopencv_imgproc.dylib | grep "from libc"

                 (undefined) external __ZNKSt3__120__vector_base_commonILb1EE20__throw_length_errorEv (from libc++)
                 (undefined) external __ZNSt3__16__sortIRNS_6__lessIiiEEPiEEvT0_S5_T_ (from libc++)
                 (undefined) external __ZSt9terminatev (from libc++)
                 (undefined) external __ZTVN10__cxxabiv117__class_type_infoE (from libc++)
                 (undefined) external __ZTVN10__cxxabiv120__si_class_type_infoE (from libc++)
                 (undefined) external __ZTVN10__cxxabiv121__vmi_class_type_infoE (from libc++)
                 (undefined) weak external __ZdaPv (from libc++)
                 (undefined) weak external __ZdlPv (from libc++)
                 (undefined) weak external __Znam (from libc++)
                 (undefined) weak external __Znwm (from libc++)
                 (undefined) external ___cxa_begin_catch (from libc++)
                 (undefined) external ___cxa_end_catch (from libc++)
                 (undefined) external ___cxa_guard_acquire (from libc++)
                 (undefined) external ___cxa_guard_release (from libc++)
                 (undefined) external ___cxa_pure_virtual (from libc++)
                 (undefined) external ___cxa_rethrow (from libc++)
                 (undefined) external ___gxx_personality_v0 (from libc++)

So, I can see that my libraries are expecting to find unresolved symbols in libc++ so I need to use that library when compiling.