本文讲述了编译可用于 Windows CE(同样适用于最新版本 Windows Embedded Compact 7)的 OpenCV 图像处理库。使用 OpenCV 版本为 1.10。我所移植的库有 cv 和 cxcore。由于 Highgui 和操作系统结合太紧密,我删除了大量代码,只移植了项目需要的 cvLoadImage 等几个函数。
准备工作
下载 OpenCV 1.10 版本,打开 VS 工程。建立空的 Windows CE 动态链接库 solution(静态库也是可以的),将 cv 和 cxcore 的代码添加分别加入不同的 project 。设定头文件位置和 SDK 等。
针对 WIN32 和 ARM 平台,需要设定不同的 preprocessor definitions, _UNICODE
、ARM
、WIN32
等指令请参考其他工程进行设置,需要额外添加的有 CVAPI_EXPORTS
, CV_DLL
,CXCORE_EXPORTS
。
修改代码
由于我的开发平台是 X86,接下来的修改都是针对此平台。 首先编译 cxcore,打开 cxerror.cpp,修改以下内容:
第 94 行(注意,行数不一定准确):
#if defined WIN32 || defined WIN64 //Changed
#define TLS_OUT_OF_INDEXES ((DWORD)0xFFFFFFFF)
static DWORD g_TlsIndex = TLS_OUT_OF_INDEXES;
#else
static pthread_key_t g_TlsIndex;
#endif
第 114 行:
if( g_TlsIndex == TLS_OUT_OF_INDEXES )
//Changed
//FatalAppExit( 0, "Only set CV_DLL for DLL usage" );
MessageBox(0, L"Only set CV_DLL for DLL usage", L"OpenCV", MB_ICONERROR);
第 121 行:
if( !context )
{
context = icvCreateContext();
if( !context )
//Changed
//FatalAppExit( 0, "OpenCV. Problem to allocate memory for TLS OpenCV context." );
MessageBox(0, L"OpenCV. Problem to allocate memory for TLS OpenCV context.", L"OpenCV", MB_ICONERROR);
TlsSetValue( g_TlsIndex, context );
}
第 191 行:
//Changed
//wsprintf( message, "%s (%s)\nin function %s, %s(%d)\n\n"
sprintf( message, "%s (%s)\nin function %s, %s(%d)\n\n"
"Press \"Abort\" to terminate application.\n"
"Press \"Retry\" to debug (if the app is running under debugger).\n"
"Press \"Ignore\" to continue (this is not safe).\n",
cvErrorStr(code), err_msg ? err_msg : "no description",
func_name, file, line );
//wsprintf( title, "OpenCV GUI Error Handler" );
//Changed
sprintf( title, "OpenCV GUI Error Handler" );
//int answer = MessageBox( NULL, message, title, MB_ICONERROR|MB_ABORTRETRYIGNORE|MB_SYSTEMMODAL );
//Changed
//int answer = MessageBox( NULL, message, title, MB_ICONERROR|MB_ABORTRETRYIGNORE );
WCHAR wmsg[2048];
MultiByteToWideChar(CP_ACP,0,title,strlen(message),wmsg,2048);
int answerr = MessageBox( NULL, wmsg, L"OpenCV GUI Error Handler", MB_ICONERROR|MB_ABORTRETRYIGNORE);
第 393 行:
#if defined WIN32 || defined WIN64
//Changed
//BOOL WINAPI DllMain( HINSTANCE, DWORD fdwReason, LPVOID )
BOOL WINAPI DllMain( HANDLE, DWORD fdwReason, LPVOID )
接下来是对 cxswitcher.cpp 的修改。
第 138 行:
//Changed
//if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\SYSTEM\\CentralProcessor\\0\\",
if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\SYSTEM\\CentralProcessor\\0\\",
0, KEY_QUERY_VALUE, &key ) >= 0 )
{
//if( RegQueryValueEx( key, "~MHz", 0, 0, (uchar*)&val, &sz ) >= 0 )
if( RegQueryValueEx( key, L"~MHz", 0, 0, (uchar*)&val, &sz ) >= 0 )
cpu_info->frequency = (double)val;
RegCloseKey( key );
}
#ifdef MASM_INLINE_ASSEMBLY
//#ifdef MASM_INLINE_ASSEMBLY && !defined ARM
第 440 行:
//Changed
//addr = (uchar*)GetProcAddress( plugins[idx].handle, name );
wchar_t tmp[1024];
swprintf(tmp, L"%s", name);
addr = (uchar*)GetProcAddress( plugins[idx].handle, tmp);
第 614 行:
//Changed
//plugins[i].handle = LoadLibrary( plugins[i].name );
wchar_t tmp[1024];
swprintf(tmp, L"%s", plugins[i].name);
plugins[i].handle = LoadLibrary( tmp );
针对 ARM,还需要修改几个地方:
第 744 行:
//#ifdef MASM_INLINE_ASSEMBLY
#ifdef MASM_INLINE_ASSEMBLY && !defined ARM
cxtypes.h 第 210 行:
#elif defined WIN32 && !defined WIN64 && defined \_MSC_VER && !defined ARM
到此应该可以正常编译 cxcore 了,如果编译时出现错误,请按照以上方式修改出错位置的预编译指令或者字符串类型等。
接下来是 cv ,由于 cv 依赖 cxcore ,需要将之前编译的 cxcore.lib 加入 cv 工程的链接目录。 cv 几乎不需要修改,但 kdtree 部分编译不过,因为我不需要使用这部分的函数,所以我删除了 kdtree 的两个文件。接下来修改 preprocessor definitions,完成编译。
Highgui 和 Windows 相关度太高,我删除了大量代码,只留下了 cvLoadImage 等几个函数。OpenCV 自带 bmp 解码,jpeg 和 png 解码需要相应的解码库。移植这些库后,将产生的 lib 文件加入 highgui 的链接目录,根据出错信息逐步修改代码,即可完成编译。