牛骨文教育服务平台(让学习变的简单)
博文笔记

内容来至(http://blog.csdn.net/dadaadao/rss/list)

创建时间:2016-04-22 投稿人: 浏览次数:2314
dadaadao的专栏
[转]Win7x64+VS2012+OpenCV2.4.3+CMake2.8.10+TBB41重编译OpenCV

PS:请参考最新的《Opencv 完美配置攻略 2014 (Win8.1 + Opencv 2.4.8 + VS 2013)》,绝对给力!由于Opencv版本升级,大多人开始用新版本VS,等等,这篇已经过时了,而且当时没有在文中加入更合适的简介的配置方法,所以有一些东西不再适用。重写一篇,,无论是Win7还是Win8,无论是VS2010, VS2012, 还是VS2013,无论是Opencv 2.x.x,方法都是一样的,只是配置思路和操作流程不同而已。

如果想重新编译Opencv,可以参考本文,不过新版本也许不用配置ttb了吧,没试过。如果有需求再玩玩自己编译的。

posted @ 2013-01-11 19:54 from [FreedomShe]

 

重编译的好处:可以调试的时候看OpenCV的源代码。

重编译要得到的东西:Debug版本和Release版本的dll,lib,头文件。(dll添加到环境变量里,运行时用,自己编译的dll调试时可以跟踪到Opencv的源码内;lib和头文件配置到编译器里)

PS:如果只是使用Opencv而不需要跟踪源码,则使用Opencv自带的库文件即可。跳到5配置Opencv开发环境,对应的文件都在..opencvuild目录下,其中dll(bin目录),lib目录在平台文件夹下如..opencvuild x86vc10。

本机Win7 64位系统,装有VS2012,以编译32位的Opencv库为例,要编译64位库需要注意选择64位的配置。

下载OpenCV2.4.3:http://opencv.org/downloads.html,解压到D:Program Files

下载CMake2.8.10:http://www.cmake.org/cmake/resources/software.html,安装

下载tbb41_20121003oss:http://threadingbuildingblocks.org/download,解压到D:Program Files

Path里添加:D:Program Files bb41_20121003ossinia32vc11

bin目录内ia32表示要编译32位工程,intel64表示要编译64位工程,vc11表示VS版本为2012

新建文件夹OpenCVProject:D:Program FilesOpenCVProject(用于存放自己的OpenCV编译工程)。

打开CMake,"Browse Source..."选择Opencv的目录D:/Program Files/opencv(内有CMake的组态档"CMakeLists.txt"),"Browse Build..."选择刚才自己新建的工程存放路径"D:Program FilesOpenCVProject"。点击Configure按钮,在出现的对话框中选择Visual Studio 11(如果编译64位dll注意选择64位VS11配置),默认Use default native compilers,Finish继续。

image

 

稍等片刻出现该图

第一轮配置完后往下拉,勾选WITH_TBB,点击Configure进入第二轮。

image

 

修改红色部分TBB路径为D:/Program Files/tbb41_20121003oss/include,再次点击Configure;继续点击Configure,直到没有红色标记。

image

 

点击Generate生成Opencv工程,退出CMake。

打开生成的Opencv工程,选择CMakeTargets下INSTALL,右键“生成”,生成Debug版dll,lib。

image

 

切换编译模式为Release模式,重复上一步生成Release版dll,lib。

image

 

上面两步后就能看到最终Debug版和Release版的dll,lib,以及文档目录doc,头文件目录include(bin内为两个版本dll,lib内为两个版本lib)。

image

 

目标达成,在D:Program FilesOpenCVProjectinstall内有我们所要的dll,lib,include头文件,有了这些就可以进行Opencv开发与源码跟踪了。跟dll关联的源代码在Opencv安装目录D:Program Filesopencvmodules内。

我习惯将将D:Program FilesOpenCVProjectinstall拷贝到D:Program Filesopencv下,并将install重命名为vc11x86。而此时D:Program FilesOpenCVProject没有用了,但是不能删除,否则无法跟踪源码,占用6G多空间,可以通过VS2012的“清理解决方案”来减到3G多。

在环境变量Path里添加:D:Program Filesopencvvc11x86in。

6.1    打开VS2012,新建控制台应用程序TestOpencv。

6.2    配置包含目录和库目录

项目->xxx属性->VC++目录->包含目录,添加D:Program Filesopencvvc11x86include

项目->xxx属性->VC++目录->库目录,添加D:Program Filesopencvvc11x86lib

image

 

项目->xxx属性->链接器->输入->附加依赖项,添加lib文件名列表如下图。

image

 

对于配置方案为Debug的配置,添加:

opencv_calib3d243d.libopencv_contrib243d.libopencv_core243d.libopencv_features2d243d.libopencv_flann243d.libopencv_gpu243d.libopencv_highgui243d.libopencv_imgproc243d.libopencv_legacy243d.libopencv_ml243d.libopencv_nonfree243d.libopencv_objdetect243d.libopencv_photo243d.libopencv_stitching243d.libopencv_ts243d.libopencv_video243d.libopencv_videostab243d.lib

对于Release配置,添加

opencv_calib3d243.libopencv_contrib243.libopencv_core243.libopencv_features2d243.libopencv_flann243.libopencv_gpu243.libopencv_highgui243.libopencv_imgproc243.libopencv_legacy243.libopencv_ml243.libopencv_nonfree243.libopencv_objdetect243.libopencv_photo243.libopencv_stitching243.libopencv_ts243.libopencv_video243.libopencv_videostab243.lib

 

Opencv的dll和lib中,末尾带d的就是Debug版本。

6.3    添加测试代码

修改TestOpencv.cpp,代码为:

复制代码
#include "stdafx.h"#include <opencv2opencv.hpp>using namespace cv;using namespace std;int main(){	Mat img = imread("c:/pp.jpg");	if(img.empty())	{		cout<<"error";		return -1;	}	imshow("pp的靓照",img);	waitKey();	return 0;}
复制代码

 

 

将要显示的图片保存为c:/pp.jpg编译运行,显示出图片。

image

 

通过设置断点发现,能够跟踪进入Opencv内部函数。

image


作者:dadaadao 发表于2014/11/5 15:52:35 原文链接 阅读:453 评论:1 查看评论
 
[转]Win32 编程入门


Win32    程序开发的流程

 

message based, event driven

Win32程序是message based, event driven。也就是说Win32程序的运行是依靠外部不断发生的事件来驱动的,也就是说,程序不断等待(有一个while循环),等待任何可能的输入,然后做判断,再做适当的处理。因此Win32程序只需要做好如下几件事情就可以了:

1. 定义窗口的外观;

2. 定义当不同的事件发生时,程序做什么样的反应(定义窗口处理函数);

3. 写一个While循环,不断检测新事件的发生,并将其发送给不同的窗口处理函数

 

程序进入点WinMain

main是一般C程序的进入点:int main( int argc, char *argv[], char *envp[])

Win32程序的进入点是

int CALLBACK WinMain(  __in  HINSTANCE hInstance,  __in  HINSTANCE hPrevInstance,  __in  LPSTR lpCmdLine,  __in  int nCmdShow);

当用户要执行一个程序时,首先是Windows 的Shell(Explorer)调用CreateProcess这个系统调用,CreateProcess为这个进程创建虚拟地址,然后将代码和数据载入,然后系统再创建一个主线程开始执行run time startup函数的代码,run time startup 函数会最终调用入口点函数(main, WinMain)。如果用户执行的是一个Win32程序,那么C startup就会调用WinMain并开始执行程序。

窗口类注册与窗口诞生

如果前面所说,Win32的一个重要的责任是定义窗口外观和窗口处理函数。这是通过窗口类注册来完成的。创建窗口可以使用CreateWindow来完成,但在调用CreateWindow时必须先设定窗口的各种属性和行为。设定窗口属性和行为是通过API 函数 RegisterClass 来完成的。RegisterClass需要一个大型数据结构WNDCLASS,窗口的属性和行为就是在这个数据结构中指定的。

ATOM WINAPI RegisterClass(  __in  const WNDCLASS *lpWndClass);

下面是数据结构WNDCLASS的定义:

typedef struct tagWNDCLASS {
  UINT      style;
  WNDPROC   lpfnWndProc;
  int       cbClsExtra;
  int       cbWndExtra;
  HINSTANCE hInstance;
  HICON     hIcon;
  HCURSOR   hCursor;
  HBRUSH    hbrBackground;
  LPCTSTR   lpszMenuName;
  LPCTSTR   lpszClassName;
} WNDCLASS, *PWNDCLASS;

 

消息循环是怎么工作的

应用程序可以获得的输入有两种类型:硬件装置产生的消息房子系统队列中、由Windows系统或者其他Windows程序传送过来的消息,放在程序队列中。以应用程序的眼光来看,消息就是消息,来自哪里或放在哪里没有太大区别,程序每次GetMessage就取得一个消息。

每个窗口都应该有一个函数负责处理消息,程序员必须负责设计这个所谓的窗口函数(Window Procedure),如果窗口获得一个消息,则这个窗口必须判断消息的类别,决定处理方式。下面是主消息循环的例子:

// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
    if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

GetMessage的原型:

BOOL WINAPI GetMessage(  __out     LPMSG lpMsg,  __in_opt  HWND hWnd,  __in      UINT wMsgFilterMin,  __in      UINT wMsgFilterMax);

调用线程的消息队列中获取一个消息,这个函数会一直等到有一个可用的Message时才会返回; 

int WINAPI TranslateAccelerator(  __in  HWND hWnd,  __in  HACCEL hAccTable,  __in  LPMSG lpMsg);

该函数处理菜单命令中的加速键。该函数将一个WM_KEYDOWN或WM_SYSKEYDOWN消息翻译成一个WM_COMMAND或WM_SYSCOMMAND消息(如果在给定的加速键表中有该键的入口),然后将WM_COMMAND或WM_SYSCOMMAND消息直接送到相应的窗口处理过程。

TranslateMessage是用来把虚拟键消息转换为字符消息。由于Windows对所有键盘编码都是采用虚拟键的定义,这样当按键按下时,并不得字符消息,需要键盘映射转换为字符的消息。
TranslateMessage函数用于将虚拟键消息转换为字符消息。字符消息被投递到调用线程的消息队列中,当下一次调用GetMessage函数时被取出。当我们敲击键盘上的某个字符键时,系统将产生WM_KEYDOWN和WM_KEYUP消息。这两个消息的附加参数(wParam和lParam)包含的是虚拟键代码和扫描码等信息,而我们在程序中往往需要得到某个字符的ASCII码,TranslateMessage这个函数就可以将WM_KEYDOWN和WM_ KEYUP消息的组合转换为一条WM_CHAR消息(该消息的wParam附加参数包含了字符的ASCII码),并将转换后的新消息投递到调用线程的消息队列中。注意,TranslateMessage函数并不会修改原有的消息,它只是产生新的消息并投递到消息队列中。
也就是说TranslateMessage会发现消息里是否有字符键的消息,如果有字符键的消息,就会产生WM_CHAR消息,如果没有就会产生什么消息。

 

windows消息处理机制是这样的: 
首先系统(也就是windows)把来自硬件(鼠标,键盘等消息)和来自应用程序的消息放到一个系统消息队列中去。而应用程序需要有自己的消息队列,也就是线程消息队列,每一个线程有自己的消息队列,对于多线程的应用程序就有和线程数目相等的线程消息队列。winsows消息队列把得到的消息发送到线程消息队列,线程消息队列每次取出一条消息发送到指定窗口,不断循环直到程序退出。这个循环就是靠消息环(while(GetMessage()) TranslateMessage();DispatchMessage(); 实现的.GetMessage()只是从线程消息中取出一条消息,而DispatchMessage 
则把取出的消息发送到目的窗口。如果收到WM_CLOSE消息则结束循环,发送postqiutmessage(0),处理WM_DESTROY销毁窗口! 

其实问题的关键在于DispatchMessage到底干了什么 
如果只是去调用相应的窗口,那自己写个switch不就可以了。DispatchMessage与switch不同之处在于DispatchMessage会先调用windows,进入管态(大概是range 0),然后再由windows调用窗口的函数。 为什么这么麻烦? 因为这样windows就可以知道你的程序运行到什么情况了, windows来调用你的窗口,这样你的窗口返回的时候windows就知道你已经处理过一个消息了,如果没有新的消息进入消息队列windows就不再会给你的进程分配时间片如果是你自己写switch的话,windows就不可能这样灵活的分配时间资源利用率就会降低那么还要消息循环干什么,windows直接把消息发给窗口不就可以了吗?因为你要在消息循环里把KEY_DOWN和KEY_UP组合成WM_CHAR,还可以直接屏蔽掉许多对你来说无用的消息,加快速度。

GetMessage: 从线程的消息队列取出一个消息   
TranslateMessage: 将msg结构传给Windows,进行一些转换,比如A键按下,转换成WM_CHAR消息等   
DispatchMessage():再将msg结构传给Windows,Windows将该消息发给窗口过程,由窗口过程处理.

TranslateMessage是对一些键盘事件做预处理。GetMessage是从系统为每个应用程序自动分配的消息对列的头部得到一个消息。

TranslateMessage是翻译需要翻译的消息

DispatchMessage()则会把翻译好的消息发送到系统的消息处理函数中,而这个函数又会把这个消息传    递到注册窗体时用户指定的消息处理函数中翻译消息不是简单的转换,一个消息被翻译后,可能会产生几个消息。

 

作者:dadaadao 发表于2014/2/28 10:50:40 原文链接 阅读:294 评论:0 查看评论
 
[转]Activex、OLE、COM、OCX、DLL之间的区别(转

熟悉面向对象编程和网络编程的人一定对ActiveX、OLE和COM/DCOM这些概念不会陌生,但是它们之间究竟是什么样的关系,对许多们还是比较模糊的。在具体介绍它们的关系之间,我们还是先明确组件(Component)和对象(Object)之间的区别。

组件是一个可重用的模块,它是由一组处理过程、数据封装和用户接口组成的业务对象(Rules Object)。组件看起来像对象,但不符合对象的学术定义。

它们的主要区别是:

 1)组件可以在另一个称为容器(有时也称为承载者或宿主)的应用程序中使用,也可以作为独立过程使用;

 2)组件可以由一个类构成,也可以由多个类组成,或者是一个完整的应用程序;

 3)组件为模块重用,而对象为代码重用。现在,比较流行的组件模型有COM(Component Objiect Module,对象组件模型)/DCOM( Distributed COM,分布式对象组件模型)和CORBA(Common Object Request Broker Architecture,公共对象请求代理体系结构)。

