不多说了先上代码
hpp
#include <stdio.h>
#include<string.h>
#include<math.h>
#include<iostream>
#include<opencv2/highgui.hpp>
#include<opencv2/opencv.hpp>
using namespace cv;
using namespace std;
//池化,用于图像降维
Mat pool_max(Mat image_source, int size);
Mat pool_min(Mat image_source, int size);
int f(int x1,int x2,int z1,int z2);
class A
{
private:
int rate=6;
int map[300][300];
Mat m;
//open,close表的栈顶
int tag_open=0,tag_close=0;
//用来存每一点的父节点
int map_root[300][300][2];
//入口
int x1;
int x2;
//出口
int z1;
int z2;
//路径
int way[1000][2];
//表的第三个参数是代价
//倒放,从大到小,tag_close是最小close[x][2]的x,3,4,父节点坐标
int close[24400][3];
//倒放,从大到小,tag_open是最小open[x][2]的x
int open[24400][4];
public:
//用于存放读入原图
Mat image_source;
//图片降维
void deal_image();
//找到出入口
void find_ori();
//a*算法核心
void deal_A();
//输出路径
void draw_road();
};
void A::draw_road()
{
Mat rgb;
rgb=imread("3.png",1);
VideoWriter witer = VideoWriter("m3.avi",CV_FOURCC('M','P','4','2'),40,Size(image_source.cols,image_source.cols),1);//保存视频
int mm=0;
//每次循环画一个点
while(1)
{
mm++;
//为了画大点,所以下面写了九个像素
for(int tag_a=4;tag_a<7;tag_a++)
for(int tag_b=4;tag_b<7;tag_b++)
for(int tag_c=0;tag_c<2;tag_c++)
rgb.at<Vec3b>((map_root[z1][z2][0]*rate+tag_a),(map_root[z1][z2][1]*rate+tag_b))[tag_c%3]=0;
imshow("a",rgb);
waitKey(1);
z1=map_root[z1][z2][0];
z2=map_root[z1][z2][1];
//输出位置坐标
witer<<rgb;
printf("%d %d \n",z1,z2);
//如果点数超过1000或者到达终点结束画路径
if(((z1==x1)&&(z2==x2))||mm>1000)break;
}
//最后一帧停止,按键继续
imshow("a",rgb);
witer.release();
}
void A::find_ori()
{
Mat image_b;
GaussianBlur(image_source,image_b,Size(3,3),5);
//图片二值化
for(int tag_a=0;tag_a<image_b.rows;tag_a++)
{
for(int tag_b=0;tag_b<image_b.cols;tag_b++)
if(image_b.at<uchar>(tag_a,tag_b)>100)image_b.at<uchar>(tag_a,tag_b)=255;
else image_b.at<uchar>(tag_a,tag_b)=0;
}
//最左侧和最右侧的白像素为出入口
for(int tag_b=0;tag_b<image_b.cols;tag_b++)
if(image_b.at<uchar>(tag_b,0)==255)
{
x1=tag_b/rate-1;
x2=0;
}
for(int tag_b=0;tag_b<image_b.cols;tag_b++)
if(image_b.at<uchar>(tag_b,image_b.rows-1)==255)
{
z1=tag_b/rate-1;
z2=(image_b.rows)/rate-1;
}
}
void A::deal_image()
{ //读图
image_source = imread("3.png",0);
//初始化图片b
Mat b;
//图片高斯降噪
GaussianBlur(image_source,b,Size(3,3),5);
//图片二值化
for(int tag_a=0;tag_a<b.rows;tag_a++)
{
for(int tag_b=0;tag_b<b.cols;tag_b++)
if(b.at<uchar>(tag_a,tag_b)>100)b.at<uchar>(tag_a,tag_b)=255;
else b.at<uchar>(tag_a,tag_b)=0;
}
//图片池化3*3(缩小三倍)(处理两次,九倍)
//m=pool_min(pool_max(b,3),3);
m=pool_min(b,6);
//再次二值化
for(int tag_a=0;tag_a<m.rows;tag_a++)
{
for(int tag_b=0;tag_b<m.cols;tag_b++)
if(m.at<uchar>(tag_a,tag_b)>100)m.at<uchar>(tag_a,tag_b)=255;
else m.at<uchar>(tag_a,tag_b)=0;
}
//展示图片
imshow("c",m);
//将图片信息载入数组map
for(int tag_a=0;tag_a<m.rows;tag_a++)
for(int tag_b=0;tag_b<m.cols;tag_b++)
map[tag_a][tag_b]=m.at<uchar>(tag_a,tag_b);
}
void A::deal_A()
{
int keyy1=0,keyy2=0,keyy3=0,keyy4=0;
map_root[z1][z2][0]=5;
//入口放入close表
close[0][0]=x1;
close[0][1]=x2;
tag_close++;
//com用来对比找出open表代价最小的
int com[2]={10000,0};
while(1)
{
//上下左右寻找合法,而且是白色的像素
if(map[close[tag_close-1][0]][close[tag_close-1][1]+1]==255&&close[tag_close-1][0]>=0&&(close[tag_close-1][1]+1)>=0)
{ //close栈顶充当新点(open表内)的父节点
for(int tag_a=0;tag_a<tag_open;tag_a++)
{
//如果open表里已经有这个点了
if((close[tag_close-1][0])==open[tag_a][0]&&(close[tag_close-1][1]+1)==open[tag_a][1])
{ //更新代价
//open[tag_a][2]=close[tag_close-1][2]+1;
keyy1=1;
break;
}
if(keyy1==0)
{
map_root[close[tag_close-1][0]][close[tag_close-1][1]+1][0]=close[tag_close-1][0];
map_root[close[tag_close-1][0]][close[tag_close-1][1]+1][1]=close[tag_close-1][1];
}
keyy1=0;
}
//com记录了open表最小的序号,而且这个已经进入close了,所以这里可以放个新的open点
if(open[com[1]][3]==100000)
{
open[com[1]][0]=close[tag_close-1][0];
open[com[1]][1]=close[tag_close-1][1]+1;
open[com[1]][2]=close[tag_close-1][2]+1;
open[com[1]][3]=f(open[tag_open][0],open[tag_open][1],z1,z2);
}
else
{
//只能放在open顶了
open[tag_open][0]=close[tag_close-1][0];
open[tag_open][1]=close[tag_close-1][1]+1;
open[tag_open][2]=close[tag_close-1][2]+1;
open[tag_open][3]=f(open[tag_open][0],open[tag_open][1],z1,z2);
tag_open++;
}
}
if(map[close[tag_close-1][0]][close[tag_close-1][1]-1]==255&&close[tag_close-1][0]>=0&&(close[tag_close-1][1]-1)>=0)
{
for(int tag_a=0;tag_a<tag_open;tag_a++)
{
if((close[tag_close-1][0])==open[tag_a][0]&&(close[tag_close-1][1]-1)==open[tag_a][1])
{
//open[tag_a][2]=close[tag_close-1][2]+1;
keyy2=1;
break;
}
if(keyy2==0)
{
map_root[close[tag_close-1][0]][close[tag_close-1][1]-1][0]=close[tag_close-1][0];
map_root[close[tag_close-1][0]][close[tag_close-1][1]-1][1]=close[tag_close-1][1];
}
keyy2=0;
}
if(open[com[1]][3]==100000)
{
open[com[1]][0]=close[tag_close-1][0];
open[com[1]][1]=close[tag_close-1][1]-1;
open[com[1]][2]=close[tag_close-1][2]+1;
open[com[1]][3]=f(open[tag_open][0],open[tag_open][1],z1,z2);
}
else
{
open[tag_open][0]=close[tag_close-1][0];
open[tag_open][1]=close[tag_close-1][1]-1;
open[tag_open][2]=close[tag_close-1][2]+1;
open[tag_open][3]=f(open[tag_open][0],open[tag_open][1],z1,z2);
tag_open++;
}
}
if(map[close[tag_close-1][0]+1][close[tag_close-1][1]]==255&&(close[tag_close-1][0]+1)>=0&&(close[tag_close-1][1])>=0)
{
for(int tag_a=0;tag_a<tag_open;tag_a++)
{
if((close[tag_close-1][0]+1)==open[tag_a][0]&&(close[tag_close-1][1])==open[tag_a][1])
{
//open[tag_a][2]=close[tag_close-1][2]+1;
keyy3=1;
break;
}
if(keyy3==0)
{
map_root[close[tag_close-1][0]+1][close[tag_close-1][1]][0]=close[tag_close-1][0];
map_root[close[tag_close-1][0]+1][close[tag_close-1][1]][1]=close[tag_close-1][1];
}
keyy3=0;
}
if(open[com[1]][3]==100000)
{
open[com[1]][0]=close[tag_close-1][0]+1;
open[com[1]][1]=close[tag_close-1][1];
open[com[1]][2]=close[tag_close-1][2]+1;
open[com[1]][3]=f(open[tag_open][0],open[tag_open][1],z1,z2);
}
else
{
open[tag_open][0]=close[tag_close-1][0]+1;
open[tag_open][1]=close[tag_close-1][1];
open[tag_open][2]=close[tag_close-1][2]+1;
open[tag_open][3]=f(open[tag_open][0],open[tag_open][1],z1,z2);
tag_open++;
}
}
if(map[close[tag_close-1][0]-1][close[tag_close-1][1]]==255&&(close[tag_close-1][0]-1)>=0&&(close[tag_close-1][1])>=0)
{
for(int tag_a=0;tag_a<tag_open;tag_a++)
{
if((close[tag_close-1][0]-1)==open[tag_a][0]&&(close[tag_close-1][1])==open[tag_a][1])
{
//open[tag_a][2]=close[tag_close-1][2]+1;
keyy4=1;
break;
}
if(keyy4==0)
{
map_root[close[tag_close-1][0]-1][close[tag_close-1][1]][0]=close[tag_close-1][0];
map_root[close[tag_close-1][0]-1][close[tag_close-1][1]][1]=close[tag_close-1][1];
}
keyy4=0;
}
if(open[com[1]][3]==100000)
{
open[com[1]][0]=close[tag_close-1][0]-1;
open[com[1]][1]=close[tag_close-1][1];
open[com[1]][2]=close[tag_close-1][2]+1;
open[com[1]][3]=f(open[tag_open][0],open[tag_open][1],z1,z2);
}
else
{
open[tag_open][0]=close[tag_close-1][0]-1;
open[tag_open][1]=close[tag_close-1][1];
open[tag_open][2]=close[tag_close-1][2]+1;
open[tag_open][3]=f(open[tag_open][0],open[tag_open][1],z1,z2);
tag_open++;
}
}
com[0]=10000;
com[1]=0;
//找出代价最小的open点
for(int tag_a=0;tag_a<tag_open;tag_a++)
{
if((open[tag_a][2]+open[tag_a][3])<com[0])
{
com[1]=tag_a;
com[0]=open[tag_a][2]+open[tag_a][3];
}
}
//放到close表
close[tag_close][0]=open[com[1]][0];
close[tag_close][1]=open[com[1]][1];
//map_root[close[tag_close][0]][close[tag_close][1]][0]=close[tag_close-1][0];
//map_root[close[tag_close][0]][close[tag_close][1]][1]=close[tag_close-1][1];
//close走过的点涂黑
map[close[tag_close-1][0]][close[tag_close-1][1]]=0;
//重置比较位
open[com[1]][3]=100000;
tag_close++;
//printf("\n %d %d\n",close[tag_close-1][0],close[tag_close-1][1]);
//waitKey(5);
if(map[z1][z2]==0)break;
}
}
int f(int x1,int x2,int z1,int z2)
{
return abs(x1-z1)+abs(x2-z2);
}
Mat pool_max(Mat image_source, int size)
{
int rows = image_source.rows;
int cols = image_source.cols;
int tag_x=0,tag_y=0,tag1=0,tag2=0;
int tag3[3]={0,0,0};
Mat image_new(image_source.rows/size,image_source.cols/size,CV_8UC1);
while(tag_x>=0&&tag_x<=rows-size)//欠调
{
while(tag_y>=0&&tag_y<=cols-size)
{
while(tag1>=0&&tag1<=size)
{
while(tag2>=0&&tag2<=size)
{
if(image_source.at<uchar>(tag_x+tag1,tag_y+tag2)>tag3[1])(tag3[1]=image_source.at<uchar>(tag_x+tag1,tag_y+tag2));
tag2++;
}
tag1++;
tag2=0;
}
image_new.at<uchar>(tag_x/size,tag_y/size)=tag3[1];
tag3[1]=0;
tag_y+=size;tag1=0;tag2=0;
}
tag_x+=size;
tag_y=0;tag1=0;tag2=0;
}
return image_new;
}
Mat pool_min(Mat image_source, int size)
{
int rows = image_source.rows;
int cols = image_source.cols;
int tag_x=0,tag_y=0,tag1=0,tag2=0;
int tag3[3]={0,0,0};
Mat image_new(image_source.rows/size,image_source.cols/size,CV_8UC1);
while(tag_x>=0&&tag_x<=rows-size)//欠调
{
while(tag_y>=0&&tag_y<=cols-size-1)
{
while(tag1>=0&&tag1<=size)
{
while(tag2>=0&&tag2<=size)
{
if(image_source.at<uchar>(tag_x+tag1,tag_y+tag2)<tag3[1])(tag3[1]=image_source.at<uchar>(tag_x+tag1,tag_y+tag2));
tag2++;
}
tag1++;
tag2=0;
}
image_new.at<uchar>(tag_x/size,tag_y/size)=tag3[1];
tag3[1]=255;
tag_y+=size;tag1=0;tag2=0;
}
tag_x+=size;
tag_y=0;tag1=0;tag2=0;
}
return image_new;
}
cpp
#include"map.hpp"
int main()
{
A a;
a.deal_image();
a.find_ori();
a.deal_A();
a.draw_road();
}
备注
本文旨在展示A*效果,所以在鲁棒性方面没有做太多研究,图片数据来源http://mazegenerator.net/
参数如下
效果:
代码中可以自动保存视频,这里放了一张最后的截图
这边opencv出现越界情况不报错,其他设备运行可能会碰到越界之类的问题,欢迎评论指正