我想用 c++ 编写一个程序,它使用两个库 libgphoto2 和 opencv3.0。因此,我想在我的主要源代码中包含一个自己编写的头文件,其中包含一些利用 libgphoto2 库中定义的函数的函数,在其中我导入 opencv。第二个头文件只定义了一些常量,不使用外部库。
这两个库都功能性地安装在我的 macbook 上。我可以使用 cmake 编写和编译使用其中任何一个的工作程序,但我真的不知道 cmake 的语法以解决上述问题......顺便说一句:find_package 适用于两个库!
文件夹结构如下:
./camera_cv
./camera_cv/CMakeLists.txt
./camera_cv/src
./camera_cv/src/takeShowAdjust.cpp
./camera_cv/src/mh_camera_control.hpp
./camera_cv/src/cv_supplement.hpp
我的 CMakeLists.txt 文件:
cmake_minimum_required(VERSION 2.8)
project( opencvTutorial )
SET(CMAKE_CXX_FLAGS_DEBUG "-g -ggdb")
SET(CMAKE_CXX_FLAGS_RELEASE "-Ofast -DNDEBUG -march=native")
SET( CMAKE_BUILD_TYPE DEBUG)
find_package( Gphoto2 REQUIRED )
find_package( OpenCV 3.0.0 REQUIRED )
include_directories( ${GPHOTO2_INCLUDE_DIR} ${OpenCV_INCLUDE_DIRS} )
add_executable( TakeShowAdjust src/takeShowAdjust.cpp src/cv_supplement.hpp src/mh_camera_control.hpp)
target_link_libraries( TakeShowAdjust ${LIBGPHOTO2_LIBRARIES} ${OpenCV_LIBS} -lm )
# --- Install ---
SET(BINDIR "${CMAKE_INSTALL_PREFIX}/bin")
INSTALL(TARGETS
TakeShowAdjust
DESTINATION ${BINDIR})
键入 $ cmake 。写入构建文件没有任何错误。但之后,如果我输入 $ make ,我会收到以下错误:
$ make
Scanning dependencies of target TakeShowAdjust
[ 50%] Building CXX object CMakeFiles/TakeShowAdjust.dir/src/takeShowAdjust.cpp.o
[100%] Linking CXX executable TakeShowAdjust
Undefined symbols for architecture x86_64:
"_gp_camera_capture", referenced from:
capture(char const*) in takeShowAdjust.cpp.o
"_gp_camera_file_delete", referenced from:
capture(char const*) in takeShowAdjust.cpp.o
"_gp_camera_file_get", referenced from:
capture(char const*) in takeShowAdjust.cpp.o
"_gp_camera_free", referenced from:
initialize_camera() in takeShowAdjust.cpp.o
"_gp_camera_get_config", referenced from:
get_config_value_string(char const*, char**, _GPContext*, _Camera*) in takeShowAdjust.cpp.o
set_config_value_string(char const*, char const*, _GPContext*, _Camera*) in takeShowAdjust.cpp.o
"_gp_camera_init", referenced from:
initialize_camera() in takeShowAdjust.cpp.o
"_gp_camera_new", referenced from:
initialize_camera() in takeShowAdjust.cpp.o
"_gp_camera_set_config", referenced from:
set_config_value_string(char const*, char const*, _GPContext*, _Camera*) in takeShowAdjust.cpp.o
"_gp_camera_unref", referenced from:
close_camera() in takeShowAdjust.cpp.o
_main in takeShowAdjust.cpp.o
"_gp_camera_wait_for_event", referenced from:
capture(char const*) in takeShowAdjust.cpp.o
"_gp_context_new", referenced from:
initialize_camera() in takeShowAdjust.cpp.o
"_gp_context_set_error_func", referenced from:
initialize_camera() in takeShowAdjust.cpp.o
"_gp_context_set_message_func", referenced from:
initialize_camera() in takeShowAdjust.cpp.o
"_gp_context_unref", referenced from:
close_camera() in takeShowAdjust.cpp.o
_main in takeShowAdjust.cpp.o
"_gp_file_free", referenced from:
capture(char const*) in takeShowAdjust.cpp.o
"_gp_file_new_from_fd", referenced from:
capture(char const*) in takeShowAdjust.cpp.o
"_gp_widget_free", referenced from:
get_config_value_string(char const*, char**, _GPContext*, _Camera*) in takeShowAdjust.cpp.o
set_config_value_string(char const*, char const*, _GPContext*, _Camera*) in takeShowAdjust.cpp.o
"_gp_widget_get_child_by_label", referenced from:
get_config_value_string(char const*, char**, _GPContext*, _Camera*) in takeShowAdjust.cpp.o
set_config_value_string(char const*, char const*, _GPContext*, _Camera*) in takeShowAdjust.cpp.o
"_gp_widget_get_child_by_name", referenced from:
get_config_value_string(char const*, char**, _GPContext*, _Camera*) in takeShowAdjust.cpp.o
set_config_value_string(char const*, char const*, _GPContext*, _Camera*) in takeShowAdjust.cpp.o
"_gp_widget_get_type", referenced from:
get_config_value_string(char const*, char**, _GPContext*, _Camera*) in takeShowAdjust.cpp.o
set_config_value_string(char const*, char const*, _GPContext*, _Camera*) in takeShowAdjust.cpp.o
"_gp_widget_get_value", referenced from:
get_config_value_string(char const*, char**, _GPContext*, _Camera*) in takeShowAdjust.cpp.o
"_gp_widget_set_value", referenced from:
set_config_value_string(char const*, char const*, _GPContext*, _Camera*) in takeShowAdjust.cpp.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [TakeShowAdjust] Error 1
make[1]: *** [CMakeFiles/TakeShowAdjust.dir/all] Error 2
make: *** [all] Error 2
源代码:
采取ShowAdjust.cpp:
#include <vector>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <cstdarg>
#include <fcntl.h>
#include <opencv2/opencv.hpp>
#include "../src/cv_supplement.hpp"
#include "../src/mh_camera_control.hpp"
#define killall_PTPCamera system("killall PTPCamera");
using namespace cv;
using namespace std;
int main(int argc, char *argv[]) {
// Load Camera
initialize_camera();
// take picture
char filename[256];
int i = 1;
snprintf(filename, 256, "shot-%04d.jpg", i++);
printf("Capturing to file %s\n", filename);
capture(filename);
// load image
Mat img = imread(filename, CV_LOAD_IMAGE_COLOR);
// show image
namedWindow("original", WINDOW_AUTOSIZE);
moveWindow("original", POS_00);
imshow("original", img);
waitKey(0);
close_camera();
return 0;
}
mh_camera_control.hpp:
#ifndef MH_CAMERA_CONTROL
#define MH_CAMERA_CONTROL
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <cstdarg>
#include <fcntl.h>
#include <gphoto2/gphoto2.h>
#define killall_PTPCamera system("killall PTPCamera");
Camera *camera;
GPContext *context;
int initialize_camera(void);
void close_camera(void);
int capture (const char *filename);
static int _lookup_widget(CameraWidget*widget, const char *key, CameraWidget **child);
int get_config_value_string (const char *key, char **str, GPContext *contxt = context, Camera *cam = camera);
int set_config_value_string (const char *key, const char *val, GPContext *contxt = context, Camera *cam = camera);
void error_func(GPContext *context, const char *format, va_list args, void *data);
void message_func(GPContext *context, const char *format, va_list args, void *data);
int initialize_camera(void){
killall_PTPCamera;
gp_camera_new(&camera);
context = gp_context_new();
gp_context_set_error_func(context, (GPContextErrorFunc)error_func, NULL);
gp_context_set_message_func(context, (GPContextStatusFunc)message_func, NULL);
int ret = gp_camera_init(camera, context);
if(ret < GP_OK){
printf("No camera auto detected.\n");
gp_camera_free(camera);
return 1;
}
return 0;
}
void close_camera(void){
gp_camera_unref(camera);
gp_context_unref(context);
}
int capture (const char *filename){
int fd, retval;
CameraFile *file;
CameraFilePath camera_file_path;
//take a shot
retval = gp_camera_capture(camera, GP_CAPTURE_IMAGE, &camera_file_path, context);
if (retval){
// do some error handling (return from function??)
}
printf("Pathname on the camera: %s/%s\n", camera_file_path.folder, camera_file_path.name);
fd = open(filename, O_CREAT | O_WRONLY, 0644);
// create new CameraFile object from a file descriptor
retval = gp_file_new_from_fd(&file, fd);
if (retval){
// error handling
}
// copy picture from camera
retval = gp_camera_file_get(camera, camera_file_path.folder, camera_file_path.name, GP_FILE_TYPE_NORMAL, file, context);
if (retval){
// error handling
}
// remove picture from camera memory
printf("Deleting\n");
retval = gp_camera_file_delete(camera, camera_file_path.folder, camera_file_path.name, context);
if (retval){
// error handling
}
// free CameraFile object
gp_file_free(file);
// wait till camera is no longer busy, could be done more efficiently (outside this fuction for ex.)
int waittime = 2000;
CameraEventType type;
void *data;
printf("Wait for events from camera\n");
while(1){
retval = gp_camera_wait_for_event(camera, waittime, &type, &data, context);
if(type == GP_EVENT_TIMEOUT){
break;
}
else if(type != GP_EVENT_CAPTURE_COMPLETE){
if (type != GP_EVENT_UNKNOWN){
printf("Unexpected event received from camera: %d\n", (int)type);
}
}
else{
break;
}
}
return 0;
}
/*
* This function looks up a label or key entry of
* a configuration widget.
* The functions descend recursively, so you can just
* specify the last component.
*/
static int
_lookup_widget(CameraWidget*widget, const char *key, CameraWidget **child) {
int ret;
ret = gp_widget_get_child_by_name (widget, key, child);
if (ret < GP_OK)
ret = gp_widget_get_child_by_label (widget, key, child);
return ret;
}
/* Gets a string configuration value.
* This can be:
* - A Text widget
* - The current selection of a Radio Button choice
* - The current selection of a Menu choice
*
* Sample (for Canons eg):
* get_config_value_string (camera, "owner", &ownerstr, context);
*/
int
get_config_value_string (const char *key, char **str, GPContext *contxt, Camera *cam) {
CameraWidget *widget = NULL, *child = NULL;
CameraWidgetType type;
int ret;
char *val;
ret = gp_camera_get_config (cam, &widget, contxt);
if (ret < GP_OK) {
fprintf (stderr, "camera_get_config failed: %d\n", ret);
return ret;
}
ret = _lookup_widget (widget, key, &child);
if (ret < GP_OK) {
fprintf (stderr, "lookup widget failed: %d\n", ret);
goto out;
}
/* This type check is optional, if you know what type the label
* has already. If you are not sure, better check. */
ret = gp_widget_get_type (child, &type);
if (ret < GP_OK) {
fprintf (stderr, "widget get type failed: %d\n", ret);
goto out;
}
switch (type) {
case GP_WIDGET_MENU:
case GP_WIDGET_RADIO:
case GP_WIDGET_TEXT:
break;
default:
fprintf (stderr, "widget has bad type %d\n", type);
ret = GP_ERROR_BAD_PARAMETERS;
goto out;
}
/* This is the actual query call. Note that we just
* a pointer reference to the string, not a copy... */
ret = gp_widget_get_value (child, &val);
if (ret < GP_OK) {
fprintf (stderr, "could not query widget value: %d\n", ret);
goto out;
}
/* Create a new copy for our caller. */
*str = strdup (val);
out:
gp_widget_free (widget);
return ret;
}
/* Sets a string configuration value.
* This can set for:
* - A Text widget
* - The current selection of a Radio Button choice
* - The current selection of a Menu choice
*
* Sample (for Canons eg):
* get_config_value_string (camera, "owner", &ownerstr, context);
*/
int
set_config_value_string (const char *key, const char *val, GPContext *contxt, Camera *cam) {
CameraWidget *widget = NULL, *child = NULL;
CameraWidgetType type;
int ret;
ret = gp_camera_get_config (cam, &widget, contxt);
if (ret < GP_OK) {
fprintf (stderr, "camera_get_config failed: %d\n", ret);
return ret;
}
ret = _lookup_widget (widget, key, &child);
if (ret < GP_OK) {
fprintf (stderr, "lookup widget failed: %d\n", ret);
goto out;
}
/* This type check is optional, if you know what type the label
* has already. If you are not sure, better check. */
ret = gp_widget_get_type (child, &type);
if (ret < GP_OK) {
fprintf (stderr, "widget get type failed: %d\n", ret);
goto out;
}
switch (type) {
case GP_WIDGET_MENU:
case GP_WIDGET_RADIO:
case GP_WIDGET_TEXT:
break;
default:
fprintf (stderr, "widget has bad type %d\n", type);
ret = GP_ERROR_BAD_PARAMETERS;
goto out;
}
/* This is the actual set call. Note that we keep
* ownership of the string and have to free it if necessary.
*/
ret = gp_widget_set_value (child, val);
if (ret < GP_OK) {
fprintf (stderr, "could not set widget value: %d\n", ret);
goto out;
}
/* This stores it on the camera again */
ret = gp_camera_set_config (cam, widget, contxt);
if (ret < GP_OK) {
fprintf (stderr, "camera_set_config failed: %d\n", ret);
return ret;
}
out:
gp_widget_free (widget);
return ret;
}
void error_func(GPContext *context, const char *format, va_list args, void *data){
fprintf (stderr, "*** Contexterror ***\n");
//fprintf(stderr, format);
vfprintf(stderr, format, args);
fprintf (stderr, "\n");
}
void message_func(GPContext *context, const char *format, va_list args, void *data){
vprintf(format, args);
//fprintf(stderr, format);
printf("\n");
}
#endif
cv_supplement.hpp:
#ifndef CV_SUPPLEMENT
#define CV_SUPPLEMENT
#define HEADER_SIZE 23
#define POS_00 0*img.cols,0
#define POS_01 1*img.cols,0
#define POS_02 2*img.cols,0
#define POS_03 3*img.cols,0
#define POS_10 0*img.cols, 1*img.rows+2*HEADER_SIZE
#define POS_11 1*img.cols, 1*img.rows+2*HEADER_SIZE
#define POS_12 2*img.cols, 1*img.rows+2*HEADER_SIZE
#define POS_13 3*img.cols, 1*img.rows+2*HEADER_SIZE
#define POS_20 0*img.cols, 2*img.rows+3*HEADER_SIZE
#define POS_21 1*img.cols, 2*img.rows+3*HEADER_SIZE
#define POS_22 2*img.cols, 2*img.rows+3*HEADER_SIZE
#define POS_23 3*img.cols, 2*img.rows+3*HEADER_SIZE
#endif
那么,如何正确链接这两个库呢?我做错了什么,或者我错过了什么?
非常感谢您!