What does HuMoments tell me?
Hello,
I would like to compare two objects whether they are similar. So I read a lot about moments and HuMoments, but things are still not clear.
What do the seven Hu invariants say about the object? I read hu[0] is about length/area of the contour but what about the rest?
Also, the invariants are very very small numbers. Is this normal, or am I doing something wrong? How could I compare such small values?
Here, I have prepared an image where the length of the square and circle; and the area of the triangle and rectangle is the same. And indeed, hu[0] seems to be same.
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace cv;
using namespace std;
Mat src; Mat srcGray;
RNG rng(12345);
int main()
{
// Load source image and convert it to gray
src = imread("source3.png", 1);
// Convert image to gray and blur it
cvtColor(src, srcGray, CV_BGR2GRAY);
blur(srcGray, srcGray, Size(3, 3));
Mat srcThresh;
double otsu;
otsu = threshold(srcGray, srcThresh, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
Mat cannyOut;
Canny(srcGray, cannyOut, otsu, otsu * 1 / 2, 3, 1);
// Find contours
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours(cannyOut, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
// Get the moments
vector<Moments> mu(contours.size());
for (int i = 0; i < contours.size(); i++)
{
mu[i] = moments(contours[i], false);
}
// Get the mass centers:
vector<Point2f> mc(contours.size());
for (int i = 0; i < contours.size(); i++)
{
mc[i] = Point2f(mu[i].m10 / mu[i].m00, mu[i].m01 / mu[i].m00);
}
// Draw contours
Mat drawing = Mat::zeros(cannyOut.size(), CV_8UC3);
string sObjectNumber; // string which will contain the result
ostringstream sContourNumber; // stream used for the conversion
for (int i = 0; i< contours.size(); i++)
{
sContourNumber << i;
sObjectNumber = sContourNumber.str(); // Convert int to string
Point pCoordinates(mc[i].x + 3, mc[i].y - 3); // Text's coordinates (A little bit off from mass center)
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
drawContours(drawing, contours, i, color, 2, 8, hierarchy, 0, Point());
circle(drawing, mc[i], 4, color, -1, 8, 0); // Draw mass center
putText(drawing, sObjectNumber, pCoordinates, CV_FONT_HERSHEY_COMPLEX, 1, color, 2, 8); // Write object number
sContourNumber.str(""); // Clear string
sContourNumber.clear(); // Clear any error flags
}
double hu[7];
for (int i = 0; i < contours.size(); i++)
{
cout << "Contour: " << i << " Area: " << contourArea(contours[i]) << " Length: " << arcLength(contours[i], true) << "\n";
for (int j = 0; j < 7; j++)
{
HuMoments(mu[i], hu);
cout << "Contour: " << i << " Hu: " << j << " Result: " << hu[j] << "\n";
}
cout << "\n";
}
imshow("Contours", drawing);
waitKey(0);
return(0);
}
Source image:
Contours with mass center:
Console output:
Contour: 0 Area: 67074 Length: 1033.66
Contour: 0 Hu: 0 Result: 0.16665
Contour: 0 Hu: 1 Result: 5.22355e-011
Contour: 0 Hu: 2 Result: 4.22817e-010
Contour: 0 Hu: 3 Result: 4.4612e-011
Contour: 0 Hu: 4 Result: 6.12709e-021
Contour: 0 Hu: 5 Result: -3.2243e-016
Contour: 0 ...
You should read this first. After you chan check with your image. Scale or rotated your image and hu moments will not change. you can track 2d shape
@LBerger I read this also, but it is not easy to understand with only formulas. Anyways, as you said hu moments doesn't change for same object. But I have a "sign" problem with the last three hu invariants. I asked that in here
take a look at this tutorial
Can you check that all shapes are similar ?
@vitruvius In your stackoverflow post your program is false. Here it's better to write like this
Not only Hu moment 0 is invariant the other hu moment too.