文章主要就以下两种情况提出解决方法:
情况一:将在自己电脑上可以运行的基于opencv的工程拷贝到别人(主要是老师)电脑上,免去别人对库文件和目录文件以及lib的配置。
情况二:将在自己电脑上可以运行的基于opencv的程序(exe)拷贝到没有装有cv库的电脑上做演示运行。
一、首先就情况一展示下自己的具体配置过程:配置原理可参加上一篇博文http://blog.csdn.net/lanbing510/article/details/8806602。
1 将\opencv\build目录下的include文件夹及\opencv\build\x86\vc10下的bin和lib文件夹拷贝到工程所在目录(及C++ Project或stdafx.h所在的那一级目录)。
2 添加目录,为了实现情况一,需要用相对路径,先相对路径进行下科普,'.\'代表本级目录,'..\'代表上级目录,注意:'\'是VC保留字,所以在你写程序时要用到'\'时就要用'\\'代替。网络路径用'/'。具体的配置如下图:
Link的配置如往常一样,只需加入这些常用lib:
opencv_nonfree243d.lib
opencv_legacy243d.lib
opencv_imgproc243d.lib
opencv_core243d.lib
opencv_highgui243d.lib
opencv_video243d.lib
opencv_ml243d.lib
opencv_features2d243d.lib
2 编译后然后把相应的dll文件放到exe所在目录就ok了;但如果dll太多,这样看起来现的很臃肿,想要把dll文件集中的各个不同的文件夹,然后让程序运行时去选择,一种方法是设置环境变量,但问题来了,不能说到了老师那里你再去当场配置环境变量,如果对方没有相应的库,更别提会有相应的环境变量设置。
解决方法是做如下配置(前提是已经按步骤1将dll所在文件夹bin拷贝到了工程所在目录):
即,在Environment选项中设置path,这样也可以使用多个文件夹中的dll。简洁清晰。
3 做了以上配置后就可以编译运行了。
二、就情况二做下简单提示。
如果对方不需要源代码和工程,只用作展示,则可以直接将bin文件夹拷贝到exe文件所在目录(vs一般问debug或release文件夹下),但是你会发现,双击exe并不能正常运行,而是提示你找不到dll,像上面所提到的,你不可能不配置环境变量或着将dll文件放到和exe同一级目录中而运行程序;但你要做演示,不能太难看了,一个exe附件都是各种dll,杂乱的很,那怎么办,也是两种方法:
1 用批处理的方法,即写一个bat,先setpath,然后运行你的exe,但还是不美观,当你运行一个bat文件而不是exe给大家看的时候。
2 详细说一下方法二,可以写一个shell,用ShellExecute调用exe。很容易,很短的命令。
下面贴一下我写的shell程序
#include <Windows.h> #include <iostream> using namespace std; #define exename _T("Motion_DS.exe") #define dllpath _T(".\\bin") int _tmain(int argc, _TCHAR* argv[]) { try { ShellExecute(NULL,NULL,exename,NULL,dllpath,SW_SHOW); } catch (...) { std::cout<<"出现异常,请检查源程序"<<exename<<std::endl; } return 0; }
将编译运行后的shell.exe放到Motion_DS.exe所在目录,将Motion_DS.exe放到bin文件夹中,演示的时候只需双击shell.exe即可。
贴上ShellExecute的参数解释和常用实例
---------------------------------------------------------------------------
ShellExecute( hWnd: HWND; {指定父窗口句柄} Operation: PChar; {指定动作, 譬如: open、print} FileName: PChar; {指定要打开的文件或程序} Parameters: PChar; {给要打开的程序指定参数; 如果打开的是文件这里应该是 nil} Directory: PChar; {缺省目录} ShowCmd: Integer {打开选项} ): HINST; {执行成功会返回应用程序句柄; 如果这个值 <= 32, 表示执行错误} //返回值可能的错误有: = 0
什么是AOP?
AOP是OOP的延续,是Aspect Oriented Programming的缩写,意思是面向方面编程。AOP实际是GoF设计模式的延续,设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,AOP可以说也是这种目标的一种实现。
为什么使用AOP?
将通用需求功能从不相关类之中分离出来;同时,能够使得很多类共享一个行为,一旦行为发生变化,不必修改很多类,只要修改这个行为就可以。我们把这种行为称为"分散关注" AOP就是这种实现分散关注的编程方法,它将“关注”封装在“方面”中。
AOP的本质可以理解为"动态代理模式",想想代理模式的作用就更容易理解AOP了,可以把前面写的一篇动态代理封装事务的文章作为例子
AOP开发过程?
1、分离关注点:分解需求提取出横切关注点和一般关注点。就一般的系统而言,比较常见的关注点为:日志关注点,权限关注点,事务关注点。
2、实现关注点:各自独立地实现关注点,例如日志模块,权限模块。
3、组合关注点:即确定在什么时候执行关注点,例如在每个操作的开始需要开启事务,每个操作结束关闭事务。
我们再来看一下AOP的原理图帮助我们理解AOP的开发过程
Cross Cutting Concern:横切性关注点,是一种独立服务,它会遍布在系统的处理流程之中
Aspect:对横切性关注点的模块化
Advice:对横切性关注点的具体实现
Pointcut:它定义了Advice应用到哪些JoinPoint上,对Spring来说是方法调用
JoinPoint:Advice在应用程序上执行的点或时机,如:Spring只支持方法的JoinPoint,Aspecj可以支持属性的JoinPoint
Weave:将Advice应用到Target Object上的过程叫织入,如Spring支持的是JDK动态代理
Target Object:Advice被应用的对象
Proxy:AOP织入方式之一,如Spring AOP默认使用JDK的动态代理,它的代理是运行时创建;也可以使用CGLIB代理,它的织入方式字节码动态生成;还有Aspecj织入方式:语言扩展
AOP的适用范围?
很明显,AOP非常适合开发J2EE容器服务器,如Jboss4.0
具体功能如下:
Authentication 权限
Caching 缓存
Context passing 内容传递
Error handling 错误处理
Lazy loading 懒加载
Debugging 调试
logging, tracing, profiling and monitoring 记录跟踪 优化 校准
Performance optimization 性能优化
Persistence 持久化
Resource pooling 资源池
Synchronization 同步
Transactions 事务
听过SOLID编码吗?有人可能会说:这是描述设计原则的一个专业术语,由我们可爱的代码整洁之道传教者鲍勃(罗伯特C. 马丁)大叔提出,是一组用于指导我们如何写出“好代码”的原则。
在编程界充满了这样由单词首字母组成的缩略词。其它类似的例子还有DRY(Don’t Repeat Yourself! 不要重复你自己!)和KISS(Keep It Simple, Stupid! 让事情简单化,傻瓜化)。但是,这些条条框框好像有点多,太多,超级多……
所以,可不可以换个角度来解决这些问题呢?看看是什么原因导致我们写出“坏代码”。
抱歉,你的代码就是那么的STUPID没有人喜欢听到别人评价他的代码很愚蠢。而且这样做也很容易冒犯别人。所以不要说出来。但平心而论:全世界中大部分代码都是不可维护的,因为它们都是乱糟糟一团的。
那些烂代码又有什么特点呢?是什么把代码变得如此STUPID?
- Singleton - 单态
- Tightcoupling - 紧密耦合
- Untestability - 不可测试
- Premature Optimization - 过早优化
- Indescriptive Naming - 胡乱命名
- Duplication - 重复代码
你同意上面的列表吗?是?好极。不?OK,我会在下面的内容中逐一解释每项观点,这样你就可以更好地明白为什么我会选用这些模式。
单态<?php class DB { private static $instance; public static function getInstance() { if (!isset(self::$instance)) { self::$instance = new self; } return self::$instance; } final private function __construct() { /* something */ } final private function __clone() { } /* actual methods here */ }
上面的代码是一段典型的数据库访问实现,你可以从很多PHP教程中找到这样的代码。实际上,不久之前我也在使用与此风格类似的代码。
你可能会感到奇怪:这段代码怎么了?不论在哪,利用DB::getInstance()都可以很容易地访问DB啊,并且它还保证一次只有一个数据库连接。到底坏哪儿了?
嗯,很好,我之前也是这样想滴^^。“我只需要一个连接”。当应用程序规模变得稍微大一些的时候,实事会证明我还需要另一个数据库的连接。这就是混乱的开始。我把单态稍加修改,增加了一个->getSecondInstance()方法,这样,单态就变成了——“双单态”了。其实我本就应该意识到数据库连接不是一个简单的单态结构,压根就不该用它来作为实现方案。同样的单态用法你还可以找到很多。请求对象的确是单态!但听过子请求吗?日志就是!难道你不需要换个方式记录点别的什么?
上面描述的只是问题之一。还有一个重大的问题就是在代码中使用DB::getInstance()会把代码与类名DB强行绑定。也就是说,你无法对类DB进行扩展。假设我需要把查询性能数据以日志的形式写到APC(Alternative PHP Cache)中。但由于类名紧密耦合,根本无法实现这项功能。如果当初程序是采用依赖注入的方式实现的,我可以很轻松地对类型DB进行扩展,然后传入新的实例对象。但单态已经不允许我这样做了。现在我能做的就是用下面这种粗制的手段实现我的想法:
<?php // original DB class class _DB { /* ... */ } // extending class class DB extends _DB { /* ... */ }
一个字儿:丑。或许还有人会加入一些别的形容词,骇客、不可维护、大米共,或STUPID。
最后还有一点要考虑:还记得我之前说过的那句,“不论在哪,利用DB::getInstance()都可以很容易地访问DB”。不得不承认,其实这也是件糟糕的事情。一看到“无论在哪”,我们自然可以联想到“全局”,也可以理解为“单态就是一个具有特别命名的全局变量”。在你学习PHP的时候,你可能早就被告知使用关键字global是一个很坏的习惯。但殊不知使用单态和使用全局变量的影响是一样的:它们都创建了全局状态对象。这种方法创建的是非显式依赖,结果就是会让程序变得难以重用与测试。
紧密耦合通过上面对单态问题的认识,你可能已经学会举一反三,把问题推向使用更为广泛的static方法和属性。不管在什么时候,只要编写Foo::bar()这样的代码,就是把代码和Foo类耦合在一起。这种耦合使得对Foo类的功能扩展几乎变得不可能,进而导致代码很难被重用和测试。
类似的情况还有包括普通类名的使用,它们也同样会带来代码臭味。其中包括new操作符的使用:
<?php class House { public function __construct() { $this->door = new Door; $this->window = new Window; } }
在上面的代码,你怎么替换房子中的门和窗呢?答案很简单:不可以。作为一个技法娴熟的开发者,你可能一眼就会看出怎么用些下流的骇客手法来替换门或窗。但是,或许下面的方式更为简单一些:
<?php class House { public function __construct(Door $door, Window $window) { // Door, Window are interfaces $this->door = $door; $this->window = $window; } }
采用这种方法可以很方便地把不同的门和窗加到房子里。另外,这份代码同时还具有良好的扩展性、重用性和可测试性。你还有什么可以奢求的吗?
上面的代码概括起来说就是使用了“依赖注入(DI=DependencyInjection)”。而一讲到DI,许多人就会把它和Symfony(一款PHP开发框架)这样的DIC(Dependency Injection Container=依赖注入容器)联系起来,而实际上DI的概念是非常简单的。
不可测试单元测试很重用。如果你没有对你的代码进行过测试,你也就登上驶往破坏代码的战船。但即使是这样,还是有很多人没有很好地完成他们的测试。为什么?大多数原因可以归结于难以测试的代码。那又是什么原因使得代码难以测试呢?主要是列表中前一点内容:紧密耦合。单元测试——看似清晰明了——就是测试一个代码单元(通常是各种类)。但如果类与类之间紧密结合,又怎么可能针对每一个类进行测试呢?这时你可能会使用更多的骇客技术。但是,通常情况下大多数人都不会在此花费这么多力气,代码仍旧保持在原先无法测试的状态,并任它慢慢腐败。
每当你决定不编写测试用例时,多时会把原因归结于“没有时间”,而真正导致这个结果的原因,其实是你的代码里有太多垃圾。如果代码结构组织良好,测试不会花费你多少时间的。只有在代码杂乱无章的时候,单元测试才会成为负担。
过早优化下面的代码片段源自于我之前编写的一个网站:
<?php if (isset($frm['title_german'][strcspn($frm['title_german'], '<>')])) { // ... }
猜一下它是干什么用的!
其实它只是检查德语标题中是否包含字符“<”或“>”,可以说下你用了多久才看明白的吗?你完全看明白了吗?
我来做一下解释:如果“<”和“>”都没有的话,strcspn会返回字符串的本身长度。所以这段代码可以简单地看成isset($str[strlen($str)])。由于字符串所允许的最大偏移量为字符串本身的长度减一,所以上面代码的结果就永远为false。假如目标字符串中包含前面所述的两个字符中的任何一个,函数就会返回一个小于字符串长度的数字,这样一来,整个表达式的结果就为true。
我为什么要写这么一段难以理解的代码呢?为什么不改用下面的方式呢:
<?php if (strlen($frm['title_german']) == strcspn($frm['title_german'], '<>'))) { // ... }因为之前我曾读到过isset要比strlen快许多……但这样写会使代码看起来很隐晦,因为它需要程序员必须精确了解函数strcspn语义(而大多数PHP程序员可能不是特别了解)。所以为什么不改写成:
<?php if (preg_match('(<|>)', $frm['title_german'])) { // ... }
因为我曾听说使用正则表达式有点慢……(这样说可能有谎话的嫌疑:实际上正则表达式要比我们想象的快得多。)
看看,除了令人费解的代码外,这些所谓的“优化”给我们带来的还有什么呢?一无是处。即便是现在,这个网站每月已经达到四千万左右的访问量(当然,在我刚写下上面代码的时候还远远没有达到这个数字),这个细小的优化基本上是微不足道的。因为这块根本就不是程序的瓶颈。而实际的瓶颈是访问最为频繁的控制器中的三重JOIN(你的程序可能也会有这样的瓶颈)。
从