到这里,已经出现了与本文相关的主题COM,而CORBA与本文无关,就不作介绍。

之所以从组件与对象的区别说起,是想让大家明确COM和 CORBA是处在整个体系结构的最底层,如果暂时对此还不能理解,不妨继续往下看,最后在回过头看一看就自然明白了。

现在开始阐述ActiveX、OLE和COM的关系。首先,让大家有一个总体的概念,从时间的角度讲,OLE是最早出现的,然后是COM和ActiveX;从体系结构角度讲,OLE和ActiveX是建立在 COM之上的,所以COM是基础;单从名称角度讲,OLE、ActiveX是两个商标名称,而COM则是一个纯技术名词,这也是大家更多的听说ActiveX和OLE的原因。

既然OLE是最早出现的,那么就从OLE说起,自从Windows操作系统流行以来,“剪贴板”( Clipboard)首先解决了不同程序间的通信问题(由剪贴板作为数据交换中心,进行复制、粘贴的操作),但是剪贴板传递的都是“死”数据,应用程序开发者得自行编写、解析数据格式的代码,于是动态数据交换(Dynamic Data Exchange,DDE)的通信协定应运而生,它可以让应用程序之间自动获取彼此的最新数据,但是,解决彼此之间的“数据格式”转换仍然是程序员沉重的负担。

