//---------------------------------------------------------
// 概要      : エッジ抽出
// File Name : edge.cpp
// Library   : OpenCV for MS-Windows 1.0
//---------------------------------------------------------

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

#define SOBEL_X_APERTURE_SIZE	3	//	Sobelオペレータのサイズ (リファレンス参照)
#define SOBEL_Y_APERTURE_SIZE	3	//	Sobelオペレータのサイズ (リファレンス参照)
#define LAPLACIAN_APERTURE_SIZE	3	//	Laplacianオペレータのサイズ (リファレンス参照)

//	cvConvertScaleAbs用定数
#define SCALE	1	//	ScaleAbs係数
#define	SHIFT	0	//	スケーリングした入力配列の要素に加える値

int main( int argc, char **argv ) {

	char windowNameSource[] = "Source";		//	元画像を表示するウィンドウの名前
	char windowNameSobelX[] = "SobelX";		//	X方向のSobelオペレータで処理した画像を表示するウィンドウの名前
	char windowNameSobleY[] = "SobelY";		//	Y方向のSobelオペレータで処理した画像を表示するウィンドウの名前
	char windowNameLaplace[] = "Laplace";	//	Laplacianオペレータで処理した画像を表示するウィンドウの名前

	//	画像を読み込む
    IplImage *sourceImage = cvLoadImage( "image/source.bmp", CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR );

	if ( sourceImage == NULL ) {
		//	画像が見つからなかった場合
		printf( "画像が見つかりません\n" );
		return -1;
	}
	
	//	画像を生成する
	IplImage *grayImage = cvCreateImage( cvGetSize( sourceImage ), IPL_DEPTH_8U, 1 );		//	グレースケール画像用IplImage
	IplImage *sobelXImage16 = cvCreateImage( cvGetSize( sourceImage ), IPL_DEPTH_16S, 1 );	//	X方向のSobelオペレータで処理した画像(16bit)用IplImage
	IplImage *sobelYImage16 = cvCreateImage( cvGetSize( sourceImage ), IPL_DEPTH_16S, 1 );	//	Y方向のSobelオペレータで処理した画像(16bit)用IplImage
	IplImage *laplaceImage16 = cvCreateImage( cvGetSize( sourceImage ), IPL_DEPTH_16S, 1 );	//	Laplaceオペレータで処理した画像(16bit)用IplImage
	IplImage *sobelXImage8 = cvCreateImage( cvGetSize( sourceImage ), IPL_DEPTH_8U, 1 );	//	X方向のSobelオペレータで処理した画像(8bit)用IplImage
	IplImage *sobelYImage8 = cvCreateImage( cvGetSize( sourceImage ), IPL_DEPTH_8U, 1 );	//	Y方向のSobelオペレータで処理した画像(8bit)用IplImage
	IplImage *laplaceImage8 = cvCreateImage( cvGetSize( sourceImage ), IPL_DEPTH_8U, 1 );	//	Laplacianオペレータで処理した画像(8bit)用IplImage
	
	//	BGRからグレースケールに変換する
	cvCvtColor( sourceImage, grayImage, CV_BGR2GRAY );

	//	X方向のSobelオペレータをかける
	cvSobel( grayImage, sobelXImage16, 1, 0, SOBEL_X_APERTURE_SIZE );

	//	Y方向のSobelオペレータをかける
	cvSobel( grayImage, sobelYImage16, 0, 1, SOBEL_Y_APERTURE_SIZE );
	
	//	Laplaceオペレータをかける
	cvLaplace( grayImage, laplaceImage16, LAPLACIAN_APERTURE_SIZE );
	
	//	16ビットの符号ありデータを8ビットの符号なしデータに変換する
	cvConvertScaleAbs( sobelXImage16, sobelXImage8, SCALE, SHIFT );
	cvConvertScaleAbs( sobelYImage16, sobelYImage8, SCALE, SHIFT );
	cvConvertScaleAbs( laplaceImage16, laplaceImage8, SCALE, SHIFT );
	
	//	ウィンドウを生成する
	cvNamedWindow( windowNameSource, CV_WINDOW_AUTOSIZE );
	cvNamedWindow( windowNameSobelX, CV_WINDOW_AUTOSIZE );
	cvNamedWindow( windowNameSobleY, CV_WINDOW_AUTOSIZE );	
	cvNamedWindow( windowNameLaplace, CV_WINDOW_AUTOSIZE );

	//	画像を表示する
	cvShowImage( windowNameSource, sourceImage );
	cvShowImage( windowNameSobelX, sobelXImage8 );
	cvShowImage( windowNameSobleY, sobelYImage8 );
	cvShowImage( windowNameLaplace, laplaceImage8 );

	//	キー入力を待つ
    cvWaitKey(0);

	//	画像を保存する
	cvSaveImage( "image/sobelx.bmp", sobelXImage8 );
	cvSaveImage( "image/sobely.bmp", sobelYImage8 );	
	cvSaveImage( "image/laplace.bmp", laplaceImage8 );
	 
	//メモリを解放する 
	cvReleaseImage( &grayImage);
	cvReleaseImage( &sobelXImage16 );
	cvReleaseImage( &sobelYImage16 );
	cvReleaseImage( &laplaceImage16 );
	cvReleaseImage( &sobelXImage8 );
	cvReleaseImage( &sobelYImage8 );
	cvReleaseImage( &laplaceImage8 );
	//ウィンドウを破棄する
	cvDestroyWindow( windowNameSource );
	cvDestroyWindow( windowNameSobelX );
	cvDestroyWindow( windowNameSobleY );
	cvDestroyWindow( windowNameLaplace );
	
	return 0;
}
