やっとOpenCVが動いた……

やっとコンパイル通ったのにリンクすると 0x8007007e とかわけのわかんないエラーがでるのはWM6エミュレータに MSVCRT80.dll がないからだとか、cvLoadImage がちっともファイルを読まないのはワイド文字列のファイル名を受け付けないからだとか、cvSaveImage は png は吐けないけど bmp なら吐けたとか、およそ Windows Mobile 6 で OpenCV を動かそうと思った者が踏みそうな地雷は全部踏みました。(……どうかなあ……)

というわけで、WM6 で cvLoadImage を使うときのコードを載せておきます。

char mbfilename[MAX_PATH];
int result = WideCharToMultiByte(CP_ACP, 0, // ANSIコードページ、フラグなし
	(LPCTSTR)m_sFile, -1, // 変換元文字列とその長さ。長さに -1 を指定すると、m_sFile はヌルターミネートとみなされる
	(LPSTR)mbfilename, MAX_PATH, // 変換先文字列バッファとそのサイズ
	NULL, NULL); // 変換不能文字について特に処理をしない
IplImage * image = cvLoadImage(mbfilename, CV_LOAD_IMAGE_COLOR);

インクルードは、今回は以下のようにします。

#include <cv.h>
#include <highgui.h>

// cxcore.hpp で max, min マクロが undef されるため、再定義する
#ifndef max
#define max(a,b)            (((a) > (b)) ? (a) : (b))
#endif

#ifndef min
#define min(a,b)            (((a) < (b)) ? (a) : (b))
#endif

この宣言は ATL/WTL 関係の前でもあとでもかまいません。


実は CStringA クラスと CStringW クラスを使えばもっと簡単にできるらしい。
たしかに WideCharToMultiByte 関数は引数が多すぎるし、ややこしい。

WM6 用に OpenCVコンパイルする手順はまた改めて書きます。

(追記)CAtlString を使った場合

CAtlStringA mbfilename = m_sFile;
IplImage * image = cvLoadImage(mbfilename, CV_LOAD_IMAGE_COLOR);

あああ一行で済んだ。しかも変数宣言して代入するだけ。
(参考:http://www.usefullcode.net/2006/11/widechartomultibytemultibyteto.html:title)


ただし、インクルードにちょっと工夫が必要です。

#define _WTL_NO_CSTRING	1 // 単なる CString が WTL::CString か ATL::CString か不明でエラーになるため、WTL::CString を利用しない

#include <atlbase.h>
#include <atlstr.h> // atlapp.h より先にインクルードしないとエラーになる
#include <atlapp.h>
#include <atlmisc.h> // atlapp.h より後にインクルードしないとエラーになる

1時間悩みました。
わかってしまえばなんてことないんですが。ほらやっぱりまた地雷を踏んだよ orz

WTL::CString が必要な場合は、すべての CString の宣言に WTL:: か ATL:: を付けなくちゃいかんのかな?