对象的链接与嵌入(Object Linking and Embedded,OLE)的诞生把原来应用程序的数据交换提高到“对象交换”,这样程序间不但获得数据也同样获得彼此的应用程序对象,并且可以直接使用彼此的数据内容,其实OLE是Microsoft的复合文档技术,它的最初版本只是瞄准复合文档,但在后续版本OLE2中,导入了COM。

由此可见,COM是应OLE的需求而诞生的,所以虽然COM是OLE的基础,但OLE的产生却在COM之前。 COM的基本出发点是,让某个软件通过一个通用的机构为另一个软件提供服务。COM是应OLE 的需求而诞生,但它的第一个使用者却是OLE2,所以COM与复合文档间并没有多大的关系,实际上,后来COM就作为与复合文档完全无关的技术,开始被广泛应用。

这样一来, Microsoft就开始“染指”通用平台技术。但是COM并不是产品,它需要一个商标名称。而那时Microsoft的市场专家们已经选用了OLE作为商标名称,所以使用COM技术的都开始贴上了 OLE的标签。虽然这些技术中的绝大多数与复合文档没有关系。Microsoft的这一做法让人产生这样一个误解OLE是仅指复合文档呢?还是不单单指复合文档?其实OLE是COM的商标名称,自然不仅仅指复合文档。但Microsoft自己恐怕无法解释清楚,这要花费相当的精力和时间。

于是,随着Internet的发展,在1996年春,Microsoft改变了主意,选择ActiveX作为新的商标名称。ActiveX是指宽松定义的、基于COM的技术集合,而OLE仍然仅指复合文档。当然, ActiveX最核心的技术还是COM。

ActiveX和OLE的最大不同在于,OLE针对的是桌面上应用软件和文件之间的集成,而ActiveX则以提供进一步的网络应用与用户交互为主。到这里,大家应该对ActiveX、OLE和COM三者的关系有了一个比较明确的认识,COM才是最根本的核心技术,所以下面的重点介绍COM。

让对象模型完全独立于编程语言,这是一个非常新奇的思想。这一点从C++和Java的对象概念上,我们就能有所了解。但所谓COM对象究竟是什么呢?为了便于理解,可以把COM看作是某种(软件)打包技术,即把它看作是软件的不同部分,按照一定的面向对象的形式,组合成可以交互的过程和以组支持库。

COM对象可以用C++、Java和VB等任意一种语言编写,并可以用DLL或作为不同过程工作的执行文件的形式来实现。使用COM对象的浏览器,无需关心对象是用什么语言写的,也无须关心它是以DLL还是以另外的过程来执行的。从浏览器端看,无任何区别。这样一个通用的处理技巧非常有用。例如,由用户协调运行的两个应用,可以将它们的共同作业部分作为COM对象间的交互来实现(当然,现在的OLE复合文档也能做到)。为在浏览器中执行从Web服务器下载的代码,浏览器可把它看作是COM对象,也就是说,COM技术也是一种打包可下载代码的标准方法(ActiveX控件就是执行这种功能的)。甚至连应用与本机OS进行交互的方法也可以用COM来指定,例如在Windows和Windows NT中用的是新API,多数是作为COM对象来定义的。可见,COM虽然起源于复合文档,但却可有效地适用于许多软件问题,它毕竟是处在底层的基础技术。用一句话来说,COM是独立于语言的组件体系结构,可以让组件间相互通信。

