学习了一段时间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