Calculating Hu moments using OpenCV from Icy

Hi,

I think I need some help calculating Hu moments in Icy using the bridge to OpenCV. I am using the script at the end of this post. While testing the code I realized that the moments changed value when the input image is rotated. So I calculated the moments using the OpenCV bindings of python. Here all seems fine: upon rotation the values change only slightly. The first two moments are actually (almost) the same in all cases.
I also attach the two test images (they are from this blog post which got me started).

So, I think I am missing something in my script when transferring the image to the OpenCV plugin.

Thanks for any help or hint,
Ekkehard

The Icy script (the result is the same even without the type conversion of the Mat objects) :

importClass(Packages.plugins.adufour.opencv.OpenCV)
importClass(Packages.icy.main.Icy)
importClass(Packages.org.opencv.imgproc.Imgproc)
importClass(Packages.org.opencv.core.Mat)
importClass(Packages.org.opencv.core.CvType)
importClass(Packages.icy.sequence.Sequence)

OpenCV.initialize();

img = Icy.getMainInterface().getActiveImage()
mat = OpenCV.convertToOpenCV(img)

dmat = Mat(mat.rows(), mat.cols(),  CvType.CV_32FC1)
mat.convertTo(dmat, CvType.CV_32FC1)
tmat = new Mat()

m = Imgproc.threshold(dmat, tmat,  128, 1, Imgproc.THRESH_BINARY)

moments = Imgproc.moments(tmat, false)

hmoments = new Mat()

Imgproc.HuMoments(moments, hmoments)

im = OpenCV.convertToIcy(hmoments)

for (i=0;i<7;i++) {
	hm= im.getDataAsDouble(0, i, 0)
	println("hm "+i+": "+hm)
}

K0 K0r

Dear Gucki,
I am inviting Alexandre Dufour @drdaleks the developer of the OpenCV plugin in Icy to join this discussion, hoping he can help you on this one.
Best regards,
Marion

Hi,

I just did two more tests:

  • I saved the “K” image with openCVs imwrite instead of calculating the moments. The difference to the original is zero
  • I loaded the image with openCVs imread instead of getting it from a sequence and got the same result.

So, it seems that the conversion from sequence to Mat is not contributing to my difficulty.

Best regards,
Ekkehard

Hi,

I think I found it: four of the spacial moments returned in the Imgproc.moments call are truncated to 2^31 - 1:

m00 3529
m10 426610
m01 455203
m20 53305780
m11 55283967
m02 62147805
m30 2147483647
m21 2147483647
m12 2147483647
m03 2147483647

The other values are exactly the same compared to the results from the python interface to openCV. In the script window itself one can handle larger values:

largeNumber = 4294967296.0
println("Large " + largeNumber)

yields the expected “Large 4294967296”. Probably somewhere on the way from openCV to the script environment the truncation happens.

Best,
Ekkehard

Hi,

after diving a bit deeper I saw that not the core of openCV, not the bridge to Icy but the java wrapper of the openCV library itself in version 3.1.0 is the culprit.

In a separate Rhino environment I used the script below for testing. I always used the opencv_java310.dll (x86) and only exchanged the openCV jar version between 3.1.0 and 4.3.0. The latter gave the “correct” results but the former showed truncation in the spacial moments and the wrong results.

Just for a test I then replaced the opencv jar content in the Icy plugin and received the desired results. This hack is of course no solution but an upgrade of the OpenCV version in the plugin will probably solve it. Not sure how difficult that is.

Best ,
Ekkehard

java.lang.System.loadLibrary("opencv_java310");
importClass(Packages.org.opencv.imgcodecs.Imgcodecs);
importClass(Packages.org.opencv.imgproc.Imgproc)
importClass(Packages.org.opencv.core.Mat)
importClass(Packages.org.opencv.core.CvType)


mat = Imgcodecs.imread("c:/Data/Imaging/test/K0.png", Imgcodecs.IMREAD_GRAYSCALE)

m = Imgproc.threshold(mat, mat,  128, 1, Imgproc.THRESH_BINARY)

moments = Imgproc.moments(mat, false)

print("m30 " + moments.get_m30())

hmoments = new Mat()
Imgproc.HuMoments(moments, hmoments)

hmoments.convertTo(hmoments, CvType.CV_64FC3);

hm  = java.lang.reflect.Array.newInstance(java.lang.Double, 7);

for (i=0;i<7;i++) {
	hm= hmoments.get(i,0)[0]
	print("hm "+i+": "+hm)
}
2 Likes

Dear Gucki,

Thank you for your feedbacks on the OpenCV plugin! I will transmit the upgrade request to the development team.

Best regards,
Marion

Dear Marion,

thank you so much!

Best regards,
Ekkehard

Just for information, the opencv bridge in imageJ/Fiji (IJ-OpenCV) uses opencv 3.4.2.
It’s not exactly the same library as it is going through javacpp, but having the same opencv version could help to limit the need to adapt the code between software :wink:

1 Like

Just checked: the opencv version 3.4.2 would solve the issue. This “milder” upgrade may also break less in existing code (if at all).

2 Likes

Hi,
as I am still interested in this topic: is there a possibility to upgrade this plugin by myself (e.g. from a GitHub repo or similar)? I have programmed in the java/Eclipse/Maven environment and I am happy to give it a try …

Ekkehard

Dear @Gucki,

Thank you for proposing your help on this topic.
We added the upgrade of OpenCV on our to do list and @Stephane and his apprentice Amandine started working on it.
Stephane can probably give you more technical details and possibly delegate some of the tasks or tests.

Best regards,
Marion

Dear @Gucki, @MarionLouveaux,

I just updated the OpenCV library to 3.4.2 in Icy, i had to changes some stuffs to make it work but it should be ok now.
Note that the plugin will be updated automatically when you will upgrade to the incoming Icy 2.1 as internally it uses some new Icy 2.1 methods (for native library loading).

Best,

– Stephane

2 Likes

Dear Stephane,

wonderful, thank you for this enhancement of Icy! I am looking forward to the new release.

Best,
Ekkehard