名前空間とクラスの宣言
日記放置してたけど暇になったし、せっかくだからメモ代わりに書いとこう。
c++で、名前空間とクラスの宣言についてちょっと嵌った。
class piyo::fuga;
じゃダメで、
namespace piyo{ class fuga; }
で宣言すりゃokって話なんだけど。
なんのこっちゃ、と思うだろうがとりあえず以下にプログラムを。
fuga.h
#include <iostream> namespace piyo{ class fuga{ public: void print(){ std::cout << "fuga" << std::endl; } }; }
hoge.h
namespace piyo{ class fuga; } //class piyo::fuga; //こっちはだめ class hoge{ public: hoge(piyo::fuga *f){ mf=f; } piyo::fuga *mf; };
main.cpp
#include "hoge.h" #include "fuga.h" #include <iostream> using namespace std; using namespace piyo; int main(int argc, char **argv) { fuga f; hoge h(&f); h.mf->print(); char c; cin >> c; return 0; }
hoge.hが話のキモ。
コメントにもあるようにclass piyo::fuga;での宣言はコンパイルが通らない。
具体的には、namespace piyo{ class fuga; }をコメントアウトして、class piyo::fuga;でコンパイルしようとすると、
hoge.h(2): error C2653: 'piyo' : 識別子がクラス名でも名前空間名でもありません。
というエラーをくらう。(Microsoft Visual C++ 2010 Express の場合)
とりあえずnamespaceで囲う感じで宣言すりゃおk、ということは分かった。
こんな感じで使えるんじゃねーの?と思ってたが、実は違うのだ。というのが話のオチ。
OpenCVのラプラシアンフィルタ
OpenCVのラプラシアンフィルタがずぅーっと謎だった。
ラプラシアンフィルタでよく見かけるのはこういうパターンのやつ。
0 | 1 | 0 |
1 | -4 | 1 |
0 | 1 | 0 |
でも、これってcvLaplaceのデフォルトじゃないんだよね。
んじゃぁどんな値使ってんのー・・・と。
別段困ることもないので放置してましたが、ひょんな事から謎が解明。
まぁ、ひょんな事ってか、OpenCVのソース読んだんですが。
んで、確かめた結果こんな具合のフィルタ使ってた。
2 | 0 | 2 |
0 | -8 | 0 |
2 | 0 | 2 |
はっはぁ〜ん。なるほどなるほど。
斜め方向で差分をとってあげるのですな。ふぅむ。
というわけで実装して確かめてみた。
結果がこちら。ついでにソベルフィルタも作ってみた。
わぁーい。大体似たような感じになったよぉー。
というわけでラプラシアンフィルタの謎がとけたのでした。
めでたしめでたし。
プログラムはこちら
/****************************************************************************** * * Laplacianフィルタを実装してみた。 * ついでにSobelも。 * ******************************************************************************/ #include <cv.h> #include <highgui.h> #include <math.h> #include <stdio.h> //フィルターの中心点(x,y)を指定し、フィルターをかけた値を計算 unsigned char filtResult(const IplImage *img, int x, int y, const int filt[3][3]) { int result = 0; x--; //フィルターの左上から計算する y--; //フィルターをかける for(int i=0; i<3; i++){ //y軸 int yyy = y+i; if(yyy<0 || yyy>=img->width){ continue; //範囲チェックして範囲外なら次のステップへ } for(int j=0; j<3; j++){ //x軸 int xxx = x+j; if(xxx<0 || xxx>=img->width){ continue; //範囲チェックして範囲外なら次のステップへ } result += filt[i][j] * CV_IMAGE_ELEM(img, uchar, yyy, xxx); } } //修正して結果を返す if(result < 0){ result = -result; } //絶対値を取る if(result > 255){ result = 255; } //大きすぎる値は255にしておく return static_cast<unsigned char>(result); } //srcにフィルターをかけたものがdestに入る src!=destとしないと結果がおかしなことになるので注意 void filteringImage(const IplImage *src, IplImage *dest, const int filt[3][3]) { for(int y=0; y<src->height; y++){ for(int x=0; x<src->width; x++){ CV_IMAGE_ELEM(dest, uchar, y, x) = filtResult(src, x, y, filt); } } } //imgにラプラシアンフィルタをかける void myLaplacian(IplImage *img) { //2次微分フィルタ int filt[3][3] = { {2, 0, 2}, {0,-8, 0}, {2, 0, 2} }; IplImage *lap = cvCloneImage(img); filteringImage(img, lap, filt); cvCopy(lap, img); cvReleaseImage(&lap); } //imgにソベルフィルタをかける void mySobel(IplImage *img) { //x方向微分 int xfilt[3][3] = { {-1, 0, 1}, {-2, 0, 2}, {-1, 0, 1} }; //y方向微分 int yfilt[3][3] = { {-1,-2,-1}, { 0, 0, 0}, { 1, 2, 1} }; IplImage *xsobel = cvCloneImage(img); IplImage *ysobel = cvCloneImage(img); filteringImage(img, xsobel, xfilt); filteringImage(img, ysobel, yfilt); //x,y方向微分画像を統合 for(int y=0; y<img->height; y++){ for(int x=0; x<img->width; x++){ int xv = CV_IMAGE_ELEM(xsobel, uchar, y, x); int yv = CV_IMAGE_ELEM(ysobel, uchar, y, x); int val = sqrt(xv*xv + yv*yv); if(val > 255){val=255;} //オーバーフロー防止 CV_IMAGE_ELEM(img, uchar, y, x) = val; } } cvReleaseImage(&xsobel); cvReleaseImage(&ysobel); } //main int main(int argc, char **argv) { if(argc < 2){ printf("%s file.jpg\n", argv[0]); return 0; } IplImage *srcimg, *mylap, *cvlap, *mysobel, *cvsobel, *tmp; IplImage **pimgArray[] = {&srcimg, &mylap, &cvlap, &mysobel, &cvsobel}; char *windowName[] = {"srcimg", "mylap", "cvlap", "mysobel", "cvsobel"}; srcimg = cvLoadImage(argv[1], CV_LOAD_IMAGE_GRAYSCALE); if(!srcimg){ perror(argv[1]); exit(1); } //自作laplacian,sobelを使う mylap = cvCloneImage(srcimg); myLaplacian(mylap); mysobel = cvCloneImage(srcimg); mySobel(mysobel); //tmpはオーバーフロー防止のために使われる tmp = cvCreateImage(cvGetSize(srcimg), IPL_DEPTH_16S, 1); cvlap = cvCreateImage(cvGetSize(srcimg), IPL_DEPTH_8U, 1); cvsobel = cvCreateImage(cvGetSize(srcimg), IPL_DEPTH_8U, 1); //laplacian cvLaplace(srcimg, tmp); cvConvertScaleAbs(tmp, cvlap); //sobel cvSobel(srcimg, tmp, 1, 0); cvConvertScaleAbs(tmp, cvsobel); cvSobel(srcimg, tmp, 0, 1); //x,y方向微分画像を統合 for(int y=0; y<cvsobel->height; y++){ for(int x=0; x<cvsobel->width; x++){ int xval = CV_IMAGE_ELEM(cvsobel, uchar, y, x); int yval = CV_IMAGE_ELEM(tmp, short, y, x); int val = sqrt(xval*xval + yval*yval); CV_IMAGE_ELEM(tmp, short, y, x) = val; } } cvConvertScaleAbs(tmp, cvsobel); //tmpはいらないので後始末する cvReleaseImage(&tmp); int max = sizeof(windowName)/sizeof(windowName[0]); for(int i=0; i<max; i++){ cvNamedWindow(windowName[i]); cvShowImage(windowName[i], *pimgArray[i]); } cvWaitKey(0); for(int i=0; i<max; i++){ cvDestroyWindow(windowName[i]); cvReleaseImage(pimgArray[i]); } return 0; }