OpenCV-2.4.3+VS2010+Win7(32位)安装与配置
By 马冬亮(凝霜 ?Loki)
一个人的战争(http://www.sychzs.cn/MDL13412)
开篇
最近开始做毕业设计,其中有一个需求是使用普通摄像头进行图像采集,并生成全景图像。既然涉及到了图像处理,那OpenCV是一个非常不错的选择,在OpenCV官网上浏览了一下,发现新版本的OpenCV-2.4.3中内置了stitching模块,这个模块就是用来做图像拼接的,于是选择最新版本进行配置。
准备工作
配置OpenCV前需要下载并安装的软件:
Visual Studio 2010CMake 2.8
安装OpenCV
下载OpenCV for Windows安装包,下载下来名称为OpenCV-2.4.3.exe;运行安装包,解压到D盘根目录(可以修改为其他目录);运行CMake,设置好OpenCV的源码路径及构建路径,如下图所示:
点击Configure按钮,如下图所示:
在弹出的编译器选择界面中选择Visual Studio 10,如下图所示:
等待配置完成,出现如下界面:
将BUILD_EXAMPLES选项勾上,其余的使用默认配置即可,如果需要使用OpenNI、OpenGL、QT、TBB库的请自行配置库路径;再次点击Configure按钮,再次进行配置;配置成功后,点击Generate按钮,生成VS 2010所需的工程文件;切换目录到D:/OpenCV24(以自己的build路径为准),打开使用VS 2010打开OpenCV.sln;切换Build模式为Debug,右键选择解决方案"OpenCV",在其中选择"重新生成解决方案",如下图所示:
等待Build完成后,找到INSTALL子项目,右键选择"生成",如下图所示:
切换Build模式为Release,重新进行一次构建;
配置OpenCV
用VS2010新建一个控制台项目,创建主文件,文件内容如下:
#include
#include
using namespace cv;
using namespace std;
#pragma comment(lib, "opencv_core243d")
#pragma comment(lib, "opencv_highgui243d")
#pragma comment(lib, "opencv_imgproc243d")
#pragma comment(lib, "opencv_ml243d")
#pragma comment(lib, "opencv_stitching243d")
int main()
{
string imagename = "D:\\1.jpg";
//读入图像
Mat img = imread(imagename);
//如果读入图像失败
if(img.empty())
{
return -1;
}
//创建窗口
namedWindow("image",1);
//显示图像
imshow("image", img);
//等待按键,按键盘任意键返回
waitKey();
return 0;
}
将所需的dll和lib文件拷贝到项目的Debug文件夹内,如下图所示:
接下来,切换到"属性管理器",在项目的"Debug|Win32"下,找到“Microsoft.Cpp.Win32.user”选项,右键选择"属性",如下图所示:
在弹出的属性对话框中,切换到“VC++目录”,如下图所示:
需要配置的选项为"可执行文件目录"、"包含目录"、"库目录",其中"可执行文件目录"和"库目录"配置如上图所示,"包含目录"如下图所示:
Release模式的配置方法与Debug模式类似,不再详述;完成上述配置后,在D盘根目录下保存一个1.jpg图像,在Debug模式下,编译并运行程序,即可测试OpenCV是否配置成功。
结语
OpenCV-2.4.3版本的源码及构建目录结构发生了一些变化,使用老版本的配置方法将不能工作,需要特别注意。另外新版本中的例程增加了很多,对学习OpenCV很有帮助。
另外需要吐槽一句,OpenCV的stitching模块真的很慢,合并10张640*480像素的jpg图像,在我的电脑上要运行2分钟,故不推荐使用。
1.软件获取
源代码、数据、第三方库、CMake安装包的获取地址: 链接:https://www.sychzs.cn/s/1kWwPKbH 密码:v8ci
2.编译准备
先将CMake安装后,将剩余3个文件解压后,并将源代码改名为OSG-Source-3.4.0,数据改名为OSG-Data-3.4.0。而第三方库,需要先将其中的X86文件夹剪切出来,和三个解压文件在同一级目录中,删除原来的3rdParty文件夹,并将X86文件夹改名为3rdParty。此时三个文件夹的目录地址分别为: D:\OSG\OSG-Source-3.4.0 D:\OSG\OSG-Data-3.4.0 D:\OSG\3rdParty将D:\OSG\3rdParty\include\modules内文件全部复制到D:\OSG\3rdParty\include\libxml文件夹内。在D:\OSG\OSG-Source-3.4.0文件夹内建立两个子文件夹build和bin,用于存放CMake生成的工程文件和VS编译后所要INSTALL的库文件等。
3.Cmake编译
按照下图填入源代码位置和CMake所生成的工程的存放位置 将D:\OSG\OSG-Source-3.4.0内的文件CMakeLists.txt拖入CMake,并修改build目录为下图所示: 点击Configure,选择编译器,这里使用的是默认的2010,确定后等待第一轮配置完成。 第一轮Configure完成后需要进行以下手动修改: ACTUAL_3RDPARTY_DIR -> D:/OSG/3rdParty BUILD_OSG_EXAMPLES -> ON CMAKE_INSTALL_PREFIX -> D:/OSG/OSG-Source-3.4.0/bin (即后面INSTALL的输出目录) 该教程与其他不同的地方在于,这里还配置了其他内容,目的就是为了防止出现不能加载tff格式字体和jpg、png格式图片等需要用到第三方插件的功能。先将软件上的Grouped功能勾选上,并修改如下(2处): (第一处)手动找到FREETYPE_LIBRARY_DEBUG为D:\OSG\3rdParty\lib\freetype2311MT_D.lib (第二处)手动找到LIBXML2_INCLUDE_DIR为D:\OSG\3rdParty\include\libxml再次点击Configure,等待第二轮配置完成。 第二轮配置完成后,会看到CMake自动根据我们配置的LIBXML2_INCLUDE_DIR地址补全了Grouped中的LIBXML2,如下图所示: 而后,找到BUILD_MFC_ EXAMPLE选项,选中打钩。最后一次点击Configure,等待第三轮配置完成。完成后,就可以点击Generate选项了,Generate完成之后,所有输出信息如下图所示:
4.VS编译
Step1: 在D:\OSG\OSG-Source-3.4.0\build 目录下找到CMake生成的解决方案 OpenSceneGraph.sln,后双击打开。Step2:找到批生成 Step3:编译程序的Debug版本和Release版本(ALL_BUILD版,作者耗时4:30) 完成后编译输出信息如下图所示: Step4:编译程序的Debug版本和Release版本(INSTALL版,作者耗时15min),并取消ALL_BUILD的选中状态
5.环境变量设定
这里详细说明一下第四步,一般Path变量本身就有的,不需要新建,使用时直接在后面加分号后紧跟新增的Path,这里设置的是D:\OSG\OSG-Source-3.4.0\bin\bin,即“INSTALL”时的导出位置。而像环境变量OSG_FILE_PATH这种属于某个软件专有的变量,就需自己新建一个,新建后,指定路径为D:\OSG\OSG-Data-3.4.0,即解压缩的数据文件所在位置。
6.测试1
使用组合键“WIN+R”,输入“cmd”,进入DOS窗口,使用命令“ osgviewer cow.osg ”,若安装无误,则会正常显示出一条金牛(如下图所示):
7.测试2
先建立一个win32的控制台项目,然后按照正常流程这里需要进行属性配置,包括“包含目录”、“库目录”和“附加依赖项”,但每一次创建一个工程项目都需要这样添加,是不是有点太过麻烦,这里介绍一种建立属性表的方法用于解决,方法如下:
Step1 若是在VS软件中没能找到属性管理器窗口就先按照上图中的方法调出该窗口,紧接着分别在Debug目录和Release目录下创建两个属性表文件,并分别命名为如图名字(可自由定义,但要容易区分) Step2 先双击打开属性表文件OSG_340_VS10_Win32_Debug,进行如下配置: 在包含目录中填入地址:D:\OSG\OSG-Source-3.4.0\bin\include 在库目录中填入地址:D:\OSG\OSG-Source-3.4.0\bin\lib 在第三步指向的输入处,找到附加依赖项,在其中填入以下内容(具体要以D:\OSG\OSG-Source-3.4.0\bin\lib目录下的实际库文件为准,注意这些库文件都带了字母“d”,表示Debug版本): OpenThreadsd.lib osgd.lib osgAnimationd.lib osgDBd.lib osgFXd.lib osgGAd.lib osgManipulatord.lib osgParticled.lib osgPresentationd.lib osgQtd.lib osgShadowd.lib osgSimd.lib osgTerraind.lib osgTextd.lib osgUId.lib osgUtild.lib osgViewerd.lib osgVolumed.lib osgWidgetd.lib 属性表文件OSG_340_VS10_Win32_Release的配置与Debug版本只有附加依赖项上有些许不同,不同之处就是所有的lib文件不带字母“d”,列出如下: OpenThreads.lib osg.lib osgAnimation.lib osgDB.lib osgFX.lib osgGA.lib osgManipulator.lib osgParticle.lib osgPresentation.lib osgQt.lib osgShadow.lib osgSim.lib osgTerrain.lib osgText.lib osgUI.lib osgUtil.lib osgViewer.lib osgVolume.lib osgWidget.lib 最后一定不要忘记分别保存!!!Step3 建立源文件,使用以下代码进行测试:
#include
#include
int main()
{
osg::ref_ptr
viewer->setSceneData(osgDB::readNodeFile("cow.osg"));
return viewer->run();
}
运行结果出现一条金牛,则表示成功。
8.测试3
Case1:是否能显示汉字 运行程序,按“s”键,若出现中文字体,则表示测试成功。Case2:是否能加载jpg等格式图片 若运行程序后能成功显示一个方盒子,并且上面有像生锈一样的贴图则表示测试成功。如果这两项没有测试通过,证明你的OSG并没有配置成功!
??? 在网上有很多有关Ogre嵌入MFC的文章,(我看了几乎所有的有关的文章,下载了几乎所有的所谓的源代码),不过总结起来其实都基本是一个版本的,不知道转载的人没有看懂,有没有亲自编译过,那些教程写的不是很清楚,或者那些就足够一个高手看懂了,但是对一个C++新手而言貌似有点深了,致使很多人照着做却出现很多错误,浪费了很多时间。为了让更多的人更快的学会如何将Ogre嵌入MFC框架之中,便写了这篇教程。废话不多说,直接上教程:
?????? 以下内容是结合网上找的例程进行整理的,主要参考下面链接中文章:但有少许改动以使本程序适合VS2010及Ogre1.8版本,
特别说明:以下文章所述内容可在Win7 -32位系统,XP系统,均可通过正常运行。
原文地址:http://www.sychzs.cn/tulun/article/details/5486828
第一步:建立一个名为OgreMFC的单文档应用程序
点击确定后出现下面界面:
点击下一步:
然后按图上所标示部分进行选择,完成后点击下一步:
其实可以在上一步就点击完成,哈哈。我只是想说明后面都保持的默认值。出现的界面是下面这个样子的,
接下来就是打开头文件OgreMFCView.h粘入以下代码
// OgreMFCView.h : COgreMFCView 类的接口
//
#pragma once
//添加的代码
#include "ogre.h"
#include "OgreConfigFile.h"
using namespace Ogre;
class COgreMFCView : public CView
{
protected: // 仅从序列化创建
COgreMFCView();
DECLARE_DYNCREATE(COgreMFCView)
// 属性
public:
COgreMFCDoc* GetDocument() const;
// 操作
public:
// 重写
public:
virtual void OnDraw(CDC* pDC); // 重写以绘制该视图
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
void setupResources();//添加的代码
// 实现
public:
virtual ~COgreMFCView();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// 生成的消息映射函数
protected:
DECLARE_MESSAGE_MAP()
public:
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
private:
CPoint m_mouseLast;
Root* mRoot;
RenderWindow* mWindow;
SceneManager* mSceneMgr;
Camera* mCamera;//添加的代码
public:
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg void OnTimer(UINT_PTR nIDEvent);
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnDestroy();
};
#ifndef _DEBUG // OgreMFCView.cpp 中的调试版本
inline COgreMFCDoc* COgreMFCView::GetDocument() const
{ return reinterpret_cast
#endif
?然后打开
OgreMFCView.cpp粘入以下代码:
// OgreMFCView.cpp : COgreMFCView 类的实现
//
#include "stdafx.h"
#include "OgreMFC.h"
#include "OgreMFCDoc.h"
#include "OgreMFCView.h"
#define OGRE_DEBUG_MEMORY_MANAGER 1
//#ifdef _DEBUG
//#define new DEBUG_NEW
//#endif
// COgreMFCView
IMPLEMENT_DYNCREATE(COgreMFCView, CView)
BEGIN_MESSAGE_MAP(COgreMFCView, CView)
// 标准打印命令
ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CView::OnFilePrintPreview)
ON_WM_ERASEBKGND()
ON_WM_LBUTTONDOWN()
ON_WM_MOUSEMOVE()
ON_WM_TIMER()
ON_WM_CREATE()
ON_WM_DESTROY()
END_MESSAGE_MAP()
// COgreMFCView 构造/析构
COgreMFCView::COgreMFCView()
{
// TODO: 在此处添加构造代码
mRoot = 0;
}
COgreMFCView::~COgreMFCView()
{
delete mRoot;
}
BOOL COgreMFCView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: 在此处通过修改
// CREATESTRUCT cs 来修改窗口类或样式
return CView::PreCreateWindow(cs);
}
void COgreMFCView::setupResources()
{
// Load resource paths from config file
ConfigFile cf;
cf.load("resources.cfg");
// Go through all sections & settings in the file
ConfigFile::SectionIterator seci = cf.getSectionIterator();
String secName, typeName, archName;
while (seci.hasMoreElements())
{
secName = seci.peekNextKey();
ConfigFile::SettingsMultiMap *settings = seci.getNext();
ConfigFile::SettingsMultiMap::iterator i;
for (i = settings->begin(); i != settings->end(); ++i)
{
typeName = i->first;
archName = i->second;
ResourceGroupManager::getSingleton().addResourceLocation(
archName, typeName, secName);
}
}
}
// COgreMFCView 绘制
void COgreMFCView::OnDraw(CDC*/*pDC*/)
{
static bool once =true;
COgreMFCDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
if(once)
{
mRoot = new Root();
setupResources();
RenderSystemList rl = Root::getSingleton().getAvailableRenderers();
//D3D9RenderSystem
RenderSystem* rsys = NULL;
RenderSystemList::iterator it = rl.begin();
while( it != rl.end() )
{
if( -1 != ( *it )->getName().find("Direct3D9" ) )
{
rsys = (RenderSystem*)( *it );
break;
}
it++;
}
//mRoot->showConfigDialog();
rsys->initConfigOptions();
//rsys->setConfigOption("Colour Depth", "32" );
rsys->setConfigOption("Anti aliasing", "None" );
rsys->setConfigOption("Floating-point mode", "Fastest" );
rsys->setConfigOption( "Full Screen","No" );
rsys->setConfigOption("Rendering Device","NVIDIA GeForce FX 5700VE");
rsys->setConfigOption( "VSync","No" );
//rsys->setConfigOption( "Video Mode", "800 x 600 @ 32-bit colour" );
rsys->setConfigOption( "Video Mode","640 x 480" );
//rsys->setConfigOption( "Display Frequency", "60" );
// 起用
mRoot->setRenderSystem( rsys );
mRoot->initialise( false );
NameValuePairList miscParams;
unsigned int h = (unsigned int)this->GetSafeHwnd();
miscParams["externalWindowHandle"] = StringConverter::toString(h);
mWindow = NULL;
mWindow = mRoot->createRenderWindow( "View", 640, 480,false, &miscParams );
once = false;
mSceneMgr = mRoot->createSceneManager(ST_GENERIC, "ExampleSMInstance");
// Create the camera
mCamera = mSceneMgr->createCamera("PlayerCam");
// Position it at 500 in Z direction
mCamera->setPosition(Vector3(0,0,500));
// Look back along -Z
mCamera->lookAt(Vector3(0,0,-300));
mCamera->setNearClipDistance(5);
// Create one viewport, entire window
Viewport* vp = mWindow->addViewport(mCamera);
vp->setBackgroundColour(ColourValue(0,0,0));
// Alter the camera aspect ratio to match the viewport
mCamera->setAspectRatio(
Real(vp->getActualWidth()) / Real(vp->getActualHeight()));
ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
//createScene();
// Set ambient light
mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));
// Create a skydome
mSceneMgr->setSkyDome(true, "Examples/CloudySky", 5, 8);
// Create a light
Light* l = mSceneMgr->createLight("MainLight");
// Accept default settings: point light, white diffuse, just set position
// NB I could attach the light to a SceneNode if I wanted it to move automatically with
// other objects, but I don't
l->setPosition(20,80,50);
Entity *ent;
// Define a floor plane mesh
Plane p;
p.normal = Vector3::UNIT_Y;
p.d = 200;
MeshManager::getSingleton().createPlane("FloorPlane",
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
p,2000,2000,1,1,true,1,5,5,Vector3::UNIT_Z);
// Create an entity (the floor)
ent = mSceneMgr->createEntity("floor","FloorPlane");
ent->setMaterialName("Examples/RustySteel");
mSceneMgr->getRootSceneNode()->attachObject(ent);
ent = mSceneMgr->createEntity("head","ogrehead.mesh");
// Attach to child of root node, better for culling (otherwise bounds are the combination of the 2)
mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(ent);
mWindow->update();
}
else
{
//mRoot->startRendering();
mWindow->update();
//drawScene();
}
}
// COgreMFCView 打印
BOOL COgreMFCView::OnPreparePrinting(CPrintInfo* pInfo)
{
// 默认准备
return DoPreparePrinting(pInfo);
}
void COgreMFCView::OnBeginPrinting(CDC*/*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: 添加额外的打印前进行的初始化过程
}
void COgreMFCView::OnEndPrinting(CDC*/*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: 添加打印后进行的清除过程
}
// COgreMFCView 诊断
#ifdef _DEBUG
void COgreMFCView::AssertValid()const
{
CView::AssertValid();
}
void COgreMFCView::Dump(CDumpContext& dc)const
{
CView::Dump(dc);
}
COgreMFCDoc* COgreMFCView::GetDocument() const// 非调试版本是内联的
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(COgreMFCDoc)));
return (COgreMFCDoc*)m_pDocument;
}
#endif //_DEBUG
// COgreMFCView 消息处理程序
BOOL COgreMFCView::OnEraseBkgnd(CDC* pDC)
{
// TODO: Add your message handler code here and/or call default
//return CView::OnEraseBkgnd(pDC);
return true;
}
void COgreMFCView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
m_mouseLast = point;
CView::OnLButtonDown(nFlags, point);
}
void COgreMFCView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
if(nFlags & MK_LBUTTON)
{
CPoint mouseDiff = point - m_mouseLast;
m_mouseLast = point;
mCamera->yaw(Degree(mouseDiff.x) * 0.2);
mCamera->pitch(Degree(mouseDiff.y) * 0.2);
}
CView::OnMouseMove(nFlags, point);
}
void COgreMFCView::OnTimer(UINT_PTR nIDEvent)
{
// TODO: Add your message handler code here and/or call default
Invalidate();
CView::OnTimer(nIDEvent);
}
int COgreMFCView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
SetTimer(1, 30, NULL);
return 0;
}
void COgreMFCView::OnDestroy()
{
CView::OnDestroy();
// TODO: Add your message handler code here
KillTimer(1);
}
好了,现在代码部分已经好了,下面就要开始配置工程的属性了:
参照
http://www.sychzs.cn/tikiwiki/tiki-index.php?page=Setting+Up+An+Application+-+Visual+Studio
进行配置,配置完成后;按F7编译一下试试:很不幸运我出了一个错误:
看看错误的说明:?8?IntelliSense: #error 指令: Please use the /MD switch for _AFXDLL builds?
怎么办呢,改变一下吧就:项目属性打开——C\C++——代码生成——运行时库——多线程 DLL (/MD)
再编译一下:
郁闷至极又报错:错误?8?error C1083: 无法打开编译器生成的文件:“Debug\OgreMFCView.obj”: Permission denied?
怎么解决呢:网上有人说直接删除debug下所有文件重新编译一下,开始竟然还删除不掉,只能强力删除了,然后重新编译。
哈哈,编译成功后直接运行出现效果如下所示:
?
补充说明一点,其中我还在此过程中做了如下改动:
1、在项目属性页——C\C++——预处理器——预处理器定义——_AFXDLL。(添加的)
2、如果你在编译时出现了Assertain failed ,那么
看一下ogre.log 文件,发现是FileNotFind,问题解决了,只需要把62行的 cf.load("resources.cfg"); 改成cf.load("resources_d.cfg");即可(Debug下)
3、如果第二步不好使,那么请到你的
把OgreSDK_vc10_v1-8-0/bin/debug中的resources_d.cfg跟plugins_d.cfg文件重命名为resources.cfg和plugins.cfg
按道理来讲,应该不会再有编译错误了。