學習了一段時間opencv視覺編程,也不知道自己學了點啥,做一個小的東西練練手,作爲入門學習的練習吧。如果要跳起來可以用調用ADB工具進行與手機通訊實現模擬人的點擊。
ADB工具下載地址:https://download.csdn.net/download/llikestudy_/10826334
一、起始點識別:
從圖可以看到,棋子是圖中不變得元素,我們可以通過模板匹配來確定妻子的位置然後通過棋子的位置,對座標進一步加工,得到起始點位置。
//使用模板匹配匹配到圖中棋子位置
Mat src, playsrc,local_player;
src = imread("1.jpg"); //帶匹配圖
playsrc = imread("2.png"); //模板(棋子)
src.copyTo(local_player);
int resultImage_cols = local_player.cols - playsrc.cols + 1;
int resultImage_rows = local_player.rows - playsrc.rows + 1;
Mat resultImage;
resultImage.create(resultImage_cols,resultImage_rows,CV_32FC1);
matchTemplate(local_player, playsrc, resultImage, TM_CCOEFF_NORMED); //模板匹配
匹配到了模板位置,用線框圈出棋子位置,標出起始點。
Point max_Loc; //max_Loc是最佳匹配的區域左上角點
minMaxLoc(resultImage, 0,0,0, &max_Loc, Mat()); //minMaxLoc尋找矩陣(一維數組當作向量,用Mat定義) 中最小值和最大值的位置,這裏只需要最大值,即左上角點。
Point sport = Point(max_Loc.x + 25, max_Loc.y + 150);
Scalar color(0, 0, 255);
circle(local_player, sport, 6, color, -1);
rectangle(local_player, max_Loc,Point(max_Loc.x+50,max_Loc.y+150),Scalar(255,0,255), 2, 8);
printf("玩家落點位置:(%d,%d)\n", max_Loc.x + 50, max_Loc.y + 150);
可以看出,棋子位置已經被標出,起始點被標出爲紅點。下一步就是尋找目標點位置。
二、目標點位置:
首先對圖像先進行一些處理,以便操作。
我們看出,其實我們所需要的是上半部分的區域,且上半區域有標誌等部分干擾項也將其切除。
Mat blur;
GaussianBlur(src, blur, Size(5, 5), 0);
Mat canny_image;
Canny(blur, canny_image, 1, 10);//先預處理
int height, width;
height = canny_image.rows;
width = canny_image.cols;
Mat crop_img;
Rect crop_rect;
crop_rect = Rect(0, 300, width, int(height / 2 - 300));//左上角座標,寬,高
crop_img = canny_image(crop_rect);//取出所需要的區域(這裏記住,我們給圖像上面去除了300像素,後面計算的縱座標得加回來)
得到的效果:
圖中看到,棋子還留有一點干擾項,也給它去掉。因爲之前已經得出了棋子位置,遍歷棋子位置,像素值置零就好了。
for (int i = max_Loc.x; i <= max_Loc.x + 50; i++)
for (int j = max_Loc.y; j <= max_Loc.y+150; j++)
{
canny_image.at<uchar>(j, i) = 0;
}
效果圖:
嗯啊,現在乾淨多了。
現在我們該計算這個目標跳臺的中心點了啊,看下圖:
由圖很容易看出,獲得最上點的x,最右點的y。
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(crop_img, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point()); //找到關鍵的角點
//遍歷每一個輪廓,把多餘的輪廓去掉
Point point1;
Point point2;
vector<vector<Point> >::const_iterator it = contours.begin();
while (it != contours.end()) {
if (it->size() < 150)
it = contours.erase(it);
else
++it;
}
int nYMin = crop_img.rows;
int nXMin = crop_img.cols;
int nYMax = 0;
int nXMax = 0;
int nIdY = 0;
for (int i = 0; i < contours.size(); i++)
{
//contours[i]代表的是第i個輪廓,contours[i].size()代表的是第i個輪廓上所有的像素點數
for (int j = 0; j < contours[i].size(); j++)
{
if (contours[i][j].y < nYMin)
{
nYMin = contours[i][j].y; //找到最低的y值
point1 = contours[i][j]; //記錄 y值最低點座標
nIdY = i; //記錄哪個區域內的
}
}
}
int minY = crop_img.cols;
for (int j = 0; j < contours[nIdY].size(); j++) //在哪個區域內繼續變量 找到x最大值
{
if (contours[nIdY][j].x > nXMax)
{
nXMax = contours[nIdY][j].x;
}
}
for (int j = 0; j < contours[nIdY].size(); j++)
{//找到x中最大值上的最小值
if (contours[nIdY][j].x == nXMax && contours[nIdY][j].y < minY)
{
point2 = contours[nIdY][j];
minY = contours[nIdY][j].y; //記錄X點的最大值
}
}
point2.y = point2.y + 300; // y測得不準,因爲之前上面切掉了300像素,得加上
Point center = Point(point1.x, point2.y); //返回中點座標
printf("中心的:(%d,%d)\n", point1.x, point2.y);
circle(local_player, center, 6, Scalar(0, 0, 255), -1);
效果如下:
兩點座標已知,求起始點和目標點距離,勾股定理。
int A = max_Loc.x + 25 - point1.x;
int B = max_Loc.y + 150 - point2.y;
C = int(pow(pow(A, 2) + pow(B, 2), 0.5));
line(local_player, sport, center, Scalar(255, 0, 255), 2, 8);
printf("距離爲:%d", C);
好吧,最主要的兩點就得到了,剩下的自己慢慢完善就好了。如果要跳起來可以用調用ADB工具進行與手機通訊實現模擬人的點擊。
ADB工具下載地址:https://download.csdn.net/download/llikestudy_/10826334