随着计算机网络的发展,COM进一步发展为分布式组件对象模型,这就是DCOM,它类似于CORBA的ORB,本文对此将不再做进一步的阐述。通过上面的讲述相信大家一定对ActiveX、OLE和COM/DCOM的关系有了一个清楚的了解。

使用Windows的人对于ActiveX控制一定不会陌生,它提供了一种类似于DLL动态链接库的调用,不过它与DLL的唯一区别就是ActiveX不注册不能被系统识别并使用。那么,当我们得到一个ActiveX没有被正确安装且不能使用的消息后,又要安装ActiveX怎么办呢?

1.Regsvr32程序法在Windows的System文件夹下有一个regsvr32.exe的程序,它就是Windows自己带的ActiveX注册和反注册工具。利用它也能够非常方便地注册AcitveX控件,它的用法为:regsvr32/u/s/n/idllname,dllname其中dllname为ActiveX控件文件名,建议在安装前拷贝到System文件夹下参数有如下意义:

    /u- 反注册控件

    /s- 不管注册成功与否,均不显示提示框

    /c -控制台输出

    /i- 跳过控件的选项进行安装 (与注册不同)

    /n- 不注册控件,此选项必须与/i 选项一起使用

例如笔者要注册一amovie.ocx控件,则打入 regsvr32 amovie.ocx即可,要反注册它时只需使用regsvr32 /u amovie.ocx就行了。

2.注册表法所谓注册AcitveX,无非是将一些信息记录在Windows的注册表中,如ShockwaveFlashObject控件,我们可以运行Regedit.exe注册表编辑程序,利用关键字进行搜索,然后把搜索得到后的注册表导出为一REG注册表文件,再将其相应的ActiveX文件拷贝到Windows的System文件夹(一般ActiveX的文件名为OCX,安装在Windows的System文件夹内)下,最后在要安装ActiveX的机器上双击导入刚才导出的注册表文件即可完成安装。

  总结:Activex,OLE,COM都是微软的一些技术标准。Ole比较老后来发展成Activex,再后来发展成为COM OCX,DLL是扩展名。 Activex有两种扩展名OCX和DLL。实际上你可以把它们的扩暂名字调换。 COM作为ActiveX的更新技术,扩展名也有可能是DLL DLL文件还有可能是动态链接库。主要是装载一些函数,可以动态加载。 作者:dadaadao 发表于2013/11/22 11:48:34 原文链接 阅读:438 评论:0 查看评论
 
[转]classView不显示已存在的类向导

最近在做一个VC++程序,在做的过程中出现一个问题:视图类明明存在可是在ClassView中竟然没有类的相关信息,这是怎么回事呢,网上查资料,原来是vc++ 6.0的一个非常经典的bug.

解决:打开工程所在项目----->找到一个以.ncb结尾的文件,将其删除----->再次打开工程----->看到完整的类信息了----->解决。

注:

NCB是 “No Compile Browser”的缩写,其中存放了供ClassView、WizardBar和Component Gallery使用的信息,由VC开发环境自动生成。无编译浏览文件。当自动完成功能出问题时可以删除此文件。编译工程后会自动生成。

 

作者:dadaadao 发表于2012/7/13 10:41:43 原文链接 阅读:372 评论:0 查看评论
 
