本小游戲類似于4399中的火柴人打羽毛球游戲,在背景圖上,左右雙方通過鍵盤來進行接球操作。
實現(xiàn)方法比較簡單,其中的知識點包括霍夫圓檢測,鍵盤事件響應,背景填充等。
做這個小游戲的目的主要是為了用于OpenCV學習的階段性展示。
演示視頻如下所示:
basketBallGame
一、 預處理 1.1定義結構體為了增強代碼的可讀性以及后續(xù)對程序的修改,我們對項目中的一些重要對象定義結構體。
包括:游戲角色、背景圖、籃球。
// 定義籃球的結構體(把籃球看作圓形。x,y為籃球位置;d為籃球直徑)
typedef struct ballLoc {double x;
double y;
double d;
};
// 人物結構體(人物的高度,寬度,位置)
typedef struct kun {double heigth;
double width;
double x;
double y;
};
// 背景圖結構體(背景圖的寬度,高度)
typedef struct backgroundI {int bg_width;
int bg_height;
};
1.2背景處理背景圖使用resize()函數(shù)調(diào)整到合適的大小
籃球如下圖所示,為了讓籃球能夠完美地貼合到背景圖中,我們這里的先使用霍夫圓檢測,把籃球單獨從圖像之中摳出來備用。
籃球處理分為以下步驟:
1. 預處理(灰度化、高斯模糊)
2. 霍夫圓檢測
3. 在檢測出來的圓中根據(jù)特征提取出我們需要的圓
4. 將提取出來的圓單獨定義為一張圖像,調(diào)整大小并返回給主函數(shù)
實現(xiàn)代碼如下:
// 籃球處理
Mat ballDetect(Mat image) {// 1. 預處理(灰度化,濾波)
Mat gray_image,gauss_image;
cvtColor(image, gray_image, COLOR_BGR2GRAY);
GaussianBlur(gray_image, gauss_image, Size(3, 3), 0, 0);
// 2. 霍夫圓檢測
// 圓的表示:前兩個參數(shù)為圓心坐標,第三個參數(shù)為半徑
vectorball_circles;
HoughCircles(gauss_image, ball_circles, HOUGH_GRADIENT, 1, 50, 80, 80, 50, 200);
// 3. 找到需要的籃球的圓(大的圓)
Vec3f ball_circle = ball_circles[0];
for (int i = 0; i< ball_circles.size(); i++)
{if (ball_circles[i][2] >ball_circle[2]) {ball_circle = ball_circles[i];
}
}
// 4. 這里的(x,y)為通過圓參數(shù)計算出來的正方形的左上角坐標,d為正方形的邊長
double x = ball_circle[0] - ball_circle[2];
double y = ball_circle[1] - ball_circle[2];
double d = ball_circle[2]*2;
Rect rect(x, y,d ,d);
// 單獨把籃球提取出成一張圖像
Mat det_ball;
image(rect).copyTo(det_ball);
resize(det_ball, det_ball, Size(ball_01.d, ball_01.d));
return det_ball;
}
二、項目實現(xiàn)
2.1籃球放置(角色放置同理)如果使用常規(guī)的ball(ROI).copyTo(background(ROI));需要把感興趣區(qū)域設置為圓形,但是由于沒有看懂這塊是怎么用的(我不會?。?。所以使用數(shù)學的方法暴力進行背景填充。
如下圖所示,給出一個圓形和他的外接正方形(正方形邊長與圓直徑相同),將中心視作圖像的原點,那么我們就可以通過判斷 x,y的坐標與圓半徑r的關系得出這個點是否落在圓內(nèi)。
但是由于圖形的默認坐標是從左上角算起。即(0,0)點為圖像的左上點。所以我們在遍歷圖像像素點的過程中應當使用額外的參數(shù)來進行判斷。
實現(xiàn)代碼如下:
圓形區(qū)域(籃球)像素點不變;圓形區(qū)域外的像素用背景圖的對應像素進行替換
// 畫球(主要用來分離背景)
// 有坐標位置,有背景圖
void drawBall(Mat & ball) {
int r = ball_01.d / 2;
for (int i = -r, ix = 0; i< ball_01.d - r; i++, ix++) {for (int j = -r, iy = 0; j< ball_01.d - r; j++, iy++) {if (i * i + j * j >r * r) {for (int c = 0; c< 3; c++) {ball.at(iy, ix)[c] = background.at(ball_01.y + iy, ball_01.x + ix)[c];
}
}
}
}
}
2.2籃球移動(角色移動同理,但是需要通過鍵盤監(jiān)聽)在主函數(shù)中通過while(1){} ,不斷循環(huán)繪制籃球(通過籃球坐標),由于我們定義了籃球位置的結構體,所以如果想要改變籃球的位置,修改其坐標即可。
// x向著左邊越界
if (ball_01.x<= 5) {ball_01.x += 1;
b_x = -b_x;
}
// x右邊界越界
else if (ball_01.x >= (bg_width - ball_01.d - 4)) {ball_01.x -= 1;
b_x = -b_x;
}
// 上邊界
else if (ball_01.y<= 5) {ball_01.y += 1;
b_y = -b_y;
}
// 下邊界
else if (ball_01.y >= (bg_height - ball_01.d - 4)) {ball_01.y -= 1;
b_y = -b_y;
break;
}
籃球撞墻后的變向思路如下圖所示:
角色與籃球碰撞后,籃球的運動方向改變,且角色狀態(tài)改變。
這里只是通過籃球和角色的位置以及他們各自的高度寬度進行檢測,因此如果當籃球的大小設置的過于大時,會出現(xiàn)bug,感覺后續(xù)可以通過opencv視覺的方法進行替換。代碼如下:
// 檢測哥哥與籃球碰撞
if (((ball_01.y + ball_01.d) >= kun01.y &&
(ball_01.x + ball_01.d) >= kun01.x &&
(ball_01.x + ball_01.d)<= (kun01.x + kun01.width))
||
((ball_01.y + ball_01.d) >= kun_right.y &&
(ball_01.x + ball_01.d) >= kun_right.x &&
(ball_01.x + ball_01.d)<= (kun_right.x + kun_right.width)
))
{drawKun(background, kunImage2, 0);
drawKun(background, kunImage2, 1);
b_y = -b_y;
}
2.4角色移動角色移動通過監(jiān)聽鍵盤響應實現(xiàn)。
使用int key = waitKeyEx(1);獲取到按鍵,再通過按鍵內(nèi)容進行響應。
int key = waitKeyEx(1);
if (key == 2424832)
{//鍵盤←鍵
if (kun01.x >10) {kun01.x -= 10;
drawKun(background, kunImage2, 0);
}
}
if (key == 2555904)
{//鍵盤→鍵
if (kun01.x< ((bg01.bg_width - 10 - kun01.width)/2)) {kun01.x += 10;
drawKun(background, kunImage2, 0);
}
}
if (key == 97)
{//鍵盤a鍵
if (kun_right.x >((bg01.bg_width - 10 - kun_right.width)/2)) {kun_right.x -= 10;
drawKun(background, kunImage2, 1);
}
}
if (key == 100)
{//鍵盤d鍵
if (kun_right.x< (bg01.bg_width - 10 - kun_right.width)) {kun_right.x += 10;
drawKun(background, kunImage2, 1);
}
}
三、項目總結
3.1 復習內(nèi)容vectorball_circles;
HoughCircles(gauss_image, ball_circles, HOUGH_GRADIENT, 1, 50, 80, 80, 50, 200);
int key = waitKeyEx(1);
key = 100:d
key = 97:a
key = 2555904:鍵盤→鍵
key = 2424832:鍵盤←鍵
可以嘗試用數(shù)學的角度去解決一些圖像中的問題。
例如正方形中大圓的檢測以及碰撞中球的運動軌跡變化
https://download.csdn.net/download/weixin_46221106/87212956
你是否還在尋找穩(wěn)定的海外服務器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調(diào)度確保服務器高可用性,企業(yè)級服務器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