I'm trying to compile OpenCV in C++ with boost::python but I keep getting a linker error that I can't quite resolve.
Here is the code below.
cascade_handler.cpp
#include <iostream>
#include <boost/python.hpp>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/ocl/ocl.hpp>
#include "cascade_handler.h"
using namespace std;
using namespace boost::python;
void CascadeHandler::cascade_classifier_cpu(const string *cascade_file, std::vector<cv::Rect>& objects, double scale_factor, int min_neighbors){
/*cv::Mat image;
cv::CascadeClassifier cascade_classifier;
cascade_classifier.load(*cascade_file);
cascade_classifier.detectMultiScale(image, objects, scale_factor, min_neighbors, 0 | CASCADE_SCALE_IMAGE, Size(20, 20));
*/
}
void CascadeHandler::cascade_classifier_gpu(const string *cascade_file, std::vector<cv::Rect>& objects, double scale_factor, int min_neighbors){
/*Mat image;
cv::CascadeClassifier cascade_classifier;
*/
}
void CascadeHandler::handle(const string cascade_file, std::vector<cv::Rect>& objects, double scale_factor, int min_neighbors)
{
CascadeHandler cascade_handler;
cv::CascadeClassifier cascade_classifier;
//ocl::Context context;
/*
if (!cascade_classifier.load(cascade_file)){
cout << "[!] Error: You must load a Cascade file\n";
}
if (objects.empty()){
}
if (scale_factor == 0){
cout << "[!] Error: Unacceptable Scale Factor\n";
}
if (min_neighbors == 0){
cout << "[!] Error: Unacceptable Minimum Neighbors\n";
}
if (context.ndevices()){
cascade_handler.cascade_classifier_gpu(&cascade_file, objects, scale_factor, min_neighbors);
}
else if (!context.ndevices()){
cascade_handler.cascade_classifier_cpu(&cascade_file, objects, scale_factor, min_neighbors);
}
*/
}
void cascade_handler_wrapper(const string cascade_file, std::vector<cv::Rect>& objects,
double scale_factor, int min_neighbors){
CascadeHandler cascade_handler;
cascade_handler.handle(cascade_file, objects, scale_factor, min_neighbors);
}
BOOST_PYTHON_MODULE(cascade_handler){
def("handle", cascade_handler_wrapper);
}
The Header file
#ifndef _CASCADE_HANDLER
#define _CASCADE_HANDLER
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/ocl/ocl.hpp>
using namespace std;
class CascadeHandler
{
public:
void cascade_classifier_cpu(const string *cascade_file, std::vector<cv::Rect>& objects, double scale_factor, int min_neighbors);
void cascade_classifier_gpu(const string *cascade_file, std::vector<cv::Rect>& objects, double scale_factor, int min_neighbors);
void handle(const string cascade_file, std::vector<cv::Rect>& objects, double scale_factor, int min_neighbors);
};
#endif
The Makefile
CPP = g++
CPPFLAGS = -g -Wall -std=c++11
INCLUDES = -I /usr/local/include
LDFLAGS = -L /usr/local/lib
ARCH := $$(getconf LONG_BIT)
CUDA_PATH = /opt/cuda
CUDA_LDFLAGS = -L$(CUDA_PATH)/lib$(ARCH)
CUDA_INCLUDES = -I$(CUDA_PATH)/include
OPENCV_LDFLAGS = $(CUDA_LDFLAGS)
OPENCV_LIBS = $$(pkg-config --libs opencv)
OPENCV_INCLUDES = $$(pkg-config --cflags opencv) $(CUDA_INCLUDES)
PYTHON_VER = 2
ifeq ($(PYTHON_VER), 2)
BOOST_LIBS = -lboost_python
else
BOOST_LIBS = -lboost_python$(PYTHON_VER)
endif
PYTHON_LIBS = $$(pkg-config --libs python$(PYTHON_VER))
PYTHON_INCLUDES = $$(pkg-config --cflags python$(PYTHON_VER))
TARGET = cascade_handler
all: $(TARGET).so
$(TARGET).so: $(TARGET).o
$(CPP) -shared -Wl,--export-dynamic $(LDFLAGS) \
$(OPENCV_LIBS) $(BOOST_LIBS) $(PYTHON_LIBS) \
$(TARGET).o -o $(TARGET).so
$(TARGET).o: $(TARGET).cpp
$(CPP) $(CPPFLAGS) $(INCLUDES) $(OPENCV_INCLUDES) $(PYTHON_INCLUDES) \
-fPIC -c $(TARGET).cpp
clean:
rm -f *.o *.so
And the Output
g++ -shared -Wl,--export-dynamic -L /usr/local/lib \
$(pkg-config --libs opencv) -lboost_python $(pkg-config --libs python2) \
cascade_handler.o -o cascade_handler.so
ld: unknown option: --export-dynamic
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [cascade_handler.so] Error 1
The linker error is the thing I can't quite fix. I wanted to have everything compile on a Makefile because I couldn't find a way to compile OpenCV with the setup.py you normally use when using boost::python. I've also read that some people have been using numpy to wrap their code in and then compile that way, but I was wondering if this method may also work? I also have most of the code commented out because I just wanted to test if it would compile by just have the class cv::CascadeClassifier cascade_classifier;
Related
I need to compile a C++ library to use with contiki on the Zolertia Re-Mote. I am trying a simple program first:
hello-world.c
#include "contiki.h"
#include "misc.h"
/*---------------------------------------------------------------------------*/
PROCESS(hello_world_process, "Hello world process");
AUTOSTART_PROCESSES(&hello_world_process);
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(hello_world_process, ev, data)
{
PROCESS_BEGIN();
say_hello();
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
misc.cpp
/* C++ implementation */
#ifdef CONTIKI_TARGET_ZOUL
void* __dso_handle;
void* __exidx_end;
void* __exidx_start;
#endif
#include <iostream>
using namespace std;
void cpp_say_hello(){
cout << "Hello world!" << endl;
}
/* C wrapper */
extern "C"{
#include "misc.h"
void say_hello(){
cpp_say_hello();
}
}
misc.h
#ifndef _MISC_H_
#define _MISC_H_
/**
* \brief Prints hello to stdout
*/
void say_hello();
#endif /* _MISC_H_ */
Makefile
ifeq ($(TARGET),)
TARGET = native
endif
CONTIKI_PROJECT = hello-world
all: $(CONTIKI_PROJECT)
PROJECT_LIBRARIES = obj_$(TARGET)/misc.o
include $(CONTIKI)/Makefile.include
obj_$(TARGET)/misc.o: misc.cpp
#mkdir -p obj_$(TARGET)
$(TRACE_CXX)
$(Q)$(CXX) $(CFLAGS) $(CXXFLAGS) -c $^ -o $#
This (with some modifications to the contiki Makefiles: here) made possible for me to use C++ code for the 'native' target. However when i try to compile for the Zolertia Re-Mote platform (TARGET=zoul) i obtain the following error:
/usr/lib/gcc/arm-none-eabi/8.2.0/../../../../arm-none-eabi/bin/ld: hello-world.elf section `.ARM.extab.text._Z13cpp_say_hellov' will not fit in region `FLASH_CCA'
/usr/lib/gcc/arm-none-eabi/8.2.0/../../../../arm-none-eabi/bin/ld: region `FLASH_CCA' overflowed by 788 bytes
collect2: error: ld returned 1 exit status
make: *** [/home/wellsaid/contiki/cpu/cc2538/Makefile.cc2538:103: hello-world.elf] Error 1
rm hello-world.co obj_zoul/startup-gcc.o
Any way to fix this?
I have an OpenSUSE 13.2 System with Qt5 and OpenCV installed with cudasupport. The Hardware is an Intel i5 processor with an integrated intel gpu chip and a NVidia GForce 940 M and i have tried to compile this file.
#include <iostream>
#include <time.h>
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/opencv.hpp"
#include "opencv2/gpu/gpu.hpp"
using namespace std;
int main()
{
try
{
cv::Mat dst_mat;
cv::Mat src_host = cv::imread("/home/peter/testCuda/testCuda/GothaOrangerie.JPG", CV_LOAD_IMAGE_GRAYSCALE);
cv::namedWindow("Result",cv::WINDOW_NORMAL);
cv::imshow("Result", src_host);
cv::waitKey();
cv::gpu::GpuMat dst, src;
src.upload(src_host);
clock_t t = clock();
cv::gpu::threshold(src, dst, 128.0, 255.0, CV_THRESH_BINARY);
t = clock() -t;
cv::Mat result_host(dst);
cout << ((float)t)/CLOCKS_PER_SEC << endl;
cv::imshow("Result", result_host);
cv::waitKey();
t = clock();
cv::threshold(src_host, dst_mat, 128.0, 255.0, CV_THRESH_BINARY);
t = clock() -t;
cout << ((float)t)/CLOCKS_PER_SEC << endl;
cv::imshow("Result", dst_mat);
cv::waitKey();
}
catch(const cv::Exception& ex)
{
cout << "Error: " << ex.what() << endl;
}
return 0;
}
The compilation in the shell with
g++ main.cpp -o threshold `pkg-config --cflags --libs opencv` -lopencv_gpu -L/usr/local/cuda-7.5/lib64
works pretty well i can run the small program without any issues. If i try it with the Qt5 IDE it returns me this error.
OpenCV Error: No GPU support (The library is compiled without CUDA support) in mallocPitch, file /home/abuild/rpmbuild/BUILD/opencv-2.4.9/modules/dynamicuda/include/opencv2/dynamicuda/dynamicuda.hpp, line 126
Error: /home/abuild/rpmbuild/BUILD/opencv-2.4.9/modules/dynamicuda/include/opencv2/dynamicuda/dynamicuda.hpp:126: error: (-216) The library is compiled without CUDA support in function mallocPitch
If i run the shellcompiled program with this command
optirun ./threshold
i get the same error.
The .pro File is
#-------------------------------------------------
#
# Project created by QtCreator 2015-10-15T04:02:07
#
#-------------------------------------------------
TARGET = testCuda
LIBS += -L/usr/lib64/
LIBS += -L/usr/local/cuda-7.5/lib64 -lopencv_gpu
LIBS += `pkg-config opencv --cflags --libs`
SOURCES += main.cpp
and the Qt compilation command is
22:58:12: Running steps for project testCuda...
22:58:12: Configuration unchanged, skipping qmake step.
22:58:12: Starting: "/usr/bin/make"
g++ -c -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt4/mkspecs/linux-g++ -I../testCuda -I/usr/include/QtCore -I/usr/include/QtGui -I/usr/include -I. -I../testCuda -I. -o main.o ../testCuda/main.cpp
g++ -Wl,-O1 -o testCuda main.o -L/usr/lib64 -L/usr/lib64/ -L/usr/local/cuda-7.5/lib64 -lopencv_gpu `pkg-config opencv --cflags --libs` -lQtGui -L/usr/lib64 -L/usr/X11R6/lib -lQtCore -lpthread
22:58:13: The process "/usr/bin/make" exited normally.
22:58:13: Elapsed time: 00:01.
Anybody an idea how to fix that?
Deinstalling the preinstalled libopencv-2.4.9 package solved it.
Please help me, How to access run time varibale's data(att) in stub.exe of att variable that is defined in proc.so,
I have created proc.so and linked with attol.exe and stub.exe and
attol.exe updates 'att' variable and stub.exe is accessing 'att' variable and prints att's value.
I have used below commands to compile the code :
g++ -Wall -c attol.cc proc.cc stub.cc
g++ -shared -dynamiclib -fPIC -o libproc.so proc.o -ldl
g++ -rdynamic -o attol.exe attol.o /users/hbharti/DLOPEN/proc/libproc.so -ldl
g++ -rdynamic -o stub.exe stub.o /users/hbharti/DLOPEN/proc/libproc.so -ldl
When i am running both .exe at different terminal then attol.exe showing 'att:4' value but stub.exe is showing incorrect value,
But stub.exe should display '4' value or updated value.
out put attol.exe:
./attol.exe
Value of att is : 4
Enter the value of att :
out put stub.exe:
./stub.exe
Att : 0
----Complete Code Details----
proc.h:
#ifndef __X_H_INCLUDED__
#define __X_H_INCLUDED__
extern int att;
int fun();
#endif
proc.cc:
#include<iostream.h>
#include "proc.h"
int att;
int fun ()
{
att=4;
return 0;
}
Above code is generating proc.o and then this proc.o will converted into proc.so with below commands:
g++ -Wall -c attol.cc proc.cc stub.cc
g++ -shared -dynamiclib -fPIC -o libproc.so proc.o -ldl
attol.cc:
#include <iostream.h>
#include "proc.h"
using namespace std;
int main ()
{
int ch=1;
fun();
cout<<"\n Value of att is : "<<att;
do{
cout<<"\n Enter the value of att : ";
cin>>att;
cout<<"\n Do you want to continue the : ";
cin>>ch;
}while(ch!=0);
return 0;
}
attol.cc file creates attol.exe by using below command
g++ -rdynamic -o attol.exe attol.o /users/hbharti/DLOPEN/proc/libproc.so -ldl
out put:
Value of att is : 4
Enter the value of att :
stub.cc:
#include <iostream.h>
#include <dlfcn.h>
int main ()
{
void *handle;
char *error;
handle = dlopen ("/users/hbharti/DLOPEN/proc/libproc.so", RTLD_LAZY);
if (!handle) {
fputs (dlerror(), stderr);
exit(1);
}
int *att =(int*) dlsym(handle, "att");
if ((error = dlerror()) != NULL) {
fputs(error, stderr);
exit(1);
}
cout<<"\n Att : " <<*att;
cout<<"\n " ;
dlclose(handle);
}
stub.cc file creates stub.exe by using below command
g++ -rdynamic -o stub.exe stub.o /users/hbharti/DLOPEN/proc/libproc.so -ldl
Judging by the code, there seems to be a fundamental issue with the core-logic.
A shared-object (*.so) is loaded into the executing process's memory address space.
However it is NOT shared across multiple processes. When 2 or more executables attempt to access the same shared-object (*.so), they both get independent copies of it mapped into their respective memory address spaces.
Data (even globals) within a shared-object (*so) are NOT shared across 2 or more executables.
Makefile:
CC:=g++
OUTFILE?=addon
SOURCE?=src
CFLAGS+=-Iinclude -lv8 -m64
.PHONY: all clean
all:
$(CC) $(CFLAGS) -o $(OUTFILE) `ls $(SOURCE)/*.cc`
clean:
rm -f $(OUTFILE)
addon.h:
#ifndef __addon_h
#define __addon_h
#define BUILDING_NODE_EXTENSION
#define ADDON_VERSION "0.0.1"
#ifdef BUILDING_NODE_EXTENSION
#include <node/node.h>
#include <node/v8.h>
#else
#include <v8.h>
#endif
using namespace v8;
void init(Handle<Object> exports);
Handle<Object> setupExports(Handle<Object> exports);
#endif
addon.cc:
#include <cstdlib>
#include <cstdio>
#include <addon.h>
using namespace v8;
#ifndef BUILDING_NODE_EXTENSION
int main(int argc, char **argv) {
Isolate *isolate = Isolate::GetCurrent();
HandleScope scope(isolate);
Handle<Context> context = Context::New(isolate);
Context::Scope context_scope(context);
Handle<Object> exports = Object::New();
init(exports);
printf("Version: %s\n", *String::Utf8Value(exports->Get(String::New("version"))));
return 0;
}
#else
int main() {
printf("This is a module compiled for Node.\nPlease use require in Node to use this file.\n");
return 0;
}
#endif
void init(Handle<Object> exports) {
setupExports(exports);
}
Handle<Object> setupExports(Handle<Object> exports) {
// Set version number.
exports->Set(String::New("version"), String::New(ADDON_VERSION));
return exports;
}
#ifdef BUILDING_NODE_EXTENSION
NODE_MODULE(addon, init)
#endif
When compiling the above code with the normal V8 engine without BUILDING_NODE_EXTENSION defined, the output is what we expect:
❱ make && ./addon
g++ -Iinclude -lv8 -m64 -o addon `ls src/*.cc`
Version: 0.0.1
When compiling with BUILDING_NODE_EXTENSION defined, using Node's <node/node.h> and <node/v8.h> for includes instead of the normal <v8.h>, I get this:
❱ make && ./addon
g++ -Iinclude -lv8 -m64 -o addon `ls src/*.cc`
Undefined symbols for architecture x86_64:
"v8::String::New(char const*, int)", referenced from:
setupExports(v8::Handle<v8::Object>) in ccRntYkS.o
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
make: *** [all] Error 1
Anyone have any idea what is going wrong here?
Building with node-gyp solved the problem.
Face. Palm.
Makefile change:
CC:=g++
OUTFILE?=addon
SOURCE?=src
CFLAGS+=-Iinclude -lv8 -m64
.PHONY: all clean
all:
if [ -d build ]; then \
node-gyp build; \
else \
$(CC) $(CFLAGS) -o $(OUTFILE) `ls $(SOURCE)/*.cc`; \
fi;
clean:
rm -f $(OUTFILE)
I am working on getting a few files to link together using my make file and c++ and am getting the following error when running make.
g++ -bind_at_load `pkg-config --cflags opencv` -c -o compute_gist.o compute_gist.cpp
g++ -bind_at_load `pkg-config --cflags opencv` -c -o gist.o gist.cpp
g++ -bind_at_load `pkg-config --cflags opencv` -c -o standalone_image.o standalone_image.cpp
g++ -bind_at_load `pkg-config --cflags opencv` -c -o IplImageConverter.o IplImageConverter.cpp
g++ -bind_at_load `pkg-config --cflags opencv` -c -o GistCalculator.o GistCalculator.cpp
g++ -bind_at_load `pkg-config --cflags opencv` `pkg-config --libs opencv` compute_gist.o gist.o standalone_image.o IplImageConverter.o GistCalculator.o -o rungist
Undefined symbols for architecture x86_64:
"color_gist_scaletab(color_image_t*, int, int, int const*)", referenced from:
_main in compute_gist.o
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
make: *** [rungist] Error 1
My makefile is as follows (Note, I don't need opencv bindings yet, but will be coding in opencv later.
CXX = g++
CXXFLAGS = -bind_at_load `pkg-config --cflags opencv`
LFLAGS = `pkg-config --libs opencv`
SRC = \
compute_gist.cpp \
gist.cpp \
standalone_image.cpp \
IplImageConverter.cpp \
GistCalculator.cpp
OBJS = $(SRC:.cpp=.o)
rungist: $(OBJS)
$(CXX) $(CXXFLAGS) $(LFLAGS) $(OBJS) -o $#
all: rungist
clean:
rm -rf $(OBJS) rungist
The method header is located in gist.h
float *color_gist_scaletab(color_image_t *src, int nblocks, int n_scale, const int *n_orientations);
And the method is defined in gist.cpp
float *color_gist_scaletab(color_image_t *src, int w, int n_scale, const int *n_orientation) {
And finally the compute_gist.cpp (main file)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "gist.h"
static color_image_t *load_ppm(const char *fname) {
FILE *f=fopen(fname,"r");
if(!f) {
perror("could not open infile");
exit(1);
}
int width,height,maxval;
if(fscanf(f,"P6 %d %d %d",&width,&height,&maxval)!=3 || maxval!=255) {
fprintf(stderr,"Error: input not a raw PPM with maxval 255\n");
exit(1);
}
fgetc(f); /* eat the newline */
color_image_t *im=color_image_new(width,height);
int i;
for(i=0;i<width*height;i++) {
im->c1[i]=fgetc(f);
im->c2[i]=fgetc(f);
im->c3[i]=fgetc(f);
}
fclose(f);
return im;
}
static void usage(void) {
fprintf(stderr,"compute_gist options... [infilename]\n"
"infile is a PPM raw file\n"
"options:\n"
"[-nblocks nb] use a grid of nb*nb cells (default 4)\n"
"[-orientationsPerScale o_1,..,o_n] use n scales and compute o_i orientations for scale i\n"
);
exit(1);
}
int main(int argc,char **args) {
const char *infilename="/dev/stdin";
int nblocks=4;
int n_scale=3;
int orientations_per_scale[50]={8,8,4};
while(*++args) {
const char *a=*args;
if(!strcmp(a,"-h")) usage();
else if(!strcmp(a,"-nblocks")) {
if(!sscanf(*++args,"%d",&nblocks)) {
fprintf(stderr,"could not parse %s argument",a);
usage();
}
} else if(!strcmp(a,"-orientationsPerScale")) {
char *c;
n_scale=0;
for(c=strtok(*++args,",");c;c=strtok(NULL,",")) {
if(!sscanf(c,"%d",&orientations_per_scale[n_scale++])) {
fprintf(stderr,"could not parse %s argument",a);
usage();
}
}
} else {
infilename=a;
}
}
color_image_t *im=load_ppm(infilename);
//Here's the method call -> :(
float *desc=color_gist_scaletab(im,nblocks,n_scale,orientations_per_scale);
int i;
int descsize=0;
//compute descriptor size
for(i=0;i<n_scale;i++)
descsize+=nblocks*nblocks*orientations_per_scale[i];
descsize*=3; // color
//print descriptor
for(i=0;i<descsize;i++)
printf("%.4f ",desc[i]);
printf("\n");
free(desc);
color_image_delete(im);
return 0;
}
Any help would be greatly appreciated. I hope this is enough info. Let me know if I need to add more.
I suspect that color_gist_scaletab should be declared as extern "C" in your header file:
extern "C" {
float *color_gist_scaletab(color_image_t *src, int nblocks, int n_scale, const int *n_orientations);
}
Your link command line is incorrect. See this answer.
However, that is likely not the problem you are seeing here.
What do the following commands print?
file gist.o
nm gist.o | grep color_gist_scaletab
I also see this very similar question. But there, color_gist_scaletab comes from gist.c, not gist.cpp. You didn't just rename gist.c to gist.cpp, did you? Don't do that.