[转]mfc的CDialogBar
一、创建DialogBar的派生类 首先,创建对话框资源:在对话框资源编辑器内生成一个Dialog资源,并将其风格(Style)属性必须设置为Child,不能设置为Overlapped或Popup,否则运行肯定出错;至于边界属性则随用户自己喜欢,一般都是选择None。其余属性也随用户选择,一般没有特殊要求还是选择默认的好。 其次,创建基于CDialog的派生类:打开ClassWizard,为以上创建的资源添加一个以CDialog为基类的派生类(因为ClassWizard没有将CDialogBar列在基类目录清单中,所以用户只能先以CDialog类派生)。 再次,修改派生类以CDialogBar为基类:通常需要手工修改几处代码,在本例中派生类以CDataStatus命名。(注:以后讲解中凡是手工改动都是以灰背景显示) 1、   在头文件中修改继承关系 将class CDataStatus : public CDialog   改为class CDataStatus : public CDialogBar 2、   在代码文件中修该构造函数继承关系 将CDataStatus::CDataStatus(CWnd* pParent /*=NULL*/) : CDialog(CDataStatus::IDD, pParent) {         //{{AFX_DATA_INIT(CDataStatus)                // NOTE: the ClassWizard will add member initialization here         //}}AFX_DATA_INIT } 改为 CDataStatus::CDataStatus(CWnd* pParent /*=NULL*/)
{
        //{{AFX_DATA_INIT(CDataStatus)
               // NOTE: the ClassWizard will add member initialization here
        //}}AFX_DATA_INIT
}
3、   将DDX绑定函数中的继承关系去掉 即将void CDataStatus::DoDataExchange(CDataExchange* pDX) {
        CDialog::DoDataExchange(pDX);         //{{AFX_DATA_MAP(CCurrentCheckDlg)         ………..         //}}AFX_DATA_MAP } 改为 void CDataStatus::DoDataExchange(CDataExchange* pDX)
{
        //{{AFX_DATA_MAP(CCurrentCheckDlg)
        ………….
        //}}AFX_DATA_MAP
}
4、   重新初始化函数(这个相当重要,如果不这么做的话,DDX函数形同虚设,当然用户的工具条如果没有用到DDX的话当然可以不加这段代码): 首先在ClassWizard的MessageMap中对消息该CDataStatus类的WM_INITDIALOG消息添加处理函数默认名为OnInitDialog。 其次手工修改代码如下: 1、              添加消息映射函数。由于对话框形式的初始化函数消息并未加载到消息映射内,为此我们需要手工添加,要不然代码无法拦截该工具条的初始化消息,形式如下: 将BEGIN_MESSAGE_MAP(CDataStatus, CDialogBar)     //{{AFX_MSG_MAP(CDataStatus)     .......     //}}AFX_MSG_MAP END_MESSAGE_MAP() 改为: BEGIN_MESSAGE_MAP(CDataStatus, CDialogBar)
    //{{AFX_MSG_MAP(CDataStatus)
    .......
    ON_MESSAGE(WM_INITDIALOG,OnInitDialog)
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()
2、              修改OnInitDialog函数,此函数并未传递参数,但是在这里我们需要让它传递参数,代码如下修改(当然头文件中,对声明也要做修改,在这里就不作赘述了) 将BOOL CDataStatus::OnInitDialog() {     CDialogBar::OnInitDialog();         // TODO: Add extra initialization here     return TRUE;   // return TRUE unless you set the focus to a control                // EXCEPTION: OCX Property Pages should return FALSE } 改为: BOOL CDataStatus::OnInitDialog(UINT wParam,LONG lParam)
{
    //CDialogBar::OnInitDialog();
   
    // TODO: Add extra initialization here
    BOOL bRet = HandleInitDialog(wParam,lParam);
    if (!UpdateData(FALSE))
    {
           TRACE("InitCDataStatus Failed!");
    }
    return TRUE;   // return TRUE unless you set the focus to a control
                  // EXCEPTION: OCX Property Pages should return FALSE
}


二、在框架类中实现该派生类的对象化 首先,在框架类的头文件内声明实例对象,本例实例化:CDataStatus       m_wndDataStatus;当然头文件中不可避免要包含新派生类的头文件。 其次,在框架类的OnCreate函数内创建对象并将对象绑定对话框资源。形式与创建ToolBar原理一样,本例实例如下: if (!m_wndDataStatus.Create(this,IDD_DATASTATUS,WS_VISIBLE|WS_CHILD
|CBRS_SIZE_DYNAMIC|CBRS_BOTTOM,IDD_DATASTATUS))
        {
               TRACE0("Failed to create CDataStatus bar!");
               return -1;
        }
再次,最为关键的一点就是重写框架类的OnCmdMsg虚函数。如果不重写该函数,那么不光DDX功能无法实现,连最基本的OnCommand事件都无法实现。而且还得手工添加代码,形式如下: BOOL CMainFrame::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) {         // TODO: Add your specialized code here and/or call the base class         return CFrameWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo); } 改为: BOOL CMainFrame::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
{
        // TODO: Add your specialized code here and/or call the base class
        if (m_wndDataStatus.OnCmdMsg(nID,nCode,pExtra,pHandlerInfo))
               return     TRUE;
        return CFrameWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}  
步骤1:添加一个CDialogBar派生类
     在资源中添加一个对话框,再采用类向导来添加类,找不到CDialogBar作为基类吧,可以先用CDialog作为基类产生一个,然后把所以的“CDialog”替换为“CDialogBar”,替换完成了。编译一下,^_^有错误吧!!请看步骤2。
     步骤2:解决编译错误并完善该类
     其实错误就是构着函数调用基类时有问题,: CDialogBar(/*CDlgBar::IDD, pParent*/)象这样注释掉就可以了,添加一个类似OnInitDialog的函数,在CDialogBar中是不存在OnInitDialog的消息的,至少我还不知道,因为初始化是在创建后调用的所以我们就重写virtual BOOL Create(CWnd* pParentWnd,UINT nIDTemplate,UINT nStyle,UINT nID);这个函数。注意哦用向导添加的Create函数的参数是不对的喔,看上面。下面是实现代码(很简单的)
BOOL CDlgXXX::Create(CWnd* pParentWnd,UINT nIDTemplate,UINT nStyle,UINT nID) 
{
// TODO: Add your specialized code here and/or call the base class
BOOL bRes= CDialogBar::Create(pParentWnd,nIDTemplate,nStyle,nID );
InitDialogBar();//在类中添加一个成员函数就可以了
return bRes;
}
BOOL CDlgXXX::InitDialogBar()
{
UpdateData(FALSE);//这个一定要啊,这样就会有和CDialog一样的数据交换效果了

return TRUE;
}
     步骤3:创建和使用
      if (!m_barAttrib.Create(this,IDD_DLG_COM_ATTRIB, CBRS_RIGHT|CBRS_GRIPPER, XXX))
{
    TRACE0("Failed to create dialogbar ");
    return -1;
}
m_barAttrib.SetWindowText("部件属性");
XXX是一个资源id手工直接在资源的.h文件中添加一条,不会,这里就不教了
工具条的显示和隐藏代码如下,自己慢慢理解吧:
ShowControlBar(&m_barAttrib, (m_barAttrib.GetStyle() & WS_VISIBLE) == 0, FALSE);
     上面代码实现后DoDataExchange也是可以用,给控件添加控件就和CDialog一样的方便咯
但是还有一个要注意的是就是控件类对象的添加,我试了一下好像不行,窗口句柄好像
总是0的,不能使用。还是使用GetDlgItem(IDC_DRIVER_LIST)来取得控件指针吧。

     其他方面的心得
     利用DoDataExchange来控制自定义的输入格式控制这里就举一个文本框的例子
给文本控件添加完变量后就在DoDataExchange会出现如下代码
DDX_Text(pDX, IDC_COM_VAR, m_strVar);//系统产生的
DDV_MaxChars(pDX, m_strVar,VAR_MAX_LEN);//加入长度控制后产生的
DDV_FileNameString(pDX, m_strVar);//自定义的手工添加的实现见下面
void CXXX::DDV_FileNameString(CDataExchange *pDX, CString m_strFileName)
{
CString strError=_T("\/:*?"<>|");
if(m_strFileName.SpanExcluding(strError) != m_strFileName)
{
   ::AfxMessageBox(_T("文件名中不能包含"+strError+"字符"));
   pDX->Fail();//关键是这句执行这句后就会抛出异常下面的语句就不执行了
}
}
还有几个注意点是
1.只有执行了UpdateData()才会调用DoDataExchange函数若中途 执行了pDX->Fail(); UpdateData()就返回FALSE。
2. DDX_Text(pDX, IDC_COM_VAR, m_strVar);//系统产生的
DDV_MaxChars(pDX, m_strVar,VAR_MAX_LEN);//加入长度控制后产生的
DDV_FileNameString(pDX, m_strVar);//自定义的手工添加的实现见下面
如上面几句都是对一个控件的内容的控制,他们必须放在一块,且DDX_Text要放在第一句,这样在界面上就可以正确的指出那个控件的内容有问题,控件会被设置焦点并选中全部内容。

如果你想实现有工具条的浮动和定位功能,而且可以方便的摆放任何控件上去,那就使用CDialogBar就可以拥有和CDialog一样的方便和快捷。
       添加一个CDialogBar派生类:在资源中添加一个对话框,再采用类向导来添加类,这里我们找不到CDialogBar作为基类,可以先用CDialog作为基类产生一个,然后把所以的“CDialog”替换为“CDialogBar”。
构造函数CXXXDlg::CXXXDlg(CWnd* pParent /*=NULL*/)
     : CDialog(CXXXDlg::IDD, pParent)改成: CXXXDlg::CXXXDlg()就可以了,添加一个类似OnInitDialog的函数,在CDialogBar中是不存在OnInitDialog的消息的,因为初始化是在创建后调用的,所以我们就重写virtual BOOL Create(CWnd* pParentWnd,UINT nIDTemplate,UINT nStyle,UINT nID)这个函数。注意哦用向导添加的Create函数的参数是不对的,改成上面。下面是实现代码:
BOOL CXXXDlg::Create(CWnd* pParentWnd,UINT nIDTemplate,UINT nStyle,UINT nID) 
{
BOOL bRes= CDialogBar::Create(pParentWnd,nIDTemplate,nStyle,nID );
InitDialogBar();//在类中添加一个成员函数就可以了
return bRes;
}
BOOL CXXXDlg::InitDialogBar()
{
UpdateData(FALSE);//这个一定要啊,这样就会有和CDialog一样的数据交换效果了
return TRUE;
}
创建和使用:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)

if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
    return -1;
if (!m_wndColor.Create(this, IDD_COLOR,
    CBRS_BOTTOM | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_HIDE_INPLACE,
    ID_VIEW_COLOR))
{
    TRACE0("Failed to create dialog bar m_wndContentMenu ");
    return -1;    // fail to create
}
m_wndColor.EnableDocking(CBRS_ALIGN_BOTTOM );
DockControlBar(&m_wndColor);//没有这个,CDialogBar不可以移动,FloatControlBar的功能是浮动在窗口上。
EnableDocking(CBRS_ALIGN_ANY);
m_wndColor.SetWindowText(_T("颜色"));
return 0;
}
IDD_COLOR是CDialogBar的对话框ID,ID_VIEW_COLOR是一个菜单资源id,在
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
//{{AFX_MSG_MAP(CMainFrame)
ON_WM_CREATE()
ON_COMMAND_EX(ID_VIEW_COLOR, OnBarCheck)
ON_UPDATE_COMMAND_UI(ID_VIEW_COLOR, OnUpdateControlBarMenu) 
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
时,工具条可以显示和隐藏。

想在CDialogBar上添加按钮消息还需要修改如下:
BOOL CMainFrame::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
{
// TODO: Add your specialized code here and/or call the base class
if (m_wndColor.OnCmdMsg(nID,nCode,pExtra,pHandlerInfo))
    return TRUE;
return CFrameWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}   
m_wndColor为CDialogBar对象,这样,按钮的消息可以映射到自己的类中。

这里增加一条关于对话框上响应键盘按键消息,重载
BOOL CXXXDlg::PreTranslateMessage(MSG* pMsg) 
{
if( pMsg->message>=WM_KEYDOWN && pMsg->message<=WM_KEYUP)
{
    this->SendMessage(pMsg->message,pMsg->wParam,pMsg->lParam);
    return TRUE;
}
      else
          return CDialog::PreTranslateMessage(pMsg);
}
这样就可以在对话框上重载WM_KEYDOWN和WM_KEYUP来编写代码了。

    第3中方法:定义 CDialogBar m_wndImagesInDB; 然后在OnCreate中增加

 // TODO: Add a menu item that will toggle the visibility of the
 // dialog bar named "ImagesInDB":
 //   1. In ResourceView, open the menu resource that is used by
 //      the CMainFrame class
 //   2. Select the View submenu
 //   3. Double-click on the blank item at the bottom of the submenu
 //   4. Assign the new item an ID: CG_ID_VIEW_IMAGESINDB
 //   5. Assign the item a Caption: ImagesInDB

 // TODO: Change the value of CG_ID_VIEW_IMAGESINDB to an appropriate value:
 //   1. Open the file resource.h
 // CG: The following block was inserted by the "Dialog Bar" component
  // Initialize dialog bar m_wndImagesInDB
  if (!m_wndImagesInDB.Create(this, CG_IDD_IMAGESINDB,
   CBRS_LEFT | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_HIDE_INPLACE,
   CG_ID_VIEW_IMAGESINDB))
  {
   TRACE0("Failed to create dialog bar m_wndImagesInDB ");
   return -1;  // fail to create
  }
  
  m_wndImagesInDB.EnableDocking(CBRS_ALIGN_LEFT | CBRS_ALIGN_RIGHT);
  EnableDocking(CBRS_ALIGN_ANY);
  DockControlBar(&m_wndImagesInDB);

其中要在resource.h中定义#define CG_ID_VIEW_IMAGESINDB           103
CG_IDD_IMAGESINDB为对话框的名字   CListCtrl*  pList = (CListCtrl*)m_wndImagesInDB.GetDlgItem(IDC_LIST1);
  VERIFY(pList); 做一个关联就可以了     作者:dadaadao 发表于2012/7/11 12:49:13 原文链接 阅读:2602 评论:0 查看评论
 
[转]【引用】关于图像特征提取
  本文引用自yuweiisme《关于图像特征提取》

 网上发现一篇不错的文章,是关于图像特征提取的,给自己做的项目有点类似,发出来供大家参考。

       特征提取是计算机视觉和图像处理中的一个概念。它指的是使用计算机提取图像信息,决定每个图像的点是否属于一个图像特征。特征提取的结果是把图像上的点分为不同的子集,这些子集往往属于孤立的点、连续的曲线或者连续的区域。 
特征的定义 
        至今为止特征没有万能和精确的定义。特征的精确定义往往由问题或者应用类型决定。特征是一个数字图像中“有趣”的部分,它是许多计算机图像分析算法的起点。因此一个算法是否成功往往由它使用和定义的特征决定。因此特征提取最重要的一个特性是“可重复性”:同一场景的不同图像所提取的特征应该是相同的。 
        特征提取是图象处理中的一个初级运算,也就是说它是对一个图像进行的第一个运算处理。它检查每个像素来确定该像素是否代表一个特征。假如它是一个更大的算法的一部分,那么这个算法一般只检查图像的特征区域。作为特征提取的一个前提运算,输入图像一般通过高斯模糊核在尺度空间中被平滑。此后通过局部导数运算来计算图像的一个或多个特征。 
       有时,假如特征提取需要许多的计算时间,而可以使用的时间有限制,一个高层次算法可以用来控制特征提取阶层,这样仅图像的部分被用来寻找特征。 
        由于许多计算机图像算法使用特征提取作为其初级计算步骤,因此有大量特征提取算法被发展,其提取的特征各种各样,它们的计算复杂性和可重复性也非常不同。 
边缘 
        边缘是组成两个图像区域之间边界(或边缘)的像素。一般一个边缘的形状可以是任意的,还可能包括交叉点。在实践中边缘一般被定义为图像中拥有大的梯度的点组成的子集。一些常用的算法还会把梯度高的点联系起来来构成一个更完善的边缘的描写。这些算法也可能对边缘提出一些限制。 
局部地看边缘是一维结构。 
角 
        角是图像中点似的特征,在局部它有两维结构。早期的算法首先进行边缘检测,然后分析边缘的走向来寻找边缘突然转向(角)。后来发展的算法不再需要边缘检测这个步骤,而是可以直接在图像梯度中寻找高度曲率。后来发现这样有时可以在图像中本来没有角的地方发现具有同角一样的特征的区域。 
区域 
       与角不同的是区域描写一个图像中的一个区域性的结构,但是区域也可能仅由一个像素组成,因此许多区域检测也可以用来监测角。一个区域监测器检测图像中一个对于角监测器来说太平滑的区域。区域检测可以被想象为把一张图像缩小,然后在缩小的图像上进行角检测。 
脊 
        长条形的物体被称为脊。在实践中脊可以被看作是代表对称轴的一维曲线,此外局部针对于每个脊像素有一个脊宽度。从灰梯度图像中提取脊要比提取边缘、角和区域困难。在空中摄影中往往使用脊检测来分辨道路,在医学图像中它被用来分辨血管。 
特征抽取 
        特征被检测后它可以从图像中被抽取出来。这个过程可能需要许多图像处理的计算机。其结果被称为特征描述或者特征向量。 
常用的图像特征有颜色特征、纹理特征、形状特征、空间关系特征。 
一 颜色特征 
(一)特点:颜色特征是一种全局特征,描述了图像或图像区域所对应的景物的表面性质。一般颜色特征是基于像素点的特征,此时所有属于图像或图像区域的像素都有各自的贡献。由于颜色对图像或图像区域的方向、大小等变化不敏感,所以颜色特征不能很好地捕捉图像中对象的局部特征。另外,仅使用颜色特征查询时,如果数据库很大,常会将许多不需要的图像也检索出来。颜色直方图是最常用的表达颜色特征的方法,其优点是不受图像旋转和平移变化的影响,进一步借助归一化还可不受图像尺度变化的影响,基缺点是没有表达出颜色空间分布的信息。 
(二)常用的特征提取与匹配方法 
(1) 颜色直方图 
        其优点在于:它能简单描述一幅图像中颜色的全局分布,即不同色彩在整幅图像中所占的比例,特别适用于描述那些难以自动分割的图像和不需要考虑物体空间位置的图像。其缺点在于:它无法描述图像中颜色的局部分布及每种色彩所处的空间位置,即无法描述图像中的某一具体的对象或物体。 
         最常用的颜色空间:RGB颜色空间、HSV颜色空间。 
         颜色直方图特征匹配方法:直方图相交法、距离法、中心距法、参考颜色表法、累加颜色直方图法。 
(2) 颜色集 
        颜色直方图法是一种全局颜色特征提取与匹配方法,无法区分局部颜色信息。颜色集是对颜色直方图的一种近似首先将图像从 RGB颜色空间转化成视觉均衡的颜色空间(如 HSV 空间),并将颜色空间量化成若干个柄。然后,用色彩自动分割技术将图像分为若干区域,每个区域用量化颜色空间的某个颜色分量来索引,从而将图像表达为一个二进制的颜色索引集。在图像匹配中,比较不同图像颜色集之间的距离和色彩区域的空间关系 
(3) 颜色矩 
        这种方法的数学基础在于:图像中任何的颜色分布均可以用它的矩来表示。此外,由于颜色分布信息主要集中在低阶矩中,因此,仅采用颜色的一阶矩(mean)、二阶矩(variance)和三阶矩(skewness)就足以表达图像的颜色分布。 
(4) 颜色聚合向量 
        其核心思想是:将属于直方图每一个柄的像素分成两部分,如果该柄内的某些像素所占据的连续区域的面积大于给定的阈值,则该区域内的像素作为聚合像素,否则作为非聚合像素。 
(5) 颜色相关图 
二 纹理特征 
(一)特点:纹理特征也是一种全局特征,它也描述了图像或图像区域所对应景物的表面性质。但由于纹理只是一种物体表面的特性,并不能完全反映出物体的本质属性,所以仅仅利用纹理特征是无法获得高层次图像内容的。与颜色特征不同,纹理特征不是基于像素点的特征,它需要在包含多个像素点的区域中进行统计计算。在模式匹配中,这种区域性的特征具有较大的优越性,不会由于局部的偏差而无法匹配成功。作为一种统计特征,纹理特征常具有旋转不变性,并且对于噪声有较强的抵抗能力。但是,纹理特征也有其缺点,一个很明显的缺点是当图像的分辨率变化的时候,所计算出来的纹理可能会有较大偏差。另外,由于有可能受到光照、反射情况的影响,从2-D图像中反映出来的纹理不一定是3-D物体表面真实的纹理。 
        例如,水中的倒影,光滑的金属面互相反射造成的影响等都会导致纹理的变化。由于这些不是物体本身的特性,因而将纹理信息应用于检索时,有时这些虚假的纹理会对检索造成“误导”。 
        在检索具有粗细、疏密等方面较大差别的纹理图像时,利用纹理特征是一种有效的方法。但当纹理之间的粗细、疏密等易于分辨的信息之间相差不大的时候,通常的纹理特征很难准确地反映出人的视觉感觉不同的纹理之间的差别。 
(二)常用的特征提取与匹配方法 
  纹理特征描述方法分类 
(1)统计方法统计方法的典型代表是一种称为灰度共生矩阵的纹理特征分析方法Gotlieb 和 Kreyszig 等人在研究共生矩阵中各种统计特征基础上,通过实验,得出灰度共生矩阵的四个关键特征:能量、惯量、熵和相关性。统计方法中另一种典型方法,则是从图像的自相关函数(即图像的能量谱函数)提取纹理特征,即通过对图像的能量谱函数的计算,提取纹理的粗细度及方向性等特征参数 
(2)几何法 
        所谓几何法,是建立在纹理基元(基本的纹理元素)理论基础上的一种纹理特征分析方法。纹理基元理论认为,复杂的纹理可以由若干简单的纹理基元以一定的有规律的形式重复排列构成。在几何法中,比较有影响的算法有两种:Voronio 棋盘格特征法和结构法。 
(3)模型法 
        模型法以图像的构造模型为基础,采用模型的参数作为纹理特征。典型的方法是随机场模型法,如马尔可夫(Markov)随机场(MRF)模型法和 Gibbs 随机场模型法 
(4)信号处理法 
        纹理特征的提取与匹配主要有:灰度共生矩阵、Tamura 纹理特征、自回归纹理模型、小波变换等。 
        灰度共生矩阵特征提取与匹配主要依赖于能量、惯量、熵和相关性四个参数。Tamura 纹理特征基于人类对纹理的视觉感知心理学研究,提出6种属性,即:粗糙度、对比度、方向度、线像度、规整度和粗略度。自回归纹理模型(simultaneous auto-regressive, SAR)是马尔可夫随机场(MRF)模型的一种应用实例。 
三 形状特征 
(一)特点:各种基于形状特征的检索方法都可以比较有效地利用图像中感兴趣的目标来进行检索,但它们也有一些共同的问题,包括:①目前基于形状的检索方法还缺乏比较完善的数学模型;②如果目标有变形时检索结果往往不太可靠;③许多形状特征仅描述了目标局部的性质,要全面描述目标常对计算时间和存储量有较高的要求;④许多形状特征所反映的目标形状信息与人的直观感觉不完全一致,或者说,特征空间的相似性与人视觉系统感受到的相似性有差别。另外,从 2-D 图像中表现的 3-D 物体实际上只是物体在空间某一平面的投影,从 2-D 图像中反映出来的形状常不是 3-D 物体真实的形状,由于视点的变化,可能会产生各种失真。 
(二)常用的特征提取与匹配方法 
Ⅰ几种典型的形状特征描述方法 
        通常情况下,形状特征有两类表示方法,一类是轮廓特征,另一类是区域特征。图像的轮廓特征主要针对物体的外边界,而图像的区域特征则关系到整个形状区域。 
几种典型的形状特征描述方法: 
(1)边界特征法该方法通过对边界特征的描述来获取图像的形状参数。其中Hough 变换检测平行直线方法和边界方向直方图方法是经典方法。Hough 变换是利用图像全局特性而将边缘像素连接起来组成区域封闭边界的一种方法,其基本思想是点—线的对偶性;边界方向直方图法首先微分图像求得图像边缘,然后,做出关于边缘大小和方向的直方图,通常的方法是构造图像灰度梯度方向矩阵。 
(2)傅里叶形状描述符法 
        傅里叶形状描述符(Fourier shape deors)基本思想是用物体边界的傅里叶变换作为形状描述,利用区域边界的封闭性和周期性,将二维问题转化为一维问题。 
        由边界点导出三种形状表达,分别是曲率函数、质心距离、复坐标函数。 
(3)几何参数法 
        形状的表达和匹配采用更为简单的区域特征描述方法,例如采用有关形状定量测度(如矩、面积、周长等)的形状参数法(shape factor)。在 QBIC 系统中,便是利用圆度、偏心率、主轴方向和代数不变矩等几何参数,进行基于形状特征的图像检索。 
        需要说明的是,形状参数的提取,必须以图像处理及图像分割为前提,参数的准确性必然受到分割效果的影响,对分割效果很差的图像,形状参数甚至无法提取。 
(4)形状不变矩法 
利用目标所占区域的矩作为形状描述参数。 
(5)其它方法 
        近年来,在形状的表示和匹配方面的工作还包括有限元法(Finite Element Method 或 FEM)、旋转函数(Turning )和小波描述符(Wavelet Deor)等方法。 
Ⅱ 基于小波和相对矩的形状特征提取与匹配 
        该方法先用小波变换模极大值得到多尺度边缘图像,然后计算每一尺度的 7个不变矩,再转化为 10 个相对矩,将所有尺度上的相对矩作为图像特征向量,从而统一了区域和封闭、不封闭结构。 
四 空间关系特征 
(一)特点:所谓空间关系,是指图像中分割出来的多个目标之间的相互的空间位置或相对方向关系,这些关系也可分为连接/邻接关系、交叠/重叠关系和包含/包容关系等。通常空间位置信息可以分为两类:相对空间位置信息和绝对空间位置信息。前一种关系强调的是目标之间的相对情况,如上下左右关系等,后一种关系强调的是目标之间的距离大小以及方位。显而易见,由绝对空间位置可推出相对空间位置,但表达相对空间位置信息常比较简单。 
        空间关系特征的使用可加强对图像内容的描述区分能力,但空间关系特征常对图像或目标的旋转、反转、尺度变化等比较敏感。另外,实际应用中,仅仅利用空间信息往往是不够的,不能有效准确地表达场景信息。为了检索,除使用空间关系特征外,还需要其它特征来配合。 
(二)常用的特征提取与匹配方法 
        提取图像空间关系特征可以有两种方法:一种方法是首先对图像进行自动分割,划分出图像中所包含的对象或颜色区域,然后根据这些区域提取图像特征,并建立索引;另一种方法则简单地将图像均匀地划分为若干规则子块,然后对每个图像子块提取特征,并建立索引。 
姿态估计问题就是:确定某一三维目标物体的方位指向问题。姿态估计在机器人视觉、动作跟踪和单照相机定标等很多领域都有应用。 
        在不同领域用于姿态估计的传感器是不一样的,在这里主要讲基于视觉的姿态估计。 
        基于视觉的姿态估计根据使用的摄像机数目又可分为单目视觉姿态估计和多目视觉姿态估计。根据算法的不同又可分为基于模型的姿态估计和基于学习的姿态估计。 
一基于模型的姿态估计方法&nbs

声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。