- 2009-09-11 (金) 18:09
- ソフトウエア
世間ではポインタのdeleteし忘れを防止するためにauto_ptrとかそういう類のものがあるみたいですが,
それのIplImage*版みたいなやつを何故か自前で書いてみたよ,という低レベルな遊び.
●動機
OpenCVの関数は引数が(処理対象画像,処理結果格納領域)という形が多いので,
画像をいじくる処理を書くと大抵 画像領域を作って→必要な間持っておき→要らなくなったら捨てる ということをすることになる.
画像はcvReleaseImage()関数で捨てるのだが,
処理を途中で中止(returnで関数を抜けるとか)するとなると,
中止場所によって捨てるべき画像がどれとどれなのか違ったりしてこの後始末がたいそう面倒……なのだが,
何故か今まで画像領域を捨てる作業を自動化させてこなかった.何故だろう?不思議.
で,ある日,処理サンプルプログラムみたいな関数コードを隣人に渡したら
「その関数を別スレッドにしてそのまま使う.任意のタイミングで中止できるようにして」とか言われた.(自分でやってくれ)
捨てる処理を関数末尾にまとめて中止時にgotoでそこに飛ぶ,とかやろうとしたら関数の途中で変数宣言してるから怒涛のコンパイルエラーが出て泣いた.
●やること
要するに,
・IplImage*をメンバ変数として持っていて
・デストラクタでそれをcvReleaseImage()する
・IplImage*だと思って使える
ようなクラスを書いてみる.
●個人的に予想される追加の恩恵
OpenCVを使い始めた当初,「cvReleaseImage()したらポインタの値はどうなるの?」という疑問を持った.
結局cvReleaseImage()のソースコードを見るとちゃんと0を代入してくれているのだが,
「実装が変わるかもしれない!(?) せっかくだから俺は自分でNULLを代入するぜ!」という謎の意気込みと
「ポインタのポインタとかってなんとなく嫌(※1)」という半端なこだわりを理由に,
↓の大仰な名前の関数をわざわざ用意して使ったりしていた.
//IplImageの解放. // (これを正しく働かせるために,画像を指さないIplImage*変数は常にNULLにしておくこと.初期化とか.) inline void cvSafeReleaseImage( IplImage* &pImg ) { if( pImg ){ cvReleaseImage( &pImg ); pImg=NULL; } }「&」一個をタイプしたくないのと引き換えに,かえって長ったらしい関数名をタイプするというよくわからない事態.
それはそれでそれなりに楽しいのだが,画像破棄を自動化すれば無意味に腱鞘炎になる危険性がいくらか減るかもしれない.●書いてみました
//NULL初期化と,指す領域のReleaseを自動化したIplImage* class UCpIplImage { public: UCpIplImage( IplImage* const pImg=NULL ){ operator=(pImg); } ~UCpIplImage(){ Release(); } void Release(){ cvSafeReleaseImage(m_pImg); } operator IplImage*&(){ return m_pImg; } operator const IplImage* () const { return m_pImg; } IplImage *operator =( IplImage* const pImg ){ return (m_pImg = pImg); } IplImage *operator->(){ return m_pImg; } const IplImage *operator->() const { return m_pImg; } private: //※このポインタは,有効な画像領域を指さないときはNULLに保っておかねばならない IplImage *m_pImg; };(しつこくcvSafeReleaseImageを仕込んでみました)
えと,これでいいのか……な?
とりあえずちょっと使ってみた感じ大丈夫そうに見えるが.とは言え,「勝手に画像を捨ててしまう」ことが問題となる場面ではこれでは逆に使えない.
うっかりコピーができて2重破棄等の問題が出ないようにこのクラスインスタンスの複製を禁止.//複製の禁止 private: UCpIplImage( const UCpIplImage & ); UCpIplImage &operator =( const UCpIplImage & );しかしIplImage*型ポインタを間に介せばコピーできるわけで……
結局,最初に挙げたような限られた場面(作って,使って,すぐ捨てるような一時画像)に限ってしか使えないのかも.
うーん…—————————————————–
※1
学生のころ,「動的多次元配列」とか言って,4重くらいのポインタをちりばめたコードを書いて自分で収集がつかなくなった.
しかもその悪夢のコードを読まなければならない後輩が出てきて,研究室のみんなの前で
「なんでそんなポインタ地獄になってしまったのか」についてスライド発表した.
二度とやるまいと固く誓った.
- Newer: デスクトップスーパーコンピュータ導入
- Older: cvNamedWindowのウィンドウをうっかり閉じなくする