private static List<DistrPair> prepareDistribution(Segment[] segments, Photo photo) { List<DistrPair> distribution = new ArrayList<>(); int area = photo.getWidth() * photo.getHeight(); double sum = 0; for (Segment seg : segments) { DistrPair dp = new DistrPair(); // dp.weight = (double)seg.getSumPixels() / area; /* Original method uses sqrt */ dp.weight = Math.sqrt((double) seg.getSumPixels() / area); sum += dp.weight; Vector vect = new Vector(14); Addterator<Float> addter = vect.addterator(); /* Color moments - 9 elements in total */ float[] mean_hsb = seg.getMean(); float[] stdev_hsb = seg.getStdDeviation(); float[] skew_hsb = seg.getSkewness(); for (int i = 0; i < Segment.MODEL_NUM_ELEMENTS; i++) { addter.add(mean_hsb[i]); addter.add(stdev_hsb[i]); addter.add(skew_hsb[i]); } /* The other elements - another 5 of them */ int o_width = seg.getRight() - seg.getLeft(); o_width = Math.max(o_width, 1); int o_height = seg.getBottom() - seg.getTop(); o_height = Math.max(o_height, 1); int o_area = o_width * o_height; /* 5 elements characterizing the shape of one segment */ addter.add((float) Math.log((double) o_width / o_height + 1)); addter.add((float) Math.log((double) o_area / area + 1)); addter.add((float) seg.getSumPixels() / o_area); addter.add((float) seg.getX() / photo.getWidth()); addter.add((float) seg.getY() / photo.getHeight()); dp.vector = vect; distribution.add(dp); } /* Scale the sum of weights to be 1 */ for (DistrPair distrPair : distribution) { distrPair.weight /= sum; } return distribution; }
/** * For given two photos, count their similarity. The result is from interval [0;1], 1 means * perfect match, 0 totaly different. * * @param photo1 First photo. * @param photo2 Second photo. * @return Similarity of given photos from interval [0;1]; * @throws com.kappa_labs.ohunter.lib.net.OHException When Photos are wrongly set. */ public static synchronized float computeSimilarity(Photo photo1, Photo photo2) throws OHException { float ret = 0; /* Scale the images to provide the best results */ try { photo1.sImage = photo1._sImage = new SImage(photo1.sImage); photo2.sImage = photo2._sImage = new SImage(photo2.sImage); ((SImage) photo1.sImage).setImage(resize(((SImage) photo1._sImage).toBufferedImage())); ((SImage) photo2.sImage).setImage(resize(((SImage) photo2._sImage).toBufferedImage())); } catch (Exception e) { LOGGER.log(Level.WARNING, "Could not acquire photos from client: {0}", e); throw new OHException("Could not acquire photos!", OHException.EXType.OTHER); } /* Count average from few attempts */ final int numRepeats = settingsManager.getSimilarityNumberOfRepeats(); int iteration = numRepeats; while (iteration-- > 0) { /* Perform segmentation */ Segment[] segments1 = Segmenter.findSegments(photo1); Segment[] segments2 = Segmenter.findSegments(photo2); LOGGER.log( Level.FINER, "... got {0} segments from first and {1} segments" + " in the second photo", new Object[] {segments1.length, segments2.length}); /* Create new Problem from given counted segments */ Problem problem = new Problem(); problem.distr1 = prepareDistribution(segments1, photo1); problem.distr2 = prepareDistribution(segments2, photo2); /* Solve the EMP linear problem and return the final result */ EMDSolver empm = new EMDSolver(problem); float act = Math.max(0f, Math.min(1f, (float) empm.countValue())); LOGGER.finer(String.format(" - similarity: %.1f%%", 100 - act * 100)); ret += act; } ret /= numRepeats; return 1f - ret; }