Created
June 18, 2010 09:04
-
-
Save peccu/443423 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include "cv.h" | |
| #include "highgui.h" | |
| #include <ctype.h> | |
| #include <stdio.h> | |
| #define MAIN_WINDOW "Main Window" | |
| #define MAIN_WINDOW_WIDTH 1024 | |
| #define MAIN_WINDOW_HEIGHT 768 | |
| #define GRAYCODE_NUM 32 //投影するグレイコード画像の枚数 | |
| #define GRAYCODE_FILE "graycode/GraycodeImage%d.png" //グレイコード画像ファイル | |
| #define FIELD_SIZE 320 | |
| #define PROJECTION_WIDTH 320 //投影画像サイズ | |
| #define PROJECTION_HEIGHT 240 | |
| #define ARRAY_SIZE 4 //クリックする格子点の数 | |
| #define Z_SCALE 1 | |
| #define WAIT_FRAME 10 //投影-撮影間の読み飛ばしフレーム数 | |
| #define WHITE_COLOR 255 //2値化時の白の値 | |
| #define BLACK_COLOR 0 //2値化時の黒の値 | |
| #define THRESHOLD 15 //2値化時にパターン投影外と判断する閾値 | |
| int window_width = 640; // ウインドウ幅 | |
| int window_height = 480; // ウインドウ高さ | |
| //テーブル上の格子座標 | |
| double table_field[ARRAY_SIZE][2]= | |
| { | |
| {0,0},{FIELD_SIZE,0},{0,FIELD_SIZE},{FIELD_SIZE,FIELD_SIZE} | |
| }; | |
| //カメラ上の格子点の座標 | |
| double camera_field[ARRAY_SIZE][2]; | |
| double projector_field[ARRAY_SIZE][2]; | |
| CvMat *Hct; //テーブル <-> カメラ間のホモグラフィ行列 | |
| CvMat *Hpt; //テーブル <^> プロジェクタ間のホモグラフィ行列 | |
| bool TOP_VIEW_MODE = false; | |
| bool CAMERA_VIEW_MODE=true; | |
| bool PROJECTOR_VIEW_MODE=false; | |
| bool CAMERA_CALIBRATION_MODE=false; | |
| bool PROJECTOR_CALIBRATION_MODE=false; | |
| bool GAME_MODE=false; | |
| bool Inverse = false; | |
| int AI_PLAYER = 0; | |
| bool AI_MODE = false; | |
| CvCapture* capture = 0; | |
| IplImage *frame; // OpenCVからのキャプチャ画像 | |
| IplImage *binarized_img; // 二値化画像 | |
| IplImage *gray_img; // グレースケール画像 | |
| IplImage *top_img; // フィールドを上からみた画像=机の画像 | |
| IplImage *projection_img; // プロジェクタに投影する画像 | |
| IplImage **graycode_img; //投影用コード画像 | |
| IplImage **captured_code_img; //コード投影の撮影結果 | |
| IplImage *coded_imgX; //コード値X | |
| IplImage *coded_imgY; //コード値X | |
| IplImage *sample_img; //テスト用画像 | |
| IplImage *field_img; //投影用フィールド | |
| int click_count =0; | |
| int graycode_count =0; | |
| int wait_count = 0; | |
| int capture_width, capture_height; | |
| //game用パラメータ | |
| #define BOARD_THRESHOLD 50 //盤面判定の時の2値化の閾値 | |
| #define STABLE_COUNT 30 //手が確定する判定時間 | |
| #define GRID_SIZE 105 //1マスの大きさ[pix] | |
| #define PLAYER_1 1 | |
| #define PLAYER_2 -1 | |
| #define BLANK 0 //打たれていない場所 | |
| #define MOMENT_TH 800 //石が置かれたかの判定閾値 | |
| IplImage *initial_field; //fieldの初期画像用 | |
| int game_state = 0; //手番 | |
| double pre_cx=0; | |
| double pre_cy=0; | |
| double stable_count=0; | |
| int board[3][3]; | |
| bool board_update = false; | |
| bool AI_turn=false; | |
| bool SEARCH_MODE=false; | |
| int available_player=PLAYER_1; | |
| int winner = BLANK; | |
| ////////////////////幾何変換変換用ルーチン///////////////////////////////////////////// | |
| //グレイコード値を整数に変換 | |
| unsigned int Gray_to_num(unsigned int x) | |
| { | |
| unsigned int ret =x; | |
| while(x >>= 1) | |
| ret ^= x; | |
| return ret; | |
| }//first <-> second間のホモグラフィ計算 | |
| void | |
| FindHomography(double first[ARRAY_SIZE][2], double second[ARRAY_SIZE][2], CvMat** Homography) | |
| { | |
| CvPoint2D32f src_pnt[ARRAY_SIZE], dst_pnt[ARRAY_SIZE]; | |
| for(int i=0;i<ARRAY_SIZE;i++){ | |
| src_pnt[i] = cvPoint2D32f ( (float)first[i][0], (float)first[i][1]); | |
| dst_pnt[i] = cvPoint2D32f ( (float)second[i][0], (float)second[i][1]); | |
| } | |
| if(!Homography){ | |
| cvReleaseMat(Homography); | |
| } | |
| *Homography = cvCreateMat(3,3,CV_32FC1); | |
| cvGetPerspectiveTransform(src_pnt,dst_pnt,*Homography); | |
| CV_MAT_ELEM(**Homography,float,2,2)=Z_SCALE; | |
| for(int y = 0; y < 3;++y){ | |
| for(int x = 0; x < 3;++x) | |
| { | |
| printf( "%f ",CV_MAT_ELEM(**Homography,float,y,x)); | |
| } | |
| printf("\n"); | |
| } | |
| //reprojectionの確認用 | |
| for(int i=0;i<ARRAY_SIZE;i++){ | |
| double X=(double)first[i][0]; | |
| double Y=(double)first[i][1]; | |
| double Z=1; | |
| double x = X*CV_MAT_ELEM(**Homography,float,0,0)+Y*CV_MAT_ELEM(**Homography,float,0,1)+Z*CV_MAT_ELEM(**Homography,float,0,2); | |
| double y = X*CV_MAT_ELEM(**Homography,float,1,0)+Y*CV_MAT_ELEM(**Homography,float,1,1)+Z*CV_MAT_ELEM(**Homography,float,1,2); | |
| double z = X*CV_MAT_ELEM(**Homography,float,2,0)+Y*CV_MAT_ELEM(**Homography,float,2,1)+Z*CV_MAT_ELEM(**Homography,float,2,2); | |
| printf("%lf, %lf %lf = %lf, %lf %lf \n", x/z, y/z, z, X, Y, Z); | |
| } | |
| } | |
| void | |
| ProjectorCalibration() | |
| { | |
| //まず、二値化画像の作成 | |
| IplImage **binarized_img; | |
| IplImage *posi_img; | |
| IplImage *nega_img; | |
| binarized_img = (IplImage **)malloc(sizeof(IplImage *)*(GRAYCODE_NUM/2)); | |
| posi_img = cvCreateImage(cvSize(capture_width,capture_height),IPL_DEPTH_8U,1); | |
| nega_img = cvCreateImage(cvSize(capture_width,capture_height),IPL_DEPTH_8U,1); | |
| for(int i=0;i<GRAYCODE_NUM;i+=2){ | |
| //まずは画像領域の確保 | |
| binarized_img[i/2] = cvCreateImage(cvSize(capture_width,capture_height),IPL_DEPTH_8U,1); | |
| //入力画像をグレースケールに変換 | |
| cvCvtColor(captured_code_img[i],posi_img,CV_RGB2GRAY); | |
| cvCvtColor(captured_code_img[i+1],nega_img,CV_RGB2GRAY); | |
| //ネガポジ画像による2値化 | |
| fprintf(stderr, "code No. %d \n",i); | |
| for(int y=0;y<capture_height;y++){ | |
| for(int x=0;x<capture_width;x++){ | |
| if( abs(CV_IMAGE_ELEM(posi_img, uchar, y, x) - CV_IMAGE_ELEM(nega_img, uchar, y, x))<THRESHOLD){ | |
| CV_IMAGE_ELEM(binarized_img[i/2], uchar, y,x) = (unsigned char) BLACK_COLOR; | |
| } | |
| else if ( CV_IMAGE_ELEM(posi_img, uchar, y, x) >= CV_IMAGE_ELEM(nega_img, uchar, y, x)){ | |
| CV_IMAGE_ELEM(binarized_img[i/2], uchar, y,x) = (unsigned char) WHITE_COLOR; | |
| } | |
| else{ | |
| CV_IMAGE_ELEM(binarized_img[i/2], uchar, y,x) = (unsigned char) BLACK_COLOR; | |
| } | |
| } | |
| } | |
| } | |
| //コード画像の作成 | |
| int bit_num = GRAYCODE_NUM/4; | |
| coded_imgX = cvCreateImage(cvSize(capture_width,capture_height),IPL_DEPTH_8U,1); | |
| coded_imgY = cvCreateImage(cvSize(capture_width,capture_height),IPL_DEPTH_8U,1); | |
| for(int y=0;y<capture_height;y++){ | |
| for(int x=0;x<capture_width;x++){ | |
| unsigned int val = 0; | |
| for(int i=0;i<bit_num;i++){ | |
| if( CV_IMAGE_ELEM(binarized_img[i],uchar,y,x)==WHITE_COLOR) | |
| val+= (int)(pow(2.0 ,i)); | |
| } | |
| //グレイコードを2進数に変換. | |
| if(val>0){ | |
| if(Inverse){ | |
| CV_IMAGE_ELEM(coded_imgX, uchar, y,x) = (unsigned char )(WHITE_COLOR - Gray_to_num(val)); | |
| } | |
| else{ | |
| CV_IMAGE_ELEM(coded_imgX, uchar, y,x) = (unsigned char )(Gray_to_num(val)); | |
| } | |
| } | |
| else | |
| CV_IMAGE_ELEM(coded_imgX, uchar, y,x) = 0; | |
| //同じ処理をY方向にもする | |
| val = 0; | |
| for(int i=0 ;i<bit_num;i++){ | |
| if( CV_IMAGE_ELEM(binarized_img[i+8],uchar,y,x)==WHITE_COLOR) | |
| val+= (int)(pow(2.0 ,(i))); | |
| } | |
| //グレイコードを2進数に変換. | |
| if(val>0){ | |
| if(Inverse){ | |
| CV_IMAGE_ELEM(coded_imgY, uchar, y,x) = (unsigned char )(WHITE_COLOR - Gray_to_num(val)); | |
| } | |
| else{ | |
| CV_IMAGE_ELEM(coded_imgY, uchar, y,x) = (unsigned char )(Gray_to_num(val)); | |
| } | |
| } | |
| else | |
| CV_IMAGE_ELEM(coded_imgY, uchar, y,x) = 0; | |
| } | |
| } | |
| //ホモグラフィの計算 | |
| //プロジェクタ座標系の計算 | |
| for(int i=0;i<ARRAY_SIZE;i++){ | |
| int x = (int)(camera_field[i][0]); | |
| int y = (int)(camera_field[i][1]); | |
| projector_field[i][0]=(double)(PROJECTION_WIDTH * CV_IMAGE_ELEM(coded_imgY, uchar, y, x))/256.0; | |
| projector_field[i][1]=(double)(PROJECTION_HEIGHT * CV_IMAGE_ELEM(coded_imgX, uchar, y, x))/256.0; | |
| fprintf(stderr,"camera %d %d, code %lf %lf, projector %lf %lf \n", | |
| x, | |
| y, | |
| (double)(CV_IMAGE_ELEM(coded_imgX, uchar, y, x)), | |
| (double)(CV_IMAGE_ELEM(coded_imgY, uchar, y, x)), | |
| projector_field[i][0], | |
| projector_field[i][1]); | |
| } | |
| FindHomography(projector_field,table_field,&Hpt); | |
| cvShowImage("debug_window",coded_imgY); | |
| cvReleaseImage(&posi_img); | |
| cvReleaseImage(&nega_img); | |
| for(int i=0;i<GRAYCODE_NUM/2;i++){ | |
| cvReleaseImage(&binarized_img[i]); | |
| } | |
| return; | |
| } | |
| void | |
| GetTopView() | |
| { | |
| if(Hct){ | |
| cvWarpPerspective(frame,top_img,Hct, CV_INTER_LINEAR | CV_WARP_FILL_OUTLIERS, cvScalarAll(100)); | |
| } | |
| } | |
| void | |
| GetProjectorView() | |
| { | |
| if(Hpt){ | |
| if(GAME_MODE) | |
| cvWarpPerspective(field_img,projection_img ,Hpt, CV_INTER_LINEAR | CV_WARP_INVERSE_MAP | CV_WARP_FILL_OUTLIERS, cvScalarAll(100)); | |
| else | |
| cvWarpPerspective(sample_img,projection_img ,Hpt, CV_INTER_LINEAR | CV_WARP_INVERSE_MAP | CV_WARP_FILL_OUTLIERS, cvScalarAll(100)); | |
| } | |
| } | |
| ////////////////////ゲーム用ルーチン///////////////////////////////////////////// | |
| void | |
| MakeFieldImage() | |
| { | |
| // field を初期化して、線を引く | |
| cvSet(field_img,cvScalarAll(255)); | |
| cvRectangle(field_img,cvPoint(0,FIELD_SIZE*2/8),cvPoint(FIELD_SIZE/8, FIELD_SIZE*6/8),CV_RGB(255,0,0),CV_FILLED); | |
| cvRectangle(field_img,cvPoint(FIELD_SIZE*7/8,FIELD_SIZE*2/8),cvPoint(FIELD_SIZE, FIELD_SIZE*6/8),CV_RGB(255,0,0),CV_FILLED); | |
| for(int x =0;x<3;x++){ | |
| for(int y=0;y<3;y++){ | |
| if(board[x][y]== PLAYER_1 && PLAYER_1==AI_PLAYER){ | |
| //とりあえず黒丸を描く、要変更 | |
| cvCircle(field_img, cvPoint(x*FIELD_SIZE/3 + FIELD_SIZE/6, y*FIELD_SIZE/3 + FIELD_SIZE/6), FIELD_SIZE/7, cvScalarAll(0),4); | |
| } | |
| if(board[x][y]==PLAYER_2 && PLAYER_2==AI_PLAYER){ | |
| //とりあえずXを描く | |
| cvLine(field_img,cvPoint(x*FIELD_SIZE/3,y*FIELD_SIZE/3),cvPoint( (x+1)*FIELD_SIZE/3,(y+1)*FIELD_SIZE/3),cvScalarAll(0),4); | |
| cvLine(field_img,cvPoint( (x+1)*FIELD_SIZE/3,y*FIELD_SIZE/3),cvPoint( (x)*FIELD_SIZE/3,(y+1)*FIELD_SIZE/3),cvScalarAll(0),4); | |
| } | |
| } | |
| } | |
| } | |
| void | |
| CoutBoard(int input[3][3]){ | |
| fprintf(stderr,"------\n"); | |
| for(int y=0;y<3;y++){ | |
| fprintf(stderr,"%2d%2d%2d\n",input[0][y],input[1][y],input[2][y]); | |
| } | |
| } | |
| int | |
| CountBlank(int input[3][3]){ | |
| int blank=0; | |
| for(int x=0;x<3;x++){ | |
| for(int y=0;y<3;y++){ | |
| if(input[x][y]==BLANK) | |
| blank++; | |
| } | |
| } | |
| return blank; | |
| } | |
| //盤面の勝敗判定 | |
| int | |
| BoardCheck(int input_board[3][3]) | |
| { | |
| for(int i=0;i<3;i++){ | |
| int val = input_board[i][0]+input_board[i][1]+input_board[i][2]; | |
| if( val==PLAYER_1*3){ | |
| return PLAYER_1; | |
| } | |
| if(val==PLAYER_2*3){ | |
| return PLAYER_2; | |
| } | |
| val = input_board[0][i]+input_board[1][i]+input_board[2][i]; | |
| if( val==PLAYER_1*3){ | |
| return PLAYER_1; | |
| } | |
| if(val==PLAYER_2*3){ | |
| return PLAYER_2; | |
| } | |
| } | |
| int val = input_board[0][0]+input_board[1][1]+input_board[2][2]; | |
| if( val==PLAYER_1*3){ | |
| return PLAYER_1; | |
| } | |
| if(val==PLAYER_2*3){ | |
| return PLAYER_2; | |
| } | |
| val = input_board[2][0]+input_board[1][1]+input_board[0][2]; | |
| if( val==PLAYER_1*3){ | |
| return PLAYER_1; | |
| } | |
| if(val==PLAYER_2*3){ | |
| return PLAYER_2; | |
| } | |
| return BLANK; | |
| } | |
| void | |
| ShowWinner(){ | |
| if(winner == AI_PLAYER){ | |
| cvPutText(field_img, "COMPUTER", cvPoint(0,FIELD_SIZE*1/3),&cvFont(5,4),cvScalar(0,255,0,0)); | |
| cvPutText(field_img, "WIN", cvPoint(0,FIELD_SIZE*2/3),&cvFont(5,4),cvScalar(255,0,0,0)); | |
| GetProjectorView(); | |
| cvShowImage(MAIN_WINDOW,projection_img); | |
| } | |
| if(AI_PLAYER!=0 && winner == AI_PLAYER*-1){ | |
| cvPutText(field_img, "YOU", cvPoint(0,FIELD_SIZE*1/3),&cvFont(5,4),cvScalar(0,255,0,0)); | |
| cvPutText(field_img, "WIN", cvPoint(0,FIELD_SIZE*2/3),&cvFont(5,4),cvScalar(255,0,0,0)); | |
| GetProjectorView(); | |
| cvShowImage(MAIN_WINDOW,projection_img); | |
| } | |
| if( AI_PLAYER == 0 && winner == PLAYER_1){ | |
| cvPutText(field_img, "PLAYER 1", cvPoint(0,FIELD_SIZE*1/3),&cvFont(4,4),cvScalar(0,255,0,0)); | |
| cvPutText(field_img, "WIN", cvPoint(0,FIELD_SIZE*2/3),&cvFont(4,4),cvScalar(255,0,0,0)); | |
| GetProjectorView(); | |
| cvShowImage(MAIN_WINDOW,projection_img); | |
| } | |
| if( AI_PLAYER == 0 && winner == PLAYER_2){ | |
| cvPutText(field_img, "PLAYER 2", cvPoint(0,FIELD_SIZE*1/3),&cvFont(4,4),cvScalar(0,255,0,0)); | |
| cvPutText(field_img, "WIN", cvPoint(0,FIELD_SIZE*2/3),&cvFont(4,4),cvScalar(255,0,0,0)); | |
| GetProjectorView(); | |
| cvShowImage(MAIN_WINDOW,projection_img); | |
| } | |
| if(winner == BLANK){ | |
| cvPutText(field_img, "DRAW", cvPoint(0,FIELD_SIZE*1/3),&cvFont(4,4),cvScalar(0,255,0,0)); | |
| cvPutText(field_img, "GAME", cvPoint(0,FIELD_SIZE*2/3),&cvFont(4,4),cvScalar(255,0,0,0)); | |
| GetProjectorView(); | |
| cvShowImage(MAIN_WINDOW,projection_img); | |
| } | |
| return; | |
| } | |
| //直接入力による盤面の更新 | |
| bool | |
| UpdateBoard2(int bx, int by, int player) | |
| { | |
| if(bx<0 || bx>=3 || by <0 || by>=3) | |
| return false; | |
| if(board[bx][by]!=0) | |
| return false; | |
| board[bx][by]=player; | |
| game_state++; | |
| CoutBoard(board); | |
| //交代や、盤面のチェックはここだとまずいかも。 | |
| //手番の交代 | |
| available_player = player*-1; | |
| winner = BoardCheck(board); | |
| if(winner !=0){ | |
| fprintf(stderr,"WINNER = %d \n",winner); | |
| available_player = BLANK; | |
| } | |
| return true; | |
| } | |
| //座標入力による盤面の更新 | |
| bool | |
| UpdateBoard(int x, int y, int player) | |
| { | |
| int bx,by; | |
| bx = x/(FIELD_SIZE/3); | |
| by = y/(FIELD_SIZE/3); | |
| return UpdateBoard2(bx,by,player); | |
| } | |
| bool | |
| FieldCheck() | |
| { | |
| //Field画像を取得 | |
| GetTopView(); | |
| if(!top_img){ | |
| return false; | |
| } | |
| IplImage *current_field = cvCloneImage(top_img); | |
| // added from | |
| IplImage* dst; | |
| IplImage* color_dst; | |
| CvMemStorage* storage = cvCreateMemStorage(0); | |
| CvSeq* lines = 0; | |
| int i; | |
| // here | |
| //盤面の確認用差分画像 | |
| IplImage *debug_image1, *debug_image2,*debug_image3; | |
| debug_image1 = cvCreateImage(cvGetSize(current_field), IPL_DEPTH_8U,1); | |
| debug_image2 = cvCreateImage(cvGetSize(initial_field), IPL_DEPTH_8U,1); | |
| debug_image3 = cvCreateImage(cvGetSize(initial_field), IPL_DEPTH_8U,1); | |
| cvCvtColor(current_field ,debug_image1, CV_RGB2GRAY); | |
| cvCvtColor(initial_field ,debug_image2, CV_RGB2GRAY); | |
| cvAbsDiff(debug_image1,debug_image2,debug_image3); | |
| cvThreshold(debug_image3,debug_image2,BOARD_THRESHOLD,255,CV_THRESH_BINARY); | |
| cvShowImage("debug",debug_image2); | |
| // added from | |
| //画像領域の確保 | |
| dst = cvCreateImage( cvGetSize(debug_image2), 8, 1 ); | |
| color_dst = cvCreateImage( cvGetSize(debug_image2), 8, 3 ); | |
| //まずはエッジ検出 | |
| cvCanny( debug_image2, dst, 50, 200, 3 ); | |
| //エッジ画像をカラー化 | |
| cvCvtColor( dst, color_dst, CV_GRAY2BGR ); | |
| //ハフ変換で直線検出 | |
| lines = cvHoughLines2( dst, // 入力画像 | |
| storage, // 検出された線を保存する領域 | |
| CV_HOUGH_PROBABILISTIC, // ハフ変換の種類 | |
| 1, // 距離解像度(1ピクセル当たりの単位) | |
| CV_PI/720,//180, // 角度解像度(ラジアン単位) | |
| 5, // しきい値 | |
| 5, // 各種法で使うパラメータ1 増やすと線が減った | |
| 10 ); // パラメータ2 | |
| //検出した直線を描 | |
| for( i = 0; i < lines->total; i++ ) | |
| { | |
| CvPoint* line = (CvPoint*)cvGetSeqElem(lines,i); | |
| cvLine( color_dst, line[0], line[1], CV_RGB(255,0,0), 3, CV_AA, 0 ); | |
| } | |
| //ウインドウに表示 | |
| cvNamedWindow( "Hough", 1 ); | |
| cvShowImage( "Hough", color_dst ); | |
| // here | |
| //9枚の画像領域を確保 | |
| IplImage **current_grid; | |
| IplImage **initial_grid; | |
| current_grid = (IplImage**)malloc(sizeof(IplImage*)*9); | |
| initial_grid = (IplImage**)malloc(sizeof(IplImage*)*9); | |
| //盤面の分割 | |
| for(int i = 0;i<9;i++){ | |
| int x = i%3; | |
| int y = i/3; | |
| cvSetImageROI(current_field, cvRect(x*current_field->width/3, y*current_field->height/3,current_field->width/3,current_field->height/3)); | |
| cvSetImageROI(initial_field, cvRect(x*initial_field->width/3, y*initial_field->height/3,initial_field->width/3,initial_field->height/3)); | |
| current_grid[i]=cvCreateImage(cvGetSize(current_field), IPL_DEPTH_8U,1); | |
| initial_grid[i]=cvCreateImage(cvGetSize(initial_field), IPL_DEPTH_8U,1); | |
| cvCvtColor(current_field ,current_grid[i], CV_RGB2GRAY); | |
| cvCvtColor(initial_field ,initial_grid[i], CV_RGB2GRAY); | |
| cvResetImageROI(current_field); | |
| cvResetImageROI(initial_field); | |
| } | |
| //各画像を認識 | |
| //作業用領域 | |
| IplImage *sub_image; | |
| sub_image = cvCreateImage(cvGetSize(current_grid[0]),IPL_DEPTH_8U,1); | |
| IplImage *bin_image; | |
| bin_image = cvCreateImage(cvGetSize(current_grid[0]),IPL_DEPTH_8U,1); | |
| CvMoments moments[9]; | |
| for(int i=0;i<9;i++){ | |
| cvAbsDiff(initial_grid[i],current_grid[i],sub_image); | |
| cvThreshold(sub_image,bin_image,BOARD_THRESHOLD,255,CV_THRESH_BINARY); | |
| //マグネットなんかがおかれてそうな場所を決定 | |
| //モーメントを求める | |
| cvMoments(bin_image, &moments[i],1); | |
| } | |
| //しばらく様子見 | |
| Sleep(100); | |
| //マグネットがおかれてそうな場所が1つに絞れたら場所の決定+盤面を更新して返す。 | |
| bool avairable_board[3][3]; | |
| int x=-1,y=-1,count=0; | |
| CvMoments tmp_moments; | |
| for(int i=0;i<9;i++){ | |
| int tx= i%3; | |
| int ty= i/3; | |
| //もういっかい同じ計算をします。 | |
| if(board[tx][ty]==BLANK && cvGetSpatialMoment(&moments[i],0,0) > MOMENT_TH){ | |
| cvAbsDiff(initial_grid[i],current_grid[i],sub_image); | |
| cvThreshold(sub_image,bin_image,BOARD_THRESHOLD,255,CV_THRESH_BINARY); | |
| //マグネットなんかがおかれてそうな場所を決定 | |
| //モーメントを求める | |
| // cvSetImageCOI(bin_image,1); | |
| cvMoments(bin_image, &tmp_moments,1); | |
| //面積が大きいままならば石がおかれたかもしれない。 | |
| if(cvGetSpatialMoment(&tmp_moments,0,0) > MOMENT_TH ){ | |
| x=tx; | |
| y=ty; | |
| count ++; | |
| } | |
| } | |
| } | |
| //とりあえず、画像は解放 | |
| cvReleaseImage(&debug_image1); | |
| cvReleaseImage(&debug_image2); | |
| cvReleaseImage(&debug_image3); | |
| cvReleaseImage(¤t_field); | |
| cvReleaseImage(&sub_image); | |
| cvReleaseImage(&bin_image); | |
| for(int i = 0;i<9;i++){ | |
| cvReleaseImage(&initial_grid[i]); | |
| cvReleaseImage(¤t_grid[i]); | |
| } | |
| if(count == 1){ | |
| board_update = UpdateBoard2(x,y,available_player); | |
| return true; | |
| } | |
| //マグネットが見つからなくても、いったん返す | |
| return false; | |
| } | |
| bool | |
| AIRandom(int player) | |
| { | |
| //現在の盤面のコピー | |
| int local_board[3][3]; | |
| int avairable_area=0; | |
| for(int y=0;y<3;y++){ | |
| for(int x=0;x<3;x++){ | |
| local_board[x][y]=board[x][y]; | |
| if(local_board[x][y] == BLANK){ | |
| avairable_area++; | |
| } | |
| } | |
| } | |
| if(avairable_area == 0){ | |
| return false; | |
| } | |
| //乱数を生成する。 | |
| srand(time(NULL)); | |
| int x,y; | |
| for(;;){ | |
| x = rand()%3; | |
| y = rand()%3; | |
| if(local_board[x][y]==BLANK){ | |
| board_update = UpdateBoard2(x,y,player); | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| ///////////////////イベント処理用とか初期化とか///////////////////////////////////////////// | |
| void | |
| initGameMode() | |
| { | |
| printf("Game mode \n"); | |
| PROJECTOR_VIEW_MODE=false; | |
| CAMERA_VIEW_MODE=false; | |
| TOP_VIEW_MODE=false; | |
| GAME_MODE = true; | |
| available_player = PLAYER_1; | |
| game_state = 0; | |
| winner = 0; | |
| if (field_img) cvReleaseImage(&field_img); | |
| field_img = cvCloneImage(sample_img); | |
| if (!sample_img){ | |
| fprintf(stderr, "No sample image\n"); | |
| } | |
| if (!field_img) | |
| fprintf(stderr, "No ImageFile\n"); | |
| for(int x =0;x<3;x++){ | |
| for(int y=0;y<3;y++){ | |
| board[x][y]=0; | |
| } | |
| } | |
| MakeFieldImage(); | |
| //プロジェクタで盤面を投影する。 | |
| if(field_img){ | |
| GetProjectorView(); | |
| // cvFlip(projection_img, projection_img); | |
| cvShowImage(MAIN_WINDOW, projection_img); | |
| } | |
| //フィールドの初期画像を保存 | |
| GetTopView(); | |
| if(initial_field){ | |
| cvReleaseImage(&initial_field); | |
| } | |
| initial_field = cvCloneImage(top_img); | |
| } | |
| // キーボード入力コールバック | |
| void keyboardFunc(unsigned char key) | |
| { | |
| fprintf(stderr,"key = %c\n", key); | |
| switch (key) { | |
| case '1': | |
| if(GAME_MODE){ | |
| board_update = UpdateBoard2(0,0,available_player); | |
| } | |
| break; | |
| case '2': | |
| if(GAME_MODE){ | |
| board_update = UpdateBoard2(1,0,available_player); | |
| } | |
| break; | |
| case '3': | |
| if(GAME_MODE){ | |
| board_update = UpdateBoard2(2,0,available_player); | |
| } | |
| break; | |
| case '4': | |
| if(GAME_MODE){ | |
| board_update = UpdateBoard2(0,1,available_player); | |
| } | |
| break; | |
| case '5': | |
| if(GAME_MODE){ | |
| board_update = UpdateBoard2(1,1,available_player); | |
| } | |
| break; | |
| case '6': | |
| if(GAME_MODE){ | |
| board_update = UpdateBoard2(2,1,available_player); | |
| } | |
| break; | |
| case '7': | |
| if(GAME_MODE){ | |
| board_update = UpdateBoard2(0,2,available_player); | |
| } | |
| break; | |
| case '8': | |
| if(GAME_MODE){ | |
| board_update = UpdateBoard2(1,2,available_player); | |
| } | |
| break; | |
| case '9': | |
| if(GAME_MODE){ | |
| board_update = UpdateBoard2(2,2,available_player); | |
| } | |
| break; | |
| case 'q': | |
| case 'Q': | |
| case '\033': // '\033' は ESC の ASCII コード | |
| exit(0); | |
| break; | |
| case 'T': | |
| case 't': | |
| printf("Top view mode \n"); | |
| TOP_VIEW_MODE = true; | |
| CAMERA_VIEW_MODE=false; | |
| PROJECTOR_VIEW_MODE=false; | |
| GAME_MODE = false; | |
| break; | |
| case 'C': | |
| printf("Camera Calibration mode \n"); | |
| CAMERA_CALIBRATION_MODE = true; | |
| click_count = 0; | |
| case 'c': | |
| printf("Camera View mode \n"); | |
| CAMERA_VIEW_MODE = true; | |
| TOP_VIEW_MODE=false; | |
| PROJECTOR_VIEW_MODE=false; | |
| GAME_MODE = false; | |
| break; | |
| case 'P': | |
| printf("Projector Calibration mode \n"); | |
| PROJECTOR_CALIBRATION_MODE=true; | |
| graycode_count=0; | |
| wait_count=1; | |
| case 'p': | |
| printf("Projector View mode \n"); | |
| PROJECTOR_VIEW_MODE=true; | |
| CAMERA_VIEW_MODE=false; | |
| TOP_VIEW_MODE=false; | |
| GAME_MODE = false; | |
| break; | |
| case 'A': | |
| AI_PLAYER= PLAYER_1; | |
| initGameMode(); | |
| break; | |
| case 'a': | |
| AI_PLAYER= PLAYER_2; | |
| initGameMode(); | |
| break; | |
| case 'g': | |
| AI_PLAYER = 0; | |
| initGameMode(); | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| //------------------------------------------------------------------------------ | |
| // アイドル時のコールバック | |
| void idleFunc() | |
| { | |
| if (capture) { //カメラが存在するとき | |
| //キャプチャ | |
| frame = cvQueryFrame(capture); | |
| //} | |
| // | |
| } else { //カメラが存在しないとき | |
| //特にやることなし | |
| } | |
| //テクスチャに描画したい画像を投げる | |
| if(CAMERA_VIEW_MODE){ | |
| cvShowImage(MAIN_WINDOW, frame); | |
| } | |
| else if(TOP_VIEW_MODE){ | |
| // | |
| GetTopView(); | |
| if(top_img){ | |
| cvShowImage(MAIN_WINDOW, top_img); | |
| } | |
| else{ | |
| cvShowImage(MAIN_WINDOW,frame); | |
| fprintf(stderr, "Found No top image\n"); | |
| } | |
| }else if(PROJECTOR_VIEW_MODE){ | |
| if(PROJECTOR_CALIBRATION_MODE){ | |
| //wait_countが0WAIT_FRAMEの整数倍の時にキャプチャ | |
| if(wait_count%WAIT_FRAME == 0){ | |
| frame = cvQueryFrame(capture); | |
| captured_code_img[graycode_count]= cvCloneImage(frame); | |
| graycode_count++; | |
| } | |
| //整数倍でないときは、グレイコード画像を投影 | |
| if(wait_count%WAIT_FRAME!=0 && graycode_count<GRAYCODE_NUM){ | |
| printf("No %d \n",graycode_count); | |
| cvShowImage(MAIN_WINDOW,graycode_img[graycode_count]); | |
| } | |
| //投影・撮影が終わったらカウンターを戻してキャリブレーションの計算 | |
| if(graycode_count>=GRAYCODE_NUM){ | |
| graycode_count=0; | |
| ProjectorCalibration(); | |
| //最後にフラグを戻してキャリブレーション終了 | |
| PROJECTOR_CALIBRATION_MODE=false; | |
| } | |
| wait_count++; | |
| } | |
| //PROJECTOR_VIEW_MODEの場合は、ホモグラフィを元に変換して投影。 | |
| else if(projection_img){ | |
| GetProjectorView(); | |
| cvShowImage(MAIN_WINDOW,projection_img); | |
| } | |
| else{ | |
| cvShowImage(MAIN_WINDOW,frame); | |
| } | |
| } | |
| else if(GAME_MODE){ | |
| //(マウスで)手の入力があった場合 | |
| //FieldRecognition(); | |
| //AI対戦でAIの手番の場合次の手を決定 | |
| if(available_player !=0){ | |
| if(available_player == AI_PLAYER){ | |
| AIRandom(AI_PLAYER); | |
| } | |
| else{ | |
| FieldCheck(); | |
| } | |
| } | |
| if(board_update){ | |
| //フィールド画像の作成 | |
| MakeFieldImage(); | |
| //プロジェクタ画像の更新 | |
| board_update=false; | |
| } | |
| if(winner !=0 || CountBlank(board)==0){ | |
| // fprintf(stderr,"WINNER = %d \n",winner); | |
| ShowWinner(); | |
| // available_player = BLANK; | |
| } | |
| //プロジェクタで盤面を投影する。 | |
| if(field_img){ | |
| GetProjectorView(); | |
| // cvFlip(projection_img, projection_img); | |
| cvShowImage(MAIN_WINDOW,projection_img); | |
| } | |
| else{ | |
| fprintf(stderr, "No field image\n"); | |
| } | |
| } | |
| else{ | |
| exit(1); | |
| } | |
| } | |
| /* コールバック関数 */ | |
| void | |
| on_mouse (int event, int x, int y, int flags, void *param = NULL) | |
| { | |
| double ox=0, oy=0; | |
| // (4)マウスイベントを取得 | |
| switch (event) { | |
| case CV_EVENT_LBUTTONDOWN: | |
| //マウス左ボタンが押された座標を取得 | |
| ox = x*capture_width/window_width; | |
| oy = y*capture_height/window_height; | |
| if(CAMERA_CALIBRATION_MODE){ | |
| camera_field[click_count][0]= ox; | |
| camera_field[click_count][1]= oy; | |
| printf("%lf, %lf \n",ox,oy); | |
| click_count++; | |
| if(click_count>=ARRAY_SIZE){ | |
| click_count=0; | |
| FindHomography( camera_field , table_field , &Hct); | |
| CAMERA_CALIBRATION_MODE = false; | |
| } | |
| } | |
| else if(GAME_MODE){ | |
| //board_update = UpdateBoard(ox,oy,1); | |
| } | |
| else{ | |
| printf("%lf, %lf \n",ox,oy); | |
| } | |
| break; | |
| } | |
| } | |
| int main( int argc, char** argv ) | |
| { | |
| capture = cvCaptureFromCAM(0); | |
| if (capture) { // カメラが見つかったとき | |
| //記念に一枚 | |
| frame = cvQueryFrame(capture); | |
| // カメラのキャプチャ領域サイズを取得 | |
| capture_width = (int)( cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH) ); | |
| capture_height = (int)( cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT) ); | |
| } else { | |
| fprintf(stderr,"Could not initialize capturing...\n"); | |
| return -1; | |
| } | |
| //プロジェクタ画像用 tic-tac-toe のフィールド | |
| projection_img = cvCreateImage(cvSize(PROJECTION_WIDTH, PROJECTION_HEIGHT), IPL_DEPTH_8U, 3); | |
| cvRectangle(projection_img, cvPoint(0,0),cvPoint(PROJECTION_WIDTH -1, PROJECTION_HEIGHT - 1 ), cvScalarAll(0)); | |
| //テスト用画像 | |
| sample_img = cvLoadImage("laughingman2.png"); | |
| if(!sample_img){ //画像ファイルも見つからないときは終了 | |
| fprintf(stderr, "Found No ImageFile for projection view\n"); | |
| exit(-1); | |
| } | |
| //top view 用の画像 | |
| top_img = cvLoadImage("topview2.png"); | |
| if(!top_img){ //画像ファイルも見つからないときは終了 | |
| fprintf(stderr, "Found No ImageFile for top view\n"); | |
| exit(-1); | |
| } | |
| graycode_img = (IplImage **)malloc(sizeof(IplImage *)*GRAYCODE_NUM); | |
| captured_code_img = (IplImage **)malloc(sizeof(IplImage *)*GRAYCODE_NUM); | |
| char filename[256]; | |
| for(int i=0;i<GRAYCODE_NUM;i++){ | |
| sprintf(filename, GRAYCODE_FILE , i); | |
| graycode_img[i]=cvLoadImage(filename); | |
| if(!graycode_img[i]){ | |
| fprintf(stderr, "can not find %s \n", filename); | |
| } | |
| } | |
| //作業用画像 | |
| gray_img = cvCreateImage (cvGetSize (frame), IPL_DEPTH_8U, 1); | |
| //メインウインドウの作成 | |
| cvNamedWindow( MAIN_WINDOW,0); | |
| cvResizeWindow(MAIN_WINDOW, MAIN_WINDOW_WIDTH, MAIN_WINDOW_HEIGHT); | |
| cvSetMouseCallback (MAIN_WINDOW, on_mouse); | |
| cvNamedWindow( "debug_window",0); | |
| for(;;) | |
| { | |
| idleFunc(); | |
| char c=cvWaitKey(10); | |
| if( c >= 0 ){ | |
| fprintf(stderr,"key = %d, %c, \n", c, c); | |
| if(c=='q'){ | |
| printf("q\n"); | |
| } | |
| keyboardFunc(c); | |
| } | |
| } | |
| cvReleaseCapture( &capture ); | |
| cvDestroyWindow("Camera"); | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment