不变矩介绍:
先看教课书上的公式:
再看网上很认真的论文:
最后看冈萨雷斯的:
Hu矩5,7的公式有争议,我采用数字图像处理冈萨雷斯三版的公式,不过,感到还是不满意,有问题。
我们获取轮廓的特征,在此主要考察Hu矩1,2,3,4,6五个公式就够用了。我们前面演示已经说明问题。
需要说明的是,我们程序中,Hu矩5和Hu矩6顺序对调了一下。
实现Hu矩的c#代码:
// List<Point> singlefigure = null;//大斑轮廓
//tempbuffer8//截取的roi图像
// _RoiW//截取的roi图像的宽度
int mass = 0;
for (int m = 0; m < singlefigure.Count; m++)
{
int nn = singlefigure[m].Y * _RoiW + singlefigure[m].X;
int grayValue = tempbuffer8[nn];
mass += grayValue;
}
int xAver = 0, xSum = 0;
int yAver = 0, ySum = 0;
for (int m = 0; m < singlefigure.Count; m++)
{
int nn = singlefigure[m].Y * _RoiW + singlefigure[m].X;
int xGrayValue = singlefigure[m].X * tempbuffer8[nn];
xSum += xGrayValue;
}
for (int m = 0; m < singlefigure.Count; m++)
{
int nn = singlefigure[m].Y * _RoiW + singlefigure[m].X;
int yGrayValue = singlefigure[m].Y * tempbuffer8[nn];
ySum += yGrayValue;
}
xAver = xSum / mass;
yAver = ySum / mass;
//计算P+Q阶归一化中心矩
double n11 = 0, n20 = 0, n02 = 0, n12 = 0, n21 = 0, n03 = 0, n30 = 0;
for (int m = 0; m < singlefigure.Count; m++)
{
double xCha = singlefigure[m].X - xAver;
double yCha = singlefigure[m].Y - yAver;
int nn = singlefigure[m].Y * _RoiW + singlefigure[m].X;
n11 += xCha * yCha * tempbuffer8[nn] / Math.Pow(mass, 2);
n20 += Math.Pow(xCha, 2) * tempbuffer8[nn] / Math.Pow(mass, 2);
n02 += Math.Pow(yCha, 2) * tempbuffer8[nn] / Math.Pow(mass, 2);
n12 += Math.Pow(yCha, 2) * xCha * tempbuffer8[nn] / Math.Pow(mass, 2.5);
n21 += Math.Pow(xCha, 2) * yCha * tempbuffer8[nn] / Math.Pow(mass, 2.5);
// n30 += Math.Pow(xCha, 3) * yCha * tempbuffer8[nn] / Math.Pow(mass, 2.5);
n30 += Math.Pow(xCha, 3) * tempbuffer8[nn] / Math.Pow(mass, 2.5);//更正两个错误,稳定性变好202010232134
//n03 += Math.Pow(yCha, 2) * xCha * tempbuffer8[nn] / Math.Pow(mass, 2.5);
n03 += Math.Pow(yCha, 3) * tempbuffer8[nn] / Math.Pow(mass, 2.5);
}
//计算7个不变矩//顺序更换为1234657
double[] hu = new double[7];
hu[0] = n20 + n02;
hu[1] = Math.Pow((n20 - n02), 2) + 4 * n11 * n11;
hu[2] = Math.Pow((n30 - 3 * n12), 2) + Math.Pow((n03-3 * n21 ), 2);//3
hu[3] = Math.Pow((n30 + n12), 2) + Math.Pow((n21 + n03), 2);//4
hu[4] = (n20 - n02) * (Math.Pow((n30 + n12), 2) - Math.Pow((n21 + n03), 2)) + 4 * n11 * (n30 + n12) * (n21 + n03);//6
//下面用冈萨雷斯三版公式,有争议20201024
hu[5] = (n30 - 3 * n12) * (n30 + n12) * (Math.Pow((n30 + n12), 2) - 3 * Math.Pow((n21 + n03), 2))
+ (3 * n21 - n03) * (n21 + n03) * (3 * Math.Pow((n30 + n12), 2) - Math.Pow((n21 + n03), 2));//5
hu[6] = (3 * n21 - n03) * (n30 + n12) * ((Math.Pow((n30 + n12), 2)) - 3 * Math.Pow((n21 + n03), 2))
+ (3 * n12 - n30) * (n03 + n21) * ((3 * Math.Pow((n30 + n12), 2)) - Math.Pow((n21 + n03), 2));//7
textBoxHu矩.Text = "";
textBoxHu矩.Text += hu[0].ToString() + ";Hu矩1\r\n";
textBoxHu矩.Text += hu[1].ToString() + ";Hu矩2\r\n";
textBoxHu矩.Text += hu[2].ToString() + ";Hu矩3\r\n";
textBoxHu矩.Text += hu[3].ToString() + ";Hu矩4\r\n";
textBoxHu矩.Text += hu[4].ToString() + ";Hu矩5\r\n";
textBoxHu矩.Text += hu[5].ToString() + ";Hu矩6\r\n";
textBoxHu矩.Text += hu[6].ToString() + ";Hu矩7\r\n";
ok,完成!
有谁能告诉我,这七个Hu矩公式为什么要这样设计?
我们当下使用轮廓(这里应感谢opencv的提醒),为了处理速度,这是一个极好的方法。
看到大多数都说图像求hu矩很稳定,我估计是静态图像的原因,如果是实时图像,会这么好吗?
下结论太早,可以一试!