关于DTW算法的原理这篇博客写的很好https://blog.csdn.net/aa8568849/article/details/53841189?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.nonecase
作者对原文的c程序进行注释和改进如下:
#include "stdio.h"
#include "windows.h"
struct pointOritation//保存当前节点方向,用来回溯每个W点
{
int frontI,frontJ;
};
/*求最小累计距离的二维数组g,
传入参数p为标准模板和测试模板各元素之间的欧氏距的二维数组的首地址
n,m为数组的行数和列数
g为所求最小累积距离数组的首地址
pr为保存g各个元素方向的结构体数组的首地址 */
void gArray(int *p,int n,int m,int *g,struct pointOritation *pr)
{
//定义行标和列标变量i,j
int i, j;
*(g+(n-1)*m)=(*(p+(n-1)*m))*2; //计算g起始点的值及其上个节点的行标和列标(最左下角的点)即g[5][0]
(pr+(n-1)*m)->frontI = -1;
(pr+(n-1)*m)->frontJ = -1;
for (i=1; i<m; i++)//循环m-1次计算g最下面一横的值,(除g[5][0])(只有一个方向)
{
*(g+(n-1)*m+i)=*(g+(n-1)*m+i-1)+*(p+(n-1)*m+i); //求值
(pr+(n-1)*m+i)->frontI=n-1; // 求当前节点的最小累计距离的方向
(pr+(n-1)*m+i)->frontJ=i-1; //保存方法为保存当前节点的上个节点的数组下标
// frontI为行标,frontJ为列标
}
for (i=n-2; i>=0; i--)//循环n-1次最左边的一竖的值, (除g[5][0])(只有一个方向)
{
*(g+i*m)=*(g+(i+1)*m)+*(p+i*m);
(pr+i*m)->frontI=i+1;
(pr+i*m)->frontJ=0;
}
//计算剩余网格的G值 i为行标,j为列标
for (i=n-2; i>=0; i--)
{
for (j=1; j<m; j++)
{
int left,under,incline; //分别表示当前节点三个方向上的累计距离值
left=*(g+i*m+j-1)+*(p+i*m+j);
under=*(g+(i+1)*m+j)+*(p+i*m+j);
incline=*(g+(i+1)*m+j-1)+(*(p+i*m+j))*2;
//从左、下、斜三个方向选出最小的
int min=left;
*(g+i*m+j)=min;
(pr+i*m+j)->frontI=i;
(pr+i*m+j)->frontJ=j-1;
if (min>under)
{
min=under;
*(g+i*m+j)=min;
(pr+i*m+j)->frontI=i+1;
(pr+i*m+j)->frontJ=j;
}
if (min>incline)
{
min=incline;
*(g+i*m+j)=min;
(pr+i*m+j)->frontI=i+1;
(pr+i*m+j)->frontJ=j-1;
}
}
}
//输出G数组
printf("g矩阵如下:\n");
for (i=0; i<n; i++)
{
for (j=0; j<m; j++)
{
printf("%d\t",*(g+i*m+j));
}
printf("\n");
}
//输出方向数组
printf("方向矩阵如下:\n");
for (i=0; i<n; i++)
{
for (j=0; j<m; j++)
{
printf("(%d,%d)\t",(pr+i*m+j)->frontI,(pr+i*m+j)->frontJ);
}
printf("\n");
}
}
void printPath(struct pointOritation *po,int n,int m,int *g)
{
//由于最短路径是从终点回溯找到起点,所以这里利用一个结构体数组实现正序输出路径
struct temp_save{
int i, j, distance;
};
struct temp_save temp[10];
int t = 0;
printf("路径如下:\n");
int i=0,j=m-1;
while (1)
{
int ii=(po+i*m+j)->frontI,jj=(po+i*m+j)->frontJ;
temp[t].i = i;
temp[t].j = j;
temp[t].distance = *(g+i*m+j);
t++;
i=ii;
j=jj;
if(i==-1 && j==-1)
break;
}
t--;
while(t>=0){
printf("(%d, %d): 当前最小累积距离: %d\n", temp[t].i, temp[t].j, temp[t].distance);
t--;
}
printf("标准模板与匹配模板的最小累积距离=%d\n", temp[t+1].distance);
}
int main()
{
//标准模板和匹配模板各元素之间的欧氏距离矩阵
int d[6][4]={
{2,1,7,5},
{1,5,1,6},
{4,7,2,4},
{5,2,4,3},
{3,4,8,2},
{2,1,5,1},
};
//存放累积最小距离的矩阵g
int g[6][4];
struct pointOritation pOritation[6][4];//用来存放g中当前节点的来源路径的结构体数组
//求出g和pOritation并打印
gArray(*d,6,4,*g,*pOritation);
//打印路径即标准模板和匹配模板之间各元素的映射关系
printPath(*pOritation, 6, 4,*g);
system("pause");
return 0;
}
运行结果如下: