// Catalano Imaging Library
// The Catalano Framework
//
// Copyright © Diego Catalano, 2012-2016
// diego.catalano at live.com
//
// Copyright © Asad Ali
// asad_82 at yahoo.com
//
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
package Catalano.Imaging.Tools;
import Catalano.Core.DoublePoint;
import Catalano.Imaging.FastBitmap;
/**
* Combined Blur and Affine Moment Invariants.
* Paper: "Combined blur and affine moment invariants and their use in pattern recognition. Tomas Suk, Jan Flusser"
* Link: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.85.7431&rep=rep1&type=pdf
* @author Diego Catalano
*/
public class SukFlusserMoments {
private boolean normalize;
/**
* Check if the moments are normalized.
* @return True if the moments are normalized, otherwise false.
*/
public boolean isNormalize() {
return normalize;
}
/**
* Set if the moments needs to be normalized by log.
* @param normalize Normalize.
*/
public void setNormalize(boolean normalize) {
this.normalize = normalize;
}
/**
* Initialize a new instance of the SukFlusserMoments class.
*/
public SukFlusserMoments() {
this(false);
}
/**
* Initialize a new instance of the SukFlusserMoments class.
* @param normalize Normalize by log scale.
*/
public SukFlusserMoments(boolean normalize) {
this.normalize = normalize;
}
/**
* Compute Blur and Affine moment invariants.
* @param fastBitmap Image to be processed.
* @return 6 Moments.
*/
public double[] Compute(FastBitmap fastBitmap){
if(fastBitmap.isGrayscale()){
double m00 = ImageMoments.getRawMoment(fastBitmap, 0, 0);
DoublePoint centroid = ImageMoments.getCentroid(fastBitmap, m00);
// Second order central moments
double m20 = ImageMoments.getCentralMoment(fastBitmap, 2, 0, centroid);
double m02 = ImageMoments.getCentralMoment(fastBitmap, 0, 2, centroid);
double m11 = ImageMoments.getCentralMoment(fastBitmap, 1, 1, centroid);
// Third order central moments
double m30 = ImageMoments.getCentralMoment(fastBitmap, 3, 0, centroid);
double m03 = ImageMoments.getCentralMoment(fastBitmap, 0, 3, centroid);
double m21 = ImageMoments.getCentralMoment(fastBitmap, 2, 1, centroid);
double m12 = ImageMoments.getCentralMoment(fastBitmap, 1, 2, centroid);
// Fouth order central moments
double m40 = ImageMoments.getCentralMoment(fastBitmap, 4, 0, centroid);
double m04 = ImageMoments.getCentralMoment(fastBitmap, 0, 4, centroid);
double m31 = ImageMoments.getCentralMoment(fastBitmap, 3, 1, centroid);
double m13 = ImageMoments.getCentralMoment(fastBitmap, 1, 3, centroid);
double m22 = ImageMoments.getCentralMoment(fastBitmap, 2, 2, centroid);
// Fifth order central moments
double m50 = ImageMoments.getCentralMoment(fastBitmap, 5, 0, centroid);
double m05 = ImageMoments.getCentralMoment(fastBitmap, 0, 5, centroid);
double m41 = ImageMoments.getCentralMoment(fastBitmap, 4, 1, centroid);
double m14 = ImageMoments.getCentralMoment(fastBitmap, 1, 4, centroid);
double m32 = ImageMoments.getCentralMoment(fastBitmap, 3, 2, centroid);
double m23 = ImageMoments.getCentralMoment(fastBitmap, 2, 3, centroid);
// Seventh order central moments
double m70 = ImageMoments.getCentralMoment(fastBitmap, 7, 0, centroid);
double m07 = ImageMoments.getCentralMoment(fastBitmap, 0, 7, centroid);
double m16 = ImageMoments.getCentralMoment(fastBitmap, 1, 6, centroid);
double m61 = ImageMoments.getCentralMoment(fastBitmap, 6, 1, centroid);
double m52 = ImageMoments.getCentralMoment(fastBitmap, 5, 2, centroid);
double m25 = ImageMoments.getCentralMoment(fastBitmap, 2, 5, centroid);
double m43 = ImageMoments.getCentralMoment(fastBitmap, 4, 3, centroid);
double m34 = ImageMoments.getCentralMoment(fastBitmap, 3, 4, centroid);
// For blur invariance we recompute certain values
m50 = m50 - (10*m30*m20/m00);
m41 = m41 - (2*(3*m21*m20 + 2*m30*m11)/m00);
m32 = m32 - ((3*m12*m20 + m30*m02 + 6*m21*m11)/m00);
m23 = m23 - ((3*m21*m02 + m03*m20 + 6*m12*m11)/m00);
m14 = m14 - (2*(3*m12*m02 + 2*m03*m11)/m00);
m05 = m05 - (10*m03*m02/m00);
// For blur invariance seventh order moments recomputed
m70 = m70 - 7 * (3*m50*m20 + 5*m30*m40)/m00 + (210*m30*(m20*m20) / (m00*m00));
m61 = m61 - (6*m50*m11 + 15*m41*m20 + 15*m40*m21 + 20*m31*m30)/m00 +
30*(3*m21*(m20*m20) + 4*m30*m20*m11)/(m00*m00);
m52 = m52 - (m50*m02 +10*m30*m22 + 10*m32*m20 + 20*m31*m21 +10*m41*m11 + 5*m40*m12)/m00 +
10* (3*m12*(m20*m20) + 2*m30*m20*m02 + 4*m30*(m11*m11) + 12*m21*m20*m11)/(m00*m00);
m43 = m43 - (m40*m03 + 18*m21*m22 + 12*m31*m12 + 4*m30*m13 + 3*m41*m02 + 12*m32*m11 +
6*m23*m20)/m00 + 6*(m03*(m20*m20) + 4*m30*m11*m02 + 12*m21*(m11*m11) + 12*m12*m20*m11 + 6*m21*m02*m20);
m34 = m34 - (m04*m30 + 18*m12*m22 + 12*m13*m21 + 4*m03*m31 + 3*m14*m20 + 12*m23*m11
+ 6*m32*m02)/m00 + 6 *(m30*(m02*m02) + 4*m03*m11*m20 + 12*m12*(m11*m11) + 12*m21*m02*m11 +
6*m12*m20*m02)/(m00*m00);
m25 = m25 - (m05*m20 + 10*m03*m22 + 10*m23*m02 + 20*m13*m12 + 10*m14*m11 + 5*m04*m21)/m00 +
10*(3*m21*(m02*m02) + 2*m03*m02*m20 +4*m03*(m11*m11) + 12*m12*m02*m11)/(m00*m00);
m16 = m16 - (6*m05*m11 + 15*m14*m02 + 15*m04*m12 + 20*m13*m03)/m00 + 30*(3*m12*(m02*m02) +
4*m03*m02*m11)/(m00*m00);
m07 = m07 - 7*(3*m05*m02 + 5*m03*m04)/m00 + (210*m03*(m02*m02) / (m00*m00));
//First invariant computed from the determinant of the polynomial
double I1 = ((m30*m30)*(m03*m03) - 6*m30*m21*m12*m03 + 4*m30*(m12*m12*m12) +
4*(m21*m21*m21)*m03 - 3*(m21*m21)*(m12*m12)) / Math.pow(m00, 10);
double I2 = ((m50*m50)*(m05*m05) - 10*m50*m41*m14*m05 + 4*m50*m32*m23*m05 +
16*m50*m32*(m14*m14) - 12*m50*(m23*m23)*m14 + 16*(m41*m41)*m23*m05 +
9*(m41*m41)*(m14*m14) - 12*m41*(m32*m32)*m05 - 76*m41*m32*m23*m14 +
48*m41*(m23*m23*m23) + 48*(m32*m32*m32)*m14 - 32*(m32*m32)*(m23*m23))/Math.pow(m00, 14);
double I3 = ((m30*m30)*m12*m05 - (m30*m30)*m03*m14 - m30*(m21*m21)*m05 - 2*m30*m21*m12*m14 +
4*m30*m21*m03*m23 + 2*m30*(m12*m12)*m23 - 4*m30*m12*m03*m32 +
m30*(m03*m03)*m41 + 3*(m21*m21*m21)*m14 - 6*(m21*m21)*m12*m23 - 2*(m21*m21)*m03*m32 +
6*m21*(m12*m12)*m32 + 2*m21*m12*m03*m41 - m21*(m03*m03)*m50 - 3*(m12*m12*m12)*m41 +
(m12*m12)*m03*m50) / Math.pow(m00, 11);
double I4 = (2*m30*m12*m41*m05 - 8*m30*m12*m32*m14 + 6*m30*m12*(m23*m23) -
m30*m03*m50*m05 + 3*m30*m03*m41*m14 - 2*m30*m03*m32*m23 -
2*(m21*m21)*m41*m05 + 8*(m21*m21)*m32*m14 - 6*(m21*m21)*(m23*m23) +
m21*m12*m50*m05 - 3*m21*m12*m41*m14 + 2*m21*m12*m32*m23 +
2*m21*m03*m50*m14 - 8*m21*m03*m41*m23 + 6*m21*m03*(m32*m32) -
2*(m12*m12)*m50*m14 + 8*(m12*m12)*m41*m23 - 6*(m12*m12)*(m32*m32))/Math.pow(m00, 12);
double I5 = (m30*m41*m23*m05 - m30*m41*(m14*m14) - m30*(m32*m32)*m05 + 2*m30*m32*m23*m14 -
m30*(m23*m23*m23) - m21*m50*m23*m05 + m21*m50*(m14*m14) + m21*m41*m32*m05 -
m21*m41*m23*m14 - m21*(m32*m32)*m14 + m21*m32*(m23*m23) + m12*m50*m32*m05 -
m12*m50*m23*m14 - m12*(m41*m41)*m05 + m12*m41*m32*m14 + m12*m41*(m23*m23) -
m12*(m32*m32)*m23 - m03*m50*m32*m14 + m03*m50*(m23*m23) +
m03*(m41*m41)*m14 - 2*m03*m41*m32*m23 + m03*(m32*m32*m32))/Math.pow(m00, 13);
double I6 = ((m70*m70)*(m07*m07) - 14*m70*m61*m16*m07 + 18*m70*m52*m25*m07 + 24*m70*m52*(m16*m16) -
10*m70*m43*m34*m07 - 60*m70*m43*m25*m16 + 40*m70*(m34*m34)*m16 + 24*(m61*m61)*m25*m07 +
25*(m61*m61)*(m16*m16) - 60*m61*m52*m34*m07 - 234*m61*m52*m25*m16 + 40*m61*(m43*m43)*m07 +
50*m61*m43*m34*m16 + 360*m61*m43*(m25*m25) - 240*m61*(m34*m34)*m25 + 360*(m52*m52)*m34*m16 +
81*(m52*m52)*(m25*m25) - 240*m52*(m43*m43)*m16 - 990*m52*m43*m34*m25 + 600*m52*(m34*m34*m34) +
600*(m43*m43*m43)*m25 - 375*(m43*m43)*(m34*m34))/Math.pow(m00, 18);
double[] moments = new double[6];
moments[0] = I1;
moments[1] = I2;
moments[2] = I3;
moments[3] = I4;
moments[4] = I5;
moments[5] = I6;
//Normalize by log
if(normalize){
for (int i = 0; i < moments.length; i++) {
moments[i] = Math.signum(moments[i]) * Math.log10(Math.abs(moments[i]) + 1);
}
}
return moments;
}
else{
throw new IllegalArgumentException("Suk Flusser Moments only works with grayscale images.");
}
}
}
Ads help maintain this website.