Ask Your Question
0

What does HuMoments tell me?

asked 2015-10-27 10:26:14 -0600

vitruvius gravatar image

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:

image description

Contours with mass center: image description

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 ...
(more)
edit retag flag offensive close merge delete

Comments

1

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 gravatar imageLBerger ( 2015-10-27 15:24:06 -0600 )edit

@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

vitruvius gravatar imagevitruvius ( 2015-10-27 16:39:56 -0600 )edit
1

take a look at this tutorial

sturkmen gravatar imagesturkmen ( 2015-10-27 16:49:06 -0600 )edit

Can you check that all shapes are similar ?

LBerger gravatar imageLBerger ( 2015-10-28 12:03:35 -0600 )edit

@vitruvius In your stackoverflow post your program is false. Here it's better to write like this

for (int i = 0; i < contours.size(); i++)
{
    cout << "Contour: " << i << " Area: " << contourArea(contours[i]) << " Length: " << arcLength(contours[i], true) << "\n";

    HuMoments(mu[i], hu);
    for (int j = 0; j < 7; j++)
    {
        cout << "Contour: " << i << " Hu: " << j << " Result: " << hu[j] << "\n";
    }
    cout << "\n";
}

Not only Hu moment 0 is invariant the other hu moment too.

LBerger gravatar imageLBerger ( 2015-10-28 12:31:05 -0600 )edit

1 answer

Sort by ยป oldest newest most voted
0

answered 2015-10-29 09:55:13 -0600

i think you are trying to implement something like cv::matchShapes take a look at the source

edit flag offensive delete link more

Comments

I just want to understand what they tell me about an object. Do I really need all seven Hu invariants for comparing objects? What I am looking for as an answer is not some code but some explanation.

vitruvius gravatar imagevitruvius ( 2015-10-29 17:37:41 -0600 )edit

Question Tools

1 follower

Stats

Asked: 2015-10-27 10:26:14 -0600

Seen: 4,866 times

Last updated: Oct 29 '15