解决无数人对安装opencv后环境变量配置疑惑的终极答案
按照我的这篇傻瓜式的教程2小时搞定开发环境,要不然一堆坑搞不好得弄一天(在写这篇博客的过程中,搜集了一些资料,说说我的感受:我始终没搞明白很多人的分享,为啥写的片片面面稀里糊涂的,让别人越弄越恼火,为啥不能好好写个一步步教程呢,这又有多难呢。当然opencv的文档也够偷懒的,为啥opencv背后的帅哥靓女们不好好写写文档呢,难道只是贡献点代码开会的时候吹一下牛就完了吗,这点可以好好跟postgresql学习)。
1. VirtualBox里安装Centos6.9及必要的库
CentOS:6.9 64位,不建议使用6.3(否则默认安装的gtk2的小版本会导致window_gtk.cpp编译不通过,需要替换"gtk_widget_set_realized" 为"GTK_WIDGET_SET_FLAGS"的情况),下载地址:https://pan.baidu.com/s/1pNl3EWj 注意,我们安装的是64位,所以你的主机需要设置一下bios,开启Intel虚拟化技术(参考https://www.cnblogs.com/zhao1949/p/6116183.html )。
安装时,选择Workstation和Customize now,如下图:
然后取消选择Developement -> Eclipse (我们后面自行下载喜欢的版本):
语言选择中文支持:
安装完之后重启,用root登录,然后安装VirtualBox的"安装增强功能":
安装完毕,选择VirtualBox菜单栏里的 设备-》共享黏贴板-》双向,然后重启,仍然用root登录,然后选择:
然后输入cmake,检索并安装:
同样的方法安装:libavc的开发包:
由于我们开始选择WorkStation的时候系统会默认安装gtk2-devel-2.24.23-9.el6,python2.6.6及Numpy1.4(似乎官方要求是1.5及以上,暂时我们不管了,先暂时用这个,以后出了问题再说),pkg-config 0.23,所以我们就无需再次安装了。
按照官网opencv 3.4.0安装介绍(https://docs.opencv.org/master/d7/d9f/tutorial_linux_install.html),我们还缺libavformat-dev, libswscale-dev。但是我们目前暂时先不安装,如果你想自己源码安装这些库,也可以自行搞定。
然后重启机器,用root登录,在System-》Preferences-》Display设置一下高的分辨率,在System-》Preferences-》Input Method里增加一下中文输入法Chinese-Pinyin。
这里https://pan.baidu.com/s/1ggQLqdP 有个完整的VirtualBox Centos6.9 64位的虚拟机文件,可以下载下来在VirtualBox自行加载进去,放心没毒。账号root,密码000000,另外我把主机和虚拟机之间共享了文件夹,你也可以设置一下你自己的,然后重启即可。
2. 下载opencv2.4源码,然后编译安装
然后解压缩后,执行:
cd opencv-.4.13.5/
mkdir build
cd build/
cmake -D CMAKE_BUILD_TYPE=DEBUG -D WITH_GTK=ON -D CMAKE_INSTALL_PREFIX=/usr/local ..
make
make install
我们检查一下发现opencv的lib库安装在/usr/local/lib下了,头文件安装在了/usr/local/include下了。
接下来就是让大家最头疼的各种路径的设置了(这部分往往比其他事情更耗时间),其实我们每次安装完一个软件,都要考虑一下如下几个设置要不要改:
1.看看能不能让c编译头文件路径找得到: C_INCLUDE_PATH,我们通过如下命令得到默认的C_INCLUDE_PATH包含哪些路径:
[root@localhost ~]# `gcc -print-prog-name=cc1` -v
/usr/local/include
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/include
/usr/include
发现opencv的头文件路径/usr/local/include已经在C_INCLUDE_PATH的默认搜索路径中了,所以我们就不用设置了
2.看看能不能让c++编译头文件路径找得到:CPLUS_INCLUDE_PATH,我们通过如下命令得到默认的CPLUS_INCLUDE_PATH包含哪些路径:
[root@localhost ~]# `gcc -print-prog-name=cc1plus` -v
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/x86_64-redhat-linux
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/backward
/usr/local/include
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/include
/usr/include
发现opencv的头文件路径/usr/local/include也已经在CPLUS_INCLUDE_PATH的默认搜索路径中了,所以我们也不用设置了。
3.GCC的连接器搜索路径:LIBRARY_PATH,我们通过如下命令得到默认的LIBRARY_PATH包含哪些路径:
[root@localhost ~]# ld --verbose
SEARCH_DIR("/usr/x86_64-redhat-linux/lib64");
SEARCH_DIR("/usr/local/lib64");
SEARCH_DIR("/lib64");
SEARCH_DIR("/usr/lib64");
SEARCH_DIR("/usr/x86_64-redhat-linux/lib");
SEARCH_DIR("/usr/lib64");
SEARCH_DIR("/usr/local/lib");
SEARCH_DIR("/lib");
SEARCH_DIR("/usr/lib");
发现opencv的库路径/usr/local/lib已经被包含其中了,故我们也不用设置了。
4.可执行程序运行时搜索的动态库路径:LD_LIBRARY_PATH,我们通过如下命令得到默认的LIBRARY_PATH包含哪些路径:
[root@localhost ~]# ldconfig -v 2>/dev/null | grep -v ^$'\t'
/var/lib/VBoxGuestAdditions/lib:/usr/lib64/atlas:/usr/lib64/mysql:/usr/lib64/qt-3.3/lib:/usr/lib64/xulrunner:/lib:/lib64:/usr/lib:/usr/lib64:/lib64/tls: (hwcap: 0x8000000000000000)/usr/lib64/tls: (hwcap: 0x8000000000000000)/usr/lib64/sse2: (hwcap: 0x0000000004000000)
发现opencv的库路径/usr/local/lib没有被包含其中,所以我们需要设置这个,有两个办法设置:
1)全局有效(推荐,只需要执行一次)
echo /usr/local/lib/ /etc/ld.so.conf.d/opencv.conf
ldconfig
2)本账户root有效
gedit ~/.bash_profile 增加如下内容:
export LD_LIBRARY_PATH=/usr/local/lib$LD_LIBRARY_PATH
退出执行source ~/.bash_profile生效
5.pkg-config命令寻找路径(为何要关注这个命令的路径设置呢,是因为很多开源项目的configure命令中使用该pkg-config命令搜索依赖的库是否存在,我们的opencv就试用该命令得知是否安装了gtk等):PKG_CONFIG_PATH,根据官方的文档https://people.freedesktop.org/~dbn/pkg-config-guide.html ,我们看看包含哪些路径:
On a typical Unix system, it will search in the directories /usr/lib/pkgconfig and /usr/share/pkgconfig. This will usually cover system installed modules. However, some local modules may be installed in a different prefix such as /usr/local. In that case, it's necessary to prepend the search path so that pkg-config can locate the .pc files.
可见,由于我们的opencv安装在/usr/local下面,而且安装时已经生成了/usr/local/lib/pkgconfig/opencv.pc文件,所以我们只需要把该路径添加到PKG_CONFIG_PATH里即可:
gedit ~/.bash_profile 增加如下内容:
export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH
退出执行source ~/.bash_profile生效
说了这半天,我们总结一下,综上我们只需要在gedit ~/.bash_profile 增加如下内容:
export LD_LIBRARY_PATH=/usr/local/lib$LD_LIBRARY_PATH
export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH
即可。
有些同学说了,这么麻烦,下回安装别的软件是不是也得这么检查一道,答案是的,当然有个偷懒的办法,你可以在~/.bash_profile里不管三七二十一都把相应的路径添加上,这样子哪怕重复路径也没关系,如我们的opencv就可以这么设置:export LIBRARY_PATH=/usr/local/lib/:$LIBRARY_PATH
export LD_LIBRARY_PATH=/usr/local/lib$LD_LIBRARY_PATH
export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH
export C_INCLUDE_PATH=/usr/local/include:$C_INCLUDE_PATH
export CPLUS_INCLUDE_PATH=/usr/local/include:$CPLUS_INCLUDE_PATH
然后重启测试一下:
pkg-config --modversion opencv
pkg-config --cflags --libs opencv
是不是pkg-config已经可以搜索到了。
3. 安装Eclipse
假设下载在~/software,解压缩后,打开看看是不是成功。
4. 新建项目测试gtk是否可用
在Eclipse里:
然后:
点击Finish。
如果源码里有红叉叉,稍等一会,或者右键项目,在Index-》Rebuild一下,就好了。
然后Debug一下,是否成功了。
下面DisplayImage.cpp里加入我们的代码:
#include
#include
using namespace std;
int main(int argc, char *argv[]) {
GtkWidget *window; //定义一个构件指针
gtk_init(&argc, &argv); //初始化GTK环境
window = gtk_window_new(GTK_WINDOW_TOPLEVEL); //新建一个标准的有框架窗口
gtk_widget_show(window); //显示window
gtk_main(); //启动GTK
return 1;
}
是不是一堆红叉叉(以前有个朋友告诉我最怕这堆路径找不到的玩意,烦):
不怕,我不但告诉你怎么设置这些路径,还告诉你为什么这么设置,让你一辈子都不怕这些红叉叉。
按常识我们觉得应该配置两个事情,一个是让gcc/g++编译器找到相应的头文件和库,另外一个是让Eclipse找到这些头文件和库,前者让编译通过,后者让Eclipse别给我们项目打红叉叉。
先说第1部分配置,让gcc/g++编译器找到相应的头文件和库,在Eclipse里,项目右键点击属性:
然后在C/C++ build Settings ->Configuration 选择【All Configuarations】,在GCC C Compiler,GCC C++ Compiler,GCC C++ Linker右侧的Commandline pattern,最后都加上这么一句:
`pkg-config --cflags --libs gtk+-2.0`, 如下:
为什么这么设置呢,这是由于g++编译器默认的include路径包含其中一项是/usr/include,而系统默认安装的gtk库在/usr/include/gtk-2.0下面,所以我们需要指定该目录才能让g++编译器知道,问题是gtk的头文件又引用了其依赖的头文件,我们总不能把一大堆递归引用的头文件一个一个引进来吧,多麻烦。所以我们就用`pkg-config --cflags --libs gtk+-2.0` 让系统自动找出来。lib的原因也是类似。
设置完这部分之后点击项目右键,build一下,是不是编译成功了:
从上图我们看到编译的命令是:
g++ -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/DisplayImage.d" -MT"src/DisplayImage.o" -o "src/DisplayImage.o" "../src/DisplayImage.cpp" `pkg-config --cflags --libs gtk+-2.0`
g++ -o "DisplayImage" ./src/DisplayImage.o `pkg-config --cflags --libs gtk+-2.0`
你也可以在bash里执行一下:
[root@localhost src]# cd /root/workspace/DisplayImage/src
[root@localhost src]# g++ -o "DisplayImage" ./DisplayImage.cpp `pkg-config --cflags --libs gtk+-2.0`
是不是也成功了。
第2部分配置是让Eclipse里的红叉叉都去掉,这个需要在项目右键点击属性,然后在C/C++ General ->Path and Symbols下面的Configuration 选择【All Configuarations】,在GNU C ,GNU C++ 的Includes里面加入系统安装gtk的Include路径:/usr/include/gtk-2.0,如下图:
然后在Libray Paths里设置gtk的查找路径:
/usr/lib64/gtk-2.0/2.10.0/engines
/usr/lib64/gtk-2.0/modules
如下图:
记得在GNU C ,GNU C++ 里都要设置Libray Paths,然后点击确定后,右键项目Index->Rebuild是不是可爱的红叉叉都没了:
然后我们就可以运行或调试一下了,是不是可爱的GUI界面出来了:
至此说明我们的gtk编程没问题了。
5. 新建项目测试opencv是否可用
和第4部分类似,新建一个C++项目,叫person_detect,我们计划用opencv的hog库来写个行人检测程序。
在person_detect.cpp里写入如下代码:
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
using namespace cv;
static void detectAndDraw(const HOGDescriptor &hog, Mat &img)
{
vector found, found_filtered;
double t = (double) getTickCount();
// Run the detector with default parameters. to get a higher hit-rate
// (and more false alarms, respectively), decrease the hitThreshold and
// groupThreshold (set groupThreshold to 0 to turn off the grouping completely).
hog.detectMultiScale(img, found, 0, Size(8,8), Size(32,32), 1.05, 2);
t = (double) getTickCount() - t;
cout << "detection time = " << (t*1000./cv::getTickFrequency()) << " ms" << endl;
for(size_t i = 0; i < found.size(); i++ )
{
Rect r = found[i];
size_t j;
// Do not add small detections inside a bigger detection.
for ( j = 0; j < found.size(); j++ )
if ( j != i && (r & found[j]) == r )
break;
if ( j == found.size() )
found_filtered.push_back(r);
}
for (size_t i = 0; i < found_filtered.size(); i++)
{
Rect r = found_filtered[i];
// The HOG detector returns slightly larger rectangles than the real objects,
// so we slightly shrink the rectangles to get a nicer output.
r.x += cvRound(r.width*0.1);
r.width = cvRound(r.width*0.8);
r.y += cvRound(r.height*0.07);
r.height = cvRound(r.height*0.8);
rectangle(img, r.tl(), r.br(), cv::Scalar(0,255,0), 3);
}
}
int main(int argc, char** argv) {
HOGDescriptor hog;
hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());
namedWindow( "object detection", CV_WINDOW_AUTOSIZE );
Mat frame;
frame = imread( argv[1], 1 );
if( argc != 2 || !frame.data )
{
printf( "No image data \n" );
return -1;
}
cv::imshow("object detection", frame);
detectAndDraw(hog, frame);
cv::imshow("object detection", frame);
waitKey(0);
return 0;
}
然后在C/C++ build Settings ->Configuration 选择【All Configuarations】,在GCC C Compiler,GCC C++ Compiler,GCC C++ Linker右侧的Commandline pattern,最后都加上这么一句:
`pkg-config --cflags --libs opencv`
在C/C++ General ->Path and Symbols下面的Configuration 选择【All Configuarations】,在GNU C ,GNU C++ 的Includes里面加入系统安装opencv的Include路径:
/usr/local/include/opencv2
/usr/local/include/opencv
在Libray Paths里设置opencv的查找路径:
/usr/local/lib
然后项目右键Index-》Rebuild一下,是不是红叉叉都没了。
然后在Debug设置里,设置一下我们要识别的原始图片,如下图:
然后执行调试一下,是不是可爱的图片识别结果出来了:
至此,我们的环境完全搭建完毕,你可以自由的使用opencv写代码了。
参考:
如果有啥技术问题交流,可以邮件66697561@qq.com联系。
码字码了半天,手指头都麻了,如果觉得对您还有用的话,赞助一下辛苦费吧:
转载本文请联系原作者获取授权,同时请注明本文来自孙鹏科学网博客。
链接地址:http://blog.sciencenet.cn/blog-419883-1097860.html
上一篇:使用百度地图API展示服务端传回的GEOJSON数据(PG JSON系列9)
下一篇:Eclipse CDT中导入OpenCV项目