经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门书籍《OpenCV 4开发详解》。为了更让小伙伴更早的了解最新版的OpenCV 4,小白与出版社沟通,提前在公众号上连载部分内容,请持续关注小白。 |
矩是描述图像特征的算子,被广泛用于图像检索和识别、图像匹配、图像重建、图像压缩以及运动图像序列分析等领域。本节中将介绍几何矩与Hu矩的计算方法以及应用Hu矩实现图像轮廓的匹配。
几何矩与中心矩
图像几何矩的计算方式如式(7.8)所示:
m j i = ∑ x , y I ( x , y ) ∗ x j ∗ y i (7.8) {m_{ji}} = \sum\limits_{x,y} {I(x,y) * {x^j} * {y^i}} \tag{7.8} mji=x,y∑I(x,y)∗xj∗yi(7.8)
其中 I ( x , y ) I(x,y) I(x,y)是像素 ( x , y ) (x,y) (x,y)处的像素值。 当x和y同时取值0时称为零阶矩,零阶矩可以用于计算某个形状的质心,当x和y分别取值0和1时被称为一阶矩,以此类推。图像质心的计算公式如所示:
x ˉ = m 10 m 00 , y ˉ = m 01 m 00 (7.9) \bar x = \frac{
{
{m_{10}}}}{
{
{m_{00}}}},\bar y = \frac{
{
{m_{01}}}}{
{
{m_{00}}}} \tag{7.9} xˉ=m00m10,yˉ=m00m01(7.9)
图像中心距计算方式如式(7.10)所示:
m u j i = ∑ x , y I ( x , y ) ∗ ( x − x ˉ ) j ∗ ( y − y ˉ ) i (10) m{u_{ji}} = \sum\limits_{x,y} {I(x,y) * {
{(x - \bar x)}^j} * {
{(y - \bar y)}^i}} \tag{10} muji=x,y∑I(x,y)∗(x−xˉ)j∗(y−yˉ)i(10)
图像归一化几何矩计算方式如式所示:
n u j i = m u j i m 00 ( i + j ) / ( i + j ) 2 2 + 1 (7.11) n{u_{ji}} = \frac{
{m{u_{ji}}}}{
{m_{00}^{
{
{(i + j)} \mathord{\left/ {\vphantom {
{(i + j)} 2}} \right.} 2} + 1}}} \tag{7.11} nuji=m00(i+j)/(i+j)22+1muji(7.11)
OpenCV 4提供了计算图像矩的moments()函数,该函数的函数原型在代码清单7-28中给出。
代码清单7-28 moments()函数原型
1. Moments cv::moments(InputArray array,
2. bool binaryImage = false
3. )
- array:计算矩的区域2D像素坐标集合或者单通道的CV_8U图像
- binaryImage:是否将所有非0像素值视为1的标志。
该函数用于计算图像连通域的几何矩和中心距以及归一化的几何矩。函数第一个参数是待计算矩的输入图像或者2D坐标集合。函数第二个参数为是否将所有非0像素值视为1的标志,该标志只在第一个参数输入为图像类型的数据时才会有作用。函数会返回一个Moments类的变量,Moments类中含有几何矩、中心距以及归一化的几何矩的数值属性,例如Moments.m00是零阶矩,Moments.m01和Moments.m10是一阶矩。Moments类中所有的属性在表7-5给出。
种类 | 属性 |
---|---|
spatial moments | m00、m10、m01、m20、m11、m02、m30、m21、m12、m03 |
central moments | mu20、mu11、mu02、mu30、mu21、mu12、mu03 |
central normalized moments | nu20、nu11、nu02、nu30、nu21、nu12、nu03 |
为了了解函数的使用方法,在代码清单7-29中给出了计算图像矩和读取每一种矩数值方法的示例程序,程序的部分运行结果如图7-24所示。
代码清单7-29 myMoments.cpp计算图像的矩
4. #include <opencv2/opencv.hpp>
5. #include <iostream>
6. #include <vector>
7.
8. using namespace cv;
9. using namespace std;
10.
11. int main()
12. {
13. system("color F0"); //更改输出界面颜色
14. Mat img = imread("approx.png");
15. if (img.empty())
16. {
17. cout << "请确认图像文件名称是否正确" << endl;
18. return -1;
19. }
20.
21. // 二值化
22. Mat gray, binary;
23. cvtColor(img, gray, COLOR_BGR2GRAY);
24. threshold(gray, binary, 105, 255, THRESH_BINARY