Hello OpenCV World

ずっと”後でやる”状態だったOpenCVでヒストグラムを表示してみました。

OpenCVでヒストグラム
OpenCVでヒストグラム

インストール
そろそろ最新版がリリースされるという噂があるので、リポジトリのヘッドを使おうとしたのですが、全然ビルドが成功しないので、仕方なしに1.1pre版を使いました。環境はosx 10.5.4です。

$ wget http://sourceforge.net/projects/opencvlibrary/files/opencv-linux/1.1pre1/opencv-1.1pre1.tar.gz/download
$ tar zxvf opencv-1.1pre1.tar.gz
$ cd opencv-1.1pre1
$ ./make && make install

ヒストグラムの表示
opencv.jpのサンプルコードを参考にしながら書きました。描画処理が面倒だったので、画像を白黒でロードして1次元のヒストグラムをベタ書きしています。

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

IplImage* createHistgram(IplImage* srcImg, CvSize& imageSize);

int main(int argc, char** argv) {
    // 画像読み込み(グレースケールで読み込み)
    char* imageFilename = "sample.jpg";
    if (argc == 2) {
    	imageFilename = argv[1];
    }
    IplImage* img = cvLoadImage(imageFilename, CV_LOAD_IMAGE_GRAYSCALE);
    if (!img) {
    	printf("@E failed to load image %s @\n", imageFilename);
    	exit(-1);
    }
    
    // Window作成
    char* windowTitle      = "Original Image";
    char* histWindowTitle  = "Histgram";
    cvNamedWindow(windowTitle, CV_WINDOW_AUTOSIZE);
    cvNamedWindow(histWindowTitle, CV_WINDOW_AUTOSIZE);
    
    // 元画像とヒストグラム表示
    CvSize size = cvSize(256, 256);
    IplImage* histImg = createHistgram(img, size);
    cvShowImage(histWindowTitle, histImg);
    cvShowImage(windowTitle, img);
    
    // キー入力待ち
    cvWaitKey(0);
    	
    // 破棄
    cvReleaseImage(&img);
    cvReleaseImage(&histImg);
    cvDestroyAllWindows();
    
    return 0;
}

IplImage* createHistgram(IplImage* srcImg, CvSize& imageSize) {
	// ヒストグラム作成
	int    channelSize[] = { 256 };
	float  levelRange[]  = { 0, 256 };
	float* range[]       = { levelRange };
	CvHistogram* hist    = cvCreateHist(1, channelSize, CV_HIST_ARRAY, range, 1);
	cvCalcHist(&srcImg, hist);

	// ヒストグラム出力用画像作成
	IplImage* dstImg = cvCreateImage(imageSize, IPL_DEPTH_8U, 1);
	cvSet(dstImg, cvScalarAll(255), 0);
	
	// ヒストグラムのスケール変換
	float max = 0;
	cvGetMinMaxHistValue(hist, 0, &max, 0, 0);
	cvScale(hist->bins, hist->bins, ((double)dstImg->height) / max, 0);

	// 画像に出力
	int binWidth = cvRound((double)imageSize.width / channelSize[0]);
	for (int i = 0; i < channelSize[0]; i++) {
	    int     histValue  = cvRound(cvQueryHistValue_1D(hist, i));
	    CvPoint bottomLeft = cvPoint(i * binWidth, dstImg->height);
	    CvPoint topRight   = cvPoint((i+1) * binWidth, dstImg->height - histValue);
	    cvRectangle(dstImg, bottomLeft, topRight, cvScalarAll(0), CV_FILLED, 8, 0);
	}

	// ヒストグラム破棄
	cvReleaseHist(&hist);

	return dstImg;
}

これをビルドすれば冒頭の画面が表示されます。普段スクリプト言語使ってると本当にビルドが面倒です。幾つかライブラリをリンクしないと駄目です。

TARGET = helloworld
SRCS   = helloworld.cpp
INC    = /usr/local/include/opencv
LIB    = -lcxcore -lcv -lhighgui

all:$(TARGET)
$(TARGET):$(SRCS)
	g++ $(SRCS) -o $(TARGET) -I$(INC) $(LIB)
run:all
	./$(TARGET)
clean:
	rm $(TARGET)

まとめ
ドキュメントの質が非常に良くて、サンプルも豊富にあるので、割とスムーズにコーディングできました。感触としては画像の解析能力は思ったよりも強力で、サンプルを実行するだけで楽しいです。ただ表示に必要な出力系APIが貧弱なので、もっぱら解析用に使うのが良さそうだと思いました。

Leave a Reply

Your email address will not be published. Required fields are marked *