/* * This file is part of Caliph & Emir. * * Caliph & Emir is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Caliph & Emir 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Caliph & Emir; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Copyright statement: * -------------------- * (c) 2005 by Werner Klieber (werner@klieber.info) * http://caliph-emir.sourceforge.net */ package at.wklieber.mpeg7; import java.awt.Point; import java.awt.geom.Point2D; import java.awt.image.BufferedImage; import java.awt.image.WritableRaster; import java.util.Comparator; import java.util.List; import java.util.Vector; import org.jdom.Element; import org.jdom.Namespace; import at.wklieber.tools.Console; import at.wklieber.tools.Java2dTools; class IndexCoords { int i; double x; double y; public IndexCoords() { reset(); } public void reset() { i = 0; x = 0; y = 0; } } class SortInd implements Comparator { public int compare(Object o1, Object o2) { //return (((const IndexCoords *)v1)->y <= ((const IndexCoords *)v2)->y) ? -1 : 1; IndexCoords v1 = (IndexCoords) o1; IndexCoords v2 = (IndexCoords) o2; return (v1.y <= v2.y ? -1 : 1); } } class Edge { int i; double x; double y; double dx; double dy; public Edge() { reset(); } public void reset() { i = 0; x = 0; y = 0; dx = 0; dy = 0; } } class SortEdge implements Comparator { public int compare(Object o1, Object o2) { //return (((const Edge *)v1)->x <= ((const Edge *)v2)->x ? -1 : 1); Edge v1 = (Edge) o1; Edge v2 = (Edge) o2; return (v1.x <= v2.x ? -1 : 1); } } public class ContourShape { private static Console console = Console.getReference(); private static Java2dTools java2dTools = Java2dTools.getReference(); static final boolean debug = true; private static int BITS_TO_MASK(int a) { return ((2 << ((a) - 1)) - 1); } private static long BITS_TO_MASK(long a) { return ((2 << ((a) - 1)) - 1); } private static double CONTOURSHAPE_YP = 0.05; private static double CONTOURSHAPE_AP = 0.09; private static int CONTOURSHAPE_MAXCSS = 10; private static double CONTOURSHAPE_T = 0.000001; private static double CONTOURSHAPE_TXA0 = 3.8; private static double CONTOURSHAPE_TXA1 = 0.6; private static int CONTOURSHAPE_CSSPEAKBITS = 6; private static int CONTOURSHAPE_XBITS = 6; private static long CONTOURSHAPE_YBITS = 7; private static int CONTOURSHAPE_YnBITS = 3; private static int CONTOURSHAPE_CBITS = 6; private static int CONTOURSHAPE_EBITS = 6; private static double CONTOURSHAPE_ETHR = 0.6; private static double CONTOURSHAPE_CTHR = 1.0; private static double CONTOURSHAPE_ECOST = 0.4; private static double CONTOURSHAPE_CCOST = 0.3; private static double CONTOURSHAPE_NMATCHPEAKS = 2; private static double CONTOURSHAPE_TMATCHPEAKS = 0.9; private static double CONTOURSHAPE_XMAX = 1.0; private static double CONTOURSHAPE_YMAX = 1.7; private static double CONTOURSHAPE_CMIN = 12.0; private static double CONTOURSHAPE_CMAX = 110.0; private static double CONTOURSHAPE_EMIN = 1.0; private static double CONTOURSHAPE_EMAX = 10.0; private static int CONTOURSHAPE_CSSPEAKMASK = BITS_TO_MASK(CONTOURSHAPE_CSSPEAKBITS); private static int CONTOURSHAPE_XMASK = BITS_TO_MASK(CONTOURSHAPE_XBITS); private static long CONTOURSHAPE_YMASK = BITS_TO_MASK(CONTOURSHAPE_YBITS); private static int CONTOURSHAPE_YnMASK = BITS_TO_MASK(CONTOURSHAPE_YnBITS); private static int CONTOURSHAPE_CMASK = BITS_TO_MASK(CONTOURSHAPE_CBITS); private static long CONTOURSHAPE_EMASK = BITS_TO_MASK(CONTOURSHAPE_EBITS); private BufferedImage img; private BufferedImage regionShapeImage; char m_cPeaksCount; // all unsigned long[] m_piGlobalCurvatureVector = new long[2]; long[] m_piPrototypeCurvatureVector = new long[2]; long m_iHighestPeakY; long[] m_pPeak; /** * Create a ColorLayout Object from the given BufferedImage with the desired number of Coefficients * * @param image the input image */ public ContourShape(BufferedImage image) { this.img = image; extract(img); init(); } /** * Create a ColorLayout Object from the given BufferedImage with the desired number of Coefficients * * @param pointList List of Point() */ public ContourShape(List pointList) { //this.img = image; init(); extract(pointList); } /** * Create a ColorLayout Object from its descriptor * * @param descriptor the descriptor as JDOM Element */ public ContourShape(Element descriptor) { this.img = null; } private void init() { regionShapeImage = null; //extract(); } public Element getDescriptor() { Element returnVaue = null; Namespace mpeg7, xsi; mpeg7 = Namespace.getNamespace("", "urn:mpeg:mpeg7:schema:2001"); xsi = Namespace.getNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance"); Element vdesc = new Element("VisualDescriptor", mpeg7).setAttribute("type", "ContourShapeType", xsi); int num = m_cPeaksCount; //getNoOfPeaks(); Element globalCurvatureElement = new Element("GlobalCurvature"); vdesc.addContent(globalCurvatureElement); long[] lgcv; //= new long[2]; lgcv = m_piGlobalCurvatureVector; //getGlobalCurvature(); //vector<int> gcv(2); //gcv[0] = (int)lgcv[0]; //gcv[1] = (int)lgcv[1]; String gcv = lgcv[0] + " " + lgcv[1]; globalCurvatureElement.setText(gcv); if (num > 0) { Element prototypeCurvatureElement = new Element("PrototypeCurvature"); vdesc.addContent(prototypeCurvatureElement); long[] lpcv = new long[2]; lpcv = m_piPrototypeCurvatureVector; //getPrototypeCurvature(lpcv[0], lpcv[1]); //vector<int> pcv(2); //pcv[0] = (int)lpcv[0]; //pcv[1] = (int)lpcv[1]; String pcv = lpcv[0] + " " + lpcv[1]; prototypeCurvatureElement.setText(pcv); } Element highestPeakElement = new Element("HighestPeakY"); vdesc.addContent(highestPeakElement); //getHighestPeakY() long peak = m_iHighestPeakY; highestPeakElement.setText("" + peak); for (int i = 1; i < num; i++) { //short xp, yp; Element peakElement = new Element("Peak"); long[] point = getPeak(i); String xp = "" + point[0]; String yp = "" + point[1]; peakElement.setAttribute("peakX", xp); peakElement.setAttribute("peakY", yp); } returnVaue = vdesc; return vdesc; } private int getNoOfPeaks() { return m_cPeaksCount; } private void setNoOfPeaks(int cPeaks) { int cOldPeaks = m_cPeaksCount; // Only 5 bits used so mask out rest if (cPeaks > CONTOURSHAPE_CSSPEAKMASK) m_cPeaksCount = (char) CONTOURSHAPE_CSSPEAKMASK; else m_cPeaksCount = (char) cPeaks; // Manage peak memory if (m_cPeaksCount == cOldPeaks) { //if (m_pPeak != null) { // m_pPeak = new short[0]; //} m_pPeak = null; if (m_cPeaksCount > 0) { m_pPeak = new long[m_cPeaksCount * 2]; } } else { //memset(m_pPeak, 0, m_cPeaksCount * sizeof(unsigned short) * 2); m_pPeak = new long[m_cPeaksCount * 2]; } } private long[] getGlobalCurvature() { return m_piGlobalCurvatureVector; } private void setGlobalCurvature(long lC, long lE) { m_piGlobalCurvatureVector[0] = lC; m_piGlobalCurvatureVector[1] = lE; } private long getHighestPeakY() { return m_iHighestPeakY; } private void setHighestPeakY(long iHigh) { m_iHighestPeakY = iHigh; } void setPrototypeCurvature(long lC, long lE) { if (m_cPeaksCount > 0) { m_piPrototypeCurvatureVector[0] = lC; m_piPrototypeCurvatureVector[1] = lE; } } private long[] getPeak(int cIndex) { int cOffset = (cIndex * 2); long[] returnValue = new long[2]; if (cIndex < m_cPeaksCount) { returnValue[0] = m_pPeak[cOffset]; returnValue[1] = m_pPeak[cOffset + 1]; } else { returnValue[0] = 0; returnValue[1] = 0; } return returnValue; } private void setPeak(int cIndex, long iX, long iY) { int cOffset = cIndex * 2; if (cIndex < m_cPeaksCount) { m_pPeak[cOffset] = iX; m_pPeak[cOffset + 1] = iY; } } /** * extract the shape from an image with white background and black shape * * @param image */ public void extract(BufferedImage image) { throw new java.lang.UnsupportedOperationException("Method extract(BufferedImage) not yet implemented."); //long something = ExtractContour(10, new Point()); // todo: call ExtractContor and next extract(List) //int nContour = ExtractContour(CONTOUR_SIZE, coords); } /** * extract the descrptor data * * @param pointList List of Point() */ public void extract(List pointList) { //throw new java.lang.UnsupportedOperationException("Method extract(BufferedImage) not yet implemented."); /* Point2D.Double[] pointArray = new Point2D.Double[pointList.size()]; pointArray = (Point2D.Double[]) pointList.toArray(pointArray); extractCurvature(pointList.size(), pointArray); */ extractPeaks(pointList); } public void importDescriptor(Element descriptor) { throw new java.lang.UnsupportedOperationException("Method importDescriptor() not yet implemented."); /* if (!aDescription) return (unsigned long)-1; GenericDS l_DDLDescription; GenericDSInterfaceABC *l_DDLDescriptionInterface = NULL; string xsitype; if (aDescription->GetDSName() == "Descriptor") { aDescription->GetTextAttribute("xsi:type", xsitype); if (xsitype == "ContourShapeType") { l_DDLDescriptionInterface = aDescription; } } if (!l_DDLDescriptionInterface) { l_DDLDescription = aDescription->GetDescription("Descriptor"); while (!l_DDLDescription.isNull()) { l_DDLDescription.GetTextAttribute("xsi:type", xsitype); if (xsitype == "ContourShapeType") break; l_DDLDescription = l_DDLDescription.GetNextSibling("Descriptor"); } if (l_DDLDescription.isNull()) return (unsigned long)-1; l_DDLDescriptionInterface = l_DDLDescription.GetInterface(); } GenericDS GlobalCurvature_element = l_DDLDescriptionInterface->GetDescription("GlobalCurvature"); vector<int> gcv; GlobalCurvature_element.GetIntVector(gcv); SetGlobalCurvature((unsigned long)gcv[0], (unsigned long)gcv[1]); GenericDS PrototypeCurvature_element = l_DDLDescriptionInterface->GetDescription("PrototypeCurvature"); if (!PrototypeCurvature_element.isNull()) { vector<int> pcv; PrototypeCurvature_element.GetIntVector(pcv); SetPrototypeCurvature((unsigned long)pcv[0], (unsigned long)pcv[1]); } else SetPrototypeCurvature(0, 0); GenericDS HighestPeak_element = l_DDLDescriptionInterface->GetDescription("HighestPeakY"); int peak0; HighestPeak_element.GetIntValue(peak0); SetHighestPeakY(peak0); // Now that the 'numberOfPeaks' attribute has been removed, we need this // special case to check for the case where there are zero peaks. if (peak0 > 0) { // The SetNoOfPeaks() call must be done BEFORE reading the peak data, in // order to allocate the memory, so we step through the Peak elements // here first... int numPeaks = 1; GenericDS Peak_element = l_DDLDescriptionInterface->GetDescription("Peak"); while (!Peak_element.isNull()) { Peak_element = Peak_element.GetNextSibling("Peak"); numPeaks++; } SetNoOfPeaks(numPeaks); // And now step through properly to actually read and store the data... int i = 1; Peak_element = l_DDLDescriptionInterface->GetDescription("Peak"); while (!Peak_element.isNull()) { int xp, yp; Peak_element.GetIntAttribute("peakX", xp); Peak_element.GetIntAttribute("peakY", yp); SetPeak(i++, (unsigned short)xp, (unsigned short)yp); Peak_element = Peak_element.GetNextSibling("Peak"); } // And finally, set the zeroth peak (same as the highest one) SetPeak(0, 0, peak0); } // If the highest peak has a height of zero, this implies NO peaks else SetNoOfPeaks(0); return 0; */ } /** * Takes two ColorLayout DS and calculates similarity. * * @return -1.0 if c1 or c2 does not contain a valid ColorLayout DS */ public static double getSimilarity(Element c1, Element c2) { double val = -1.0; int YCoeff1, YCoeff2, CCoeff1, CCoeff2, YCoeff, CCoeff; return val; } /** * Takes two ColorLayout DS and calculates similarity. * @return Vector of int[] (yCoeff at Vector.get(0), cbCoeff at Vector.get(1), crCoeff cbCoeff at Vector.get(2)) or null if not valid ColorLayoutDS */ /* public static Vector getCoeffs(Element descriptor) { Vector vals = null; int[] y,cb,cr; int numY = 0; int numC = 0; Namespace mpeg7, xsi; mpeg7 = Namespace.getNamespace("", "urn:mpeg:mpeg7:schema:2001"); xsi = Namespace.getNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance"); boolean isValid = false; if (descriptor.getChild("YDCCoeff", mpeg7) != null && descriptor.getChild("CbDCCoeff", mpeg7) != null && descriptor.getChild("CrDCCoeff", mpeg7) != null) { isValid = true; numC = 1; numY = 1; } if (isValid) { String str_y, str_cb, str_cr; } return vals; } */ /** * Takes two ColorLayout Coeff sets and calculates similarity. * * @return -1.0 if data is not valid. */ public static double getSimilarity(int[] YCoeff1, int[] CbCoeff1, int[] CrCoeff1, int[] YCoeff2, int[] CbCoeff2, int[] CrCoeff2) { int numYCoeff1, numYCoeff2, CCoeff1, CCoeff2, YCoeff, CCoeff; return -1; } private BufferedImage YCrCb2RGB(int[][] rgbSmallImage) { BufferedImage br = new BufferedImage(8, 8, BufferedImage.TYPE_INT_RGB); WritableRaster r = br.getRaster(); double rImage, gImage, bImage; int pixel[] = new int[3]; for (int i = 0; i < 64; i++) { rImage = ((rgbSmallImage[0][i] - 16.0) * 256.0) / 219.0; gImage = ((rgbSmallImage[1][i] - 128.0) * 256.0) / 224.0; bImage = ((rgbSmallImage[2][i] - 128.0) * 256.0) / 224.0; pixel[0] = Math.max(0, (int) ((1.0 * rImage) + (1.402 * bImage) + 0.5)); //R pixel[1] = Math.max(0, (int) ((1.0 * rImage) + (-0.34413 * gImage) + (-0.71414 * bImage) + 0.5)); //G pixel[2] = Math.max(0, (int) ((1.0 * rImage) + (1.772 * gImage) + 0.5)); //B r.setPixel(i % 8, i / 8, pixel); } return br; } private long extractContour(int n, Point ishp) { throw new java.lang.UnsupportedOperationException("Method ExtractContour() not implemented"); /* int dr[] = { 0, -1, -1, -1, 0, 1, 1, 1 }; int dc[] = { 1, 1, 0, -1, -1, -1, 0, 1 }; int size = 0; Point2 *xy = 0; MomImage *mask_chan; if (m_ImageMedia->a_chan) { mask_chan=m_ImageMedia->a_chan; } else { mask_chan=m_ImageMedia->y_chan; } for (unsigned int r = 0; (r < mask_chan->y) && (size == 0); r++) { #ifdef WHITE_ON_BLACK UChar lastPel = 0; #else // !WHITE_ON_BLACK UChar lastPel = 255; #endif // !WHITE_ON_BLACK for (unsigned int c = 0; (c < mask_chan->x) && (size == 0); c++) { UChar thisPel = *xydata(mask_chan, c, r); if (thisPel != lastPel) { UChar dir = 0, dir0; unsigned int cr = r; unsigned int cc = c; UChar *p[8]; do { p[0] = xydata(mask_chan, cc + 1, cr ); p[1] = xydata(mask_chan, cc + 1, cr - 1); p[2] = xydata(mask_chan, cc , cr - 1); p[3] = xydata(mask_chan, cc - 1, cr - 1); p[4] = xydata(mask_chan, cc - 1, cr ); p[5] = xydata(mask_chan, cc - 1, cr + 1); p[6] = xydata(mask_chan, cc , cr + 1); p[7] = xydata(mask_chan, cc + 1, cr + 1); int i; for (i = 0; i < 8; i++) { #ifdef WHITE_ON_BLACK if (p[(dir+3-i)&7] && (*p[(dir+3-i)&7] != 0)) { if (!p[(dir+4-i)&7]) { dir = (dir+3-i)&7; break; } else if (*p[(dir+4-i)&7] == 0) { dir = (dir+3-i)&7; break; } } #else // !WHITE_ON_BLACK if (p[(dir+3-i)&7] && (*p[(dir+3-i)&7] == 0)) { if (!p[(dir+4-i)&7]) { dir = (dir+3-i)&7; break; } else if (*p[(dir+4-i)&7] != 0) { dir = (dir+3-i)&7; break; } } #endif // !WHITE_ON_BLACK } if (i == 8) break; else if (size == 0) dir0 = dir; else if ((cr == r) && (cc == c) && (dir == dir0)) break; if ((size % 32) == 0) { Point2 *nxy = new Point2[size+32]; memset(nxy, 0, (size+32)*sizeof(Point2)); if (size > 0) { memcpy(nxy, xy, size*sizeof(Point2)); delete[] xy; } xy = nxy; } xy[size].x = cc; xy[size].y = cr; size++; cr += dr[dir]; cc += dc[dir]; } while (1); } } } if (size == 0) return 0; double per = 0.0; double *dst = new double[size]; for (int i1 = 0; i1 < size; i1++) { int i2 = (i1 == 0) ? (size-1) : (i1-1); double dx = xy[i1].x - xy[i2].x; double dy = xy[i1].y - xy[i2].y; dst[i1] = sqrt(dx*dx + dy*dy); per += dst[i1]; } double del = per / (double)n; int cur = 0; double oldd = dst[cur]; ishp[0] = xy[0]; for (int j = 1; j < n; j++) { if (oldd > del) { double f = del / oldd; oldd -= del; int i1 = (cur < size-1) ? (cur + 1) : 0; double xs = f*(xy[i1].x - ishp[j-1].x); double ys = f*(xy[i1].y - ishp[j-1].y); ishp[j].x = ishp[j-1].x + xs; ishp[j].y = ishp[j-1].y + ys; } else { double newd = oldd + dst[++cur]; while (newd < del) newd += dst[++cur]; oldd = newd - del; double f = (dst[cur] - oldd) / dst[cur]; int i1 = (cur < size-1) ? (cur + 1) : 0; double xs = f*(xy[i1].x - xy[cur].x); double ys = f*(xy[i1].y - xy[cur].y); ishp[j].x = xy[cur].x + xs; ishp[j].y = xy[cur].y + ys; } } delete[] dst; delete[] xy; return n; */ } private void initPointArray(Point2D.Double[] pointArray) { if (pointArray != null) { for (int i = 0; i < pointArray.length; i++) { Point2D.Double point = pointArray[i]; if (point == null) { point = new Point2D.Double(); pointArray[i] = point; } point.x = 0; point.y = 0; } } } private void initIndexCoords(IndexCoords[] indexArray) { if (indexArray != null) { for (int i = 0; i < indexArray.length; i++) { IndexCoords index = indexArray[i]; if (index == null) { index = new IndexCoords(); indexArray[i] = index; } index.reset(); } } } private void initEdgeArray(Edge[] edgeArray) { if (edgeArray != null) { for (int i = 0; i < edgeArray.length; i++) { Edge index = edgeArray[i]; if (index == null) { index = new Edge(); edgeArray[i] = index; } index.reset(); } } } /** * main routine to extract the simularity vector * * @param pointList List of Point() * @return */ private long extractPeaks(List pointList) { int n = pointList.size(); Point2D.Double[] ishp = new Point2D.Double[n]; ishp = (Point2D.Double[]) pointList.toArray(ishp); Point2D.Double[] fshp = new Point2D.Double[n]; // Point() list initPointArray(fshp); //List peaks = new Vector(CONTOURSHAPE_MAXCSS, 10); // new Point2[CONTOURSHAPE_MAXCSS]; Point2D.Double[] peaks = new Point2D.Double[CONTOURSHAPE_MAXCSS]; initPointArray(peaks); int nPeaks = 0; Point2D.Double[] dxdy = new Point2D.Double[n]; Point2D.Double[] d2xd2y = new Point2D.Double[n]; Point2D.Double[] ang = new Point2D.Double[n]; Point2D.Double[] fxfy = new Point2D.Double[n]; initPointArray(dxdy); initPointArray(d2xd2y); initPointArray(ang); initPointArray(fxfy); double[] nMinima = new double[n]; double[] nMaxima = new double[n]; int nNmin = 0; int nNmax = 0; double[] oMinima = new double[n]; double[] oMaxima = new double[n]; int oNmin = 0; int oNmax = 0; for (int n1 = 0; n1 < n; n1++) { int n2 = (n1 > 0) ? (n1 - 1) : (n - 1); dxdy[n1].x = ishp[n1].x - ishp[n2].x; dxdy[n1].y = ishp[n1].y - ishp[n2].y; } int rec = 0, maxrec = (int) (0.262144 * n * n); do { if (nNmin > 0) { //memcpy(oMinima, nMinima, nNmin*sizeof(double)); System.arraycopy(nMaxima, 0, oMaxima, 0, nNmin); } oNmin = nNmin; if (nNmax > 0) { //memcpy(oMaxima, nMaxima, nNmax*sizeof(double)); System.arraycopy(nMaxima, 0, oMaxima, 0, nNmax); } oNmax = nNmax; ang[0].x = 0.0; d2xd2y[0].x = dxdy[0].x - dxdy[n - 1].x; d2xd2y[0].y = dxdy[0].y - dxdy[n - 1].y; double len = Math.sqrt(dxdy[0].x * dxdy[0].x + dxdy[0].y * dxdy[0].y); for (int i1 = 1; i1 < n; i1++) { ang[i1].x = len; d2xd2y[i1].x = dxdy[i1].x - dxdy[i1 - 1].x; d2xd2y[i1].y = dxdy[i1].y - dxdy[i1 - 1].y; len += Math.sqrt(dxdy[i1].x * dxdy[i1].x + dxdy[i1].y * dxdy[i1].y); } double ilen = 1.0 / len; for (int i2 = 0; i2 < n; i2++) { ang[i2].x *= ilen; ang[i2].y = dxdy[i2].x * d2xd2y[i2].y - dxdy[i2].y * d2xd2y[i2].x; } nNmin = nNmax = 0; double y0, x0; double x1 = ang[0].x; double y1 = ang[0].y; for (int j1 = 0; j1 < n; j1++) { int j1w = j1 + 1; while (j1w >= n) j1w -= n; x0 = x1; y0 = y1; x1 = ang[j1w].x; y1 = ang[j1w].y; if ((y0 < -CONTOURSHAPE_T) && (y1 >= -CONTOURSHAPE_T)) { for (int j2 = j1 + 1; j2 < j1 + n; j2++) { int j2w = j2; while (j2w >= n) j2w -= n; double y2 = ang[j2w].y; if (y2 < -CONTOURSHAPE_T) break; if (y2 >= CONTOURSHAPE_T) { double x2 = ang[j2w].x; double dx = x2 - x0; while (dx < 0.0) dx += 1.0; double x = -y0 * dx / (y2 - y0) + x0; while (x > 1.0) x -= 1.0; nMinima[nNmin] = x; nNmin++; break; } } } if ((y0 >= CONTOURSHAPE_T) && (y1 < CONTOURSHAPE_T)) { for (int j2 = j1 + 1; j2 < j1 + n; j2++) { int j2w = j2; while (j2w >= n) j2w -= n; double y2 = ang[j2w].y; if (y2 >= CONTOURSHAPE_T) break; if (y2 < -CONTOURSHAPE_T) { double x2 = ang[j2w].x; double dx = x2 - x0; while (dx < 0.0) dx += 1.0; double x = -y0 * dx / (y2 - y0) + x0; while (x > 1.0) x -= 1.0; nMaxima[nNmax] = x; nNmax++; break; } } } } for (int f1 = 0; f1 < n; f1++) { int f0 = (f1 > 0) ? (f1 - 1) : (n - 1); int f2 = (f1 < n - 1) ? (f1 + 1) : 0; fxfy[f1].x = 0.25 * (dxdy[f0].x + 2.0 * dxdy[f1].x + dxdy[f2].x); fxfy[f1].y = 0.25 * (dxdy[f0].y + 2.0 * dxdy[f1].y + dxdy[f2].y); } //memcpy(dxdy, fxfy, n*sizeof(Point2)); System.arraycopy(fxfy, 0, dxdy, 0, n); if ((nNmin < oNmin) && (nNmax < oNmax) && (oNmin <= (CONTOURSHAPE_MAXCSS)) && (oNmax <= (CONTOURSHAPE_MAXCSS))) { for (int m1 = 0; m1 < nNmin; m1++) { int idx = 0; double diff = 9999.9; for (int k1 = 0; k1 < oNmin; k1++) { double d = Math.abs(nMinima[m1] - oMinima[k1]); if (d > 0.5) d = 1.0 - d; if (d < diff) { idx = k1; diff = d; } } oNmin--; if (idx < oNmin) //memmove(&oMinima[idx], &oMinima[idx+1], (oNmin-idx)*sizeof(double)); System.arraycopy(oMinima, (idx + 1), oMinima, idx, (oNmin - idx)); } for (int m2 = 0; m2 < nNmax; m2++) { int idx = 0; double diff = 9999.9; for (int k1 = 0; k1 < oNmax; k1++) { double d = Math.abs(nMaxima[m2] - oMaxima[k1]); if (d > 0.5) d = 1.0 - d; if (d < diff) { idx = k1; diff = d; } } oNmax--; if (idx < oNmax) { //memmove(&oMaxima[idx], &oMaxima[idx+1], (oNmax-idx)*sizeof(double)); System.arraycopy(oMaxima, (idx + 1), oMaxima, idx, (oNmax - idx)); } } while (oNmin == 0) { int idx = 0; double diff = 9999.9; for (int m3 = 0; m3 < oNmax; m3++) { double d = Math.abs(oMaxima[m3] - oMinima[0]); if (d > 0.5) d = 1.0 - d; if (d < diff) { idx = m3; diff = d; } } double x = 0.5 * (oMinima[0] + oMaxima[idx]); if (Math.abs(oMinima[0] - oMaxima[idx]) > 0.5) { if (x > 0.5) x -= 0.5; else x += 0.5; } int xidx = 0; diff = Math.abs(ang[0].x - x); if (diff > 0.5) diff = 1.0 - diff; for (int l1 = 1; l1 < n; l1++) { double d = Math.abs(ang[l1].x - x); if (d > 0.5) d = 1.0 - d; if (d < diff) { diff = d; xidx = l1; } } //memmove(&peaks[1], &peaks[0], (CONTOURSHAPE_MAXCSS-1)*sizeof(peaks[0])); System.arraycopy(peaks, 0, peaks, 1, (CONTOURSHAPE_MAXCSS - 1)); peaks[0].x = (double) xidx; peaks[0].y = rec; if (nPeaks < CONTOURSHAPE_MAXCSS) nPeaks++; if (--oNmin == 0) { //memmove(&oMinima[0], &oMinima[1], oNmin*sizeof(oMinima[0])); System.arraycopy(oMinima, 1, oMinima, 0, (oNmin)); } if (--oNmax > idx) { //memmove(&oMaxima[idx], &oMaxima[idx+1], (oNmax-idx)*sizeof(oMaxima[0])); System.arraycopy(oMaxima, (idx + 1), oMaxima, idx, (oNmax - idx)); } } } rec++; } while ((rec < maxrec) && (nNmin > 0) && (nNmax > 0)); oMaxima = null; oMinima = null; nMaxima = null; nMinima = null; fxfy = null; ang = null; double xc = 0.0; double yc = 0.0; double len = 0; for (int s1 = 0; s1 < n; s1++) { len += Math.sqrt(dxdy[s1].x * dxdy[s1].x + dxdy[s1].y * dxdy[s1].y); xc += dxdy[s1].x; yc += dxdy[s1].y; fshp[s1].x = xc; fshp[s1].y = yc; } double nsmap = 1.0 / ((double) n * (double) n); for (int p1 = 0; p1 < nPeaks; p1++) { double pl = 0.0; for (int p2 = 0; p2 < peaks[p1].x; p2++) pl += Math.sqrt(dxdy[p2].x * dxdy[p2].x + dxdy[p2].y * dxdy[p2].y); peaks[p1].x = pl / len; peaks[p1].y = CONTOURSHAPE_TXA0 * Math.pow(peaks[p1].y * nsmap, CONTOURSHAPE_TXA1); } d2xd2y = null; dxdy = null; double offset = peaks[0].x; for (int p2 = 0; p2 < nPeaks; p2++) { peaks[p2].x -= offset; if (peaks[p2].x < 0.0) peaks[p2].x += 1.0; } if (peaks[0].y < CONTOURSHAPE_AP) nPeaks = 0; for (int p3 = 0; p3 < nPeaks; p3++) { if (peaks[p3].y < CONTOURSHAPE_YP * peaks[0].y) nPeaks = p3; } setNoOfPeaks(nPeaks); if (nPeaks == 0) { setHighestPeakY(0); } double py = 0; for (int i = 0; i < nPeaks; i++) { long qx = 0; //unsigned long qy = 0; qx = (int) ((int) ((CONTOURSHAPE_XMASK * peaks[i].x / CONTOURSHAPE_XMAX) + 0.5) & CONTOURSHAPE_XMASK); if (i == 0) { //unsigned long qyl = (long) ((CONTOURSHAPE_YMASK * peaks[i].y / CONTOURSHAPE_YMAX) + 0.5); if (qyl > CONTOURSHAPE_YMASK) qy = CONTOURSHAPE_YMASK; else qy = (int) (qyl & CONTOURSHAPE_YMASK); py = (qy * CONTOURSHAPE_YMAX / (double) CONTOURSHAPE_YMASK); } else { //unsigned long qyl = (long) ((CONTOURSHAPE_YnMASK * peaks[i].y / py) + 0.5); if (qyl > CONTOURSHAPE_YnMASK) qy = CONTOURSHAPE_YnMASK; else qy = (int) (qyl & CONTOURSHAPE_YnMASK); py = (qy * py / (double) CONTOURSHAPE_YnMASK); } setPeak(i, qx, qy); if (i == 0) { setHighestPeakY(qy); } } //unsigned long[] qce = new long[2];//qe, qc; qce = extractCurvature(n, ishp);//, qc, qe); setGlobalCurvature(qce[0], qce[1]); if (nPeaks > 0) { qce = extractCurvature(n, fshp); //, qce[0], qce[1]); setPrototypeCurvature(qce[0], qce[1]); } peaks = null; fshp = null; return nPeaks; } private long[] extractCurvature(int n, Point2D.Double[] shp) { long[] returnValue = new long[2]; // long qc, long qe long qc; long qe; double ecc = 0.0, cir = 0.0; //IndexCoords *ind = new IndexCoords[n]; IndexCoords[] ind = new IndexCoords[n]; initIndexCoords(ind); double x1 = shp[0].x, x2 = shp[0].x; for (int k0 = 0; k0 < n; k0++) { if (shp[k0].x < x1) x1 = shp[k0].x; if (shp[k0].x > x2) x2 = shp[k0].x; ind[k0].i = k0; ind[k0].x = shp[k0].x; ind[k0].y = shp[k0].y; } //qsort(ind, n, sizeof(ind[0]), compare_ind); java.util.Arrays.sort(ind, new SortInd()); double y1 = ind[0].y, y2 = ind[n - 1].y; int iw = (int) (x2 - x1 + 1); int ih = (int) (y2 - y1 + 1); int[] xy = new int[iw * ih]; //memset(xy, 0, iw*ih*sizeof(UChar)); int nedge = 0; Edge[] edgelist = new Edge[n]; initEdgeArray(edgelist); int ybot = (int) Math.ceil(y1 - 0.5); int ytop = (int) Math.floor(y2 - 0.5); if (ybot - (int) y1 < 0) ybot = (int) y1; if (ytop - (int) y1 >= ih) ytop = ih - 1 + (int) y1; int k1 = 0; for (int y = ybot; y <= ytop; y++) { for (; (k1 < n) && (ind[k1].y < (y + 0.5)); k1++) { int i1 = ind[k1].i; int i0 = (i1 < n - 1) ? i1 + 1 : 0; int i2 = (i1 > 0) ? i1 - 1 : n - 1; if (shp[i0].y <= y - 0.5) { int e; for (e = 0; (e < nedge) && (edgelist[e].i != i1); e++) ; if (e < nedge) { //memmove(&edgelist[e], &edgelist[e+1], (nedge-e)*sizeof(edgelist[0])); System.arraycopy(edgelist, (e + 1), edgelist, e, (nedge - e)); nedge--; } } else if (shp[i0].y >= y + 0.5) { edgelist[nedge].i = i1; edgelist[nedge].dx = (shp[i1].x - shp[i0].x) / (shp[i1].y - shp[i0].y); edgelist[nedge].x = edgelist[nedge].dx * (y - shp[i0].y) + shp[i0].x; nedge++; } if (shp[i2].y <= y - 0.5) { int e; for (e = 0; (e < nedge) && (edgelist[e].i != i2); e++) ; if (e < nedge) { //memmove(&edgelist[e], &edgelist[e+1], (nedge-e)*sizeof(edgelist[0])); System.arraycopy(edgelist, (e + 1), edgelist, e, (nedge - e)); nedge--; } } else if (shp[i2].y >= y + 0.5) { edgelist[nedge].i = i2; edgelist[nedge].dx = (shp[i1].x - shp[i2].x) / (shp[i1].y - shp[i2].y); edgelist[nedge].x = edgelist[nedge].dx * (y - shp[i2].y) + shp[i2].x; nedge++; } } //qsort(edgelist, nedge, sizeof(edgelist[0]), compare_edges); java.util.Arrays.sort(edgelist, new SortEdge()); for (int s = 0; s < nedge - 1; s += 2) { int xl = (int) Math.ceil(edgelist[s].x) - (int) x1; if (xl < 0) xl = 0; int xr = (int) Math.floor(edgelist[s + 1].x) - (int) x1; if (xr >= iw) xr = iw - 1; int yl = (int) (y - (int) y1); for (int f = xl; f <= xr; f++) xy[f + yl * iw] = 255; edgelist[s].x += edgelist[s].dx; edgelist[s + 1].x += edgelist[s + 1].dx; } } double perim = Math.sqrt((shp[0].x - shp[n - 1].x) * (shp[0].x - shp[n - 1].x) + (shp[0].y - shp[n - 1].y) * (shp[0].y - shp[n - 1].y)); for (int p = 1; p < n; p++) { perim += Math.sqrt((shp[p].x - shp[p - 1].x) * (shp[p].x - shp[p - 1].x) + (shp[p].y - shp[p - 1].y) * (shp[p].y - shp[p - 1].y)); } double vol = 0; double meanx = 0.0; double meany = 0.0; for (int vy = 0; vy < ih; vy++) { for (int vx = 0; vx < iw; vx++) { if (xy[vx + vy * iw] == 0) { meanx += vx; meany += vy; vol++; } } } meanx /= vol; meany /= vol; double i11 = 0.0, i20 = 0.0, i02 = 0.0; // double rad = 0.0, co = 0.0; for (int ey = 0; ey < ih; ey++) { for (int ex = 0; ex < iw; ex++) { if (xy[ex + ey * iw] == 0) { i11 += (ex - meanx) * (ey - meany); i20 += (ex - meanx) * (ex - meanx); i02 += (ey - meany) * (ey - meany); } } } double temp1 = (i20 + i02); double temp2 = Math.sqrt(i20 * i20 + i02 * i02 - 2.0 * i02 * i20 + 4.0 * i11 * i11); cir = perim * perim / vol; ecc = Math.sqrt((temp1 + temp2) / (temp1 - temp2)); ind = null; edgelist = null; xy = null; if (ecc >= CONTOURSHAPE_EMAX) qe = CONTOURSHAPE_EMASK; else if (ecc < CONTOURSHAPE_EMIN) qe = 0; else qe = (long) ((long) (((CONTOURSHAPE_EMASK + 1) * (ecc - CONTOURSHAPE_EMIN) / (CONTOURSHAPE_EMAX - CONTOURSHAPE_EMIN))) & CONTOURSHAPE_EMASK); if (cir >= CONTOURSHAPE_CMAX) qc = CONTOURSHAPE_CMASK; else if (cir < CONTOURSHAPE_CMIN) qc = 0; else qc = (long) (((long) ((CONTOURSHAPE_CMASK + 1) * (cir - CONTOURSHAPE_CMIN) / (CONTOURSHAPE_CMAX - CONTOURSHAPE_CMIN))) & CONTOURSHAPE_CMASK); returnValue[0] = qc; returnValue[1] = qe; return returnValue; } private static void debug(String message) { if (debug) System.out.println("[ColorLayout] " + message); } /* EXAMPLE: ======== <VisualDescriptor xsi:type="ColorLayoutType"> <YDCCoeff>12</YDCCoeff> <CbDCCoeff>2</CbDCCoeff> <CrDCCoeff>2</CrDCCoeff> <YACCoeff5>1 1 1 1 1</YACCoeff5> <CbACCoeff2>2 2</CbACCoeff2> <CrACCoeff2>2 2</CrACCoeff2> </VisualDescriptor> */ public static void main(String[] args) { try { List pointListStar3 = new Vector(); pointListStar3.add(new Point2D.Double(290, 439)); pointListStar3.add(new Point2D.Double(312, 308)); pointListStar3.add(new Point2D.Double(425, 238)); pointListStar3.add(new Point2D.Double(300, 285)); pointListStar3.add(new Point2D.Double(183, 222)); pointListStar3.add(new Point2D.Double(286, 306)); //console.line(); //console.echo(CollectionTools.printCollectionContent(pointListStar3)); pointListStar3 = java2dTools.normalizeCoordinate(pointListStar3); //console.line(); //console.echo(CollectionTools.printCollectionContent(pointListStar3)); ContourShape cl = new ContourShape(pointListStar3); Element desc1 = cl.getDescriptor(); //console.line(); //todo: check this, jdom changed //new XMLOutputter(" ", true).output(desc1, System.out); //new XMLOutputter().output(desc1, System.out); //console.echo(""); List pointListBox = new Vector(); pointListStar3.add(new Point2D.Double(30, 30)); pointListStar3.add(new Point2D.Double(200, 30)); pointListStar3.add(new Point2D.Double(200, 100)); pointListStar3.add(new Point2D.Double(30, 100)); ContourShape c2 = new ContourShape(pointListStar3); Element desc2 = cl.getDescriptor(); //console.line(); //todo: check this, jdom changed //new XMLOutputter(" ", true).output(desc1, System.out); //new XMLOutputter().output(desc1, System.out); //console.echo(""); //console.line(); //Element desc2 = new ContourShape(64, 64, ImageIO.read(new FileInputStream("test2.jpg"))).getDescriptor(); //Element desc3 = new ContourShape(64, 64, ImageIO.read(new FileInputStream("test3.jpg"))).getDescriptor(); //System.out.println("Similarity test1 test2: " + ContourShape.getSimilarity(desc1, desc2)); //System.out.println("Similarity test1 test3: " + ContourShape.getSimilarity(desc1, desc3)); //System.out.println("Similarity test2 test3: " + ContourShape.getSimilarity(desc2, desc3)); } catch (Exception e) { e.printStackTrace(); } } }