Warning: session_start(): open(/var/lib/php/sessions/sess_88o7l6jej5b0lv29b9sp7pm53h, O_RDWR) failed: No space left on device (28) in /var/www/tb-usercake/models/config.php on line 51
Warning: session_start(): Failed to read session data: files (path: /var/lib/php/sessions) in /var/www/tb-usercake/models/config.php on line 51
// probabilistic (of course)
// Note: This class is theoretically subject to floating-point
// rounding errors due to repeated additions. However the precision of
// 64 bit floating point is probably way higher than the sum of all
// pixels in a normally sized image.
srecord noeq ImageSimilarityAtScale (
IIntegralImage img1,
IIntegralImage img2,
int featureSize // smallest block size to be looked at (w/h in pixels)
) extends Probabilistic implements IF0 {
int channels;
LookAtClip root;
int blocksCalculated;
bool verbose;
bool updateInnerNodes;
double factor;
double rootDiffs;
// key = area in pixels
// Hmm. stil working this out. How to get the proper diff at
// different feature sizes?
//Map diffAtScale = autoMap(() -> new RatioAccumulator);
/*void updateDiffAtScale(int area, Double change) {
addToDoubleValueMap(diffAtScale, area, change, area);
}*/
record LookAtClip(LookAtClip parent, Rect r) implements Runnable {
L children;
// diffs are in range [0;sqrt(channels)*pixelsCovered]
double initialDiff, diffsFromChildren, areaCoveredByChildren;
double latestDiff;
double latestDiff() { ret latestDiff; }
double calculateLatestDiff() {
double area = area();
double areaLeft = 1-areaCoveredByChildren/area;
latestDiff = initialDiff*areaLeft+diffsFromChildren;
if (verbose) printVars(+r, +latestDiff, +initialDiff, +areaLeft, +diffsFromChildren);
ret latestDiff;
}
run {
// make initial guess
double sum = 0;
for channel to channels: {
double sum1 = img1.rectSum(r, channel);
double sum2 = img2.rectSum(r, channel);
sum += sqr(sum1-sum2);
//if (verbose) printVars(+r, +sum1, +sum2, +sum);
}
setInitialDiff(sqrt(sum)*factor);
++blocksCalculated;
if (r.w > r.h) {
if (r.w > featureSize)
splitHorizontally();
} else {
if (r.h > featureSize)
splitVertically();
}
}
void splitHorizontally {
split(asList(splitRectInHorizontalHalves(r)));
}
void splitVertically {
split(asList(splitRectInVerticalHalves(r)));
}
void split(L parts) {
double p = 0.99;
children = map(parts, r -> new LookAtClip(this, r));
scheduleAllRelative(p, children);
}
void setInitialDiff(double initialDiff) {
this.initialDiff = initialDiff;
//updateDiffAtScale(area(), initialDiff);
calculateLatestDiff();
if (verbose) printVars setInitialDiff(+r, +initialDiff, +latestDiff);
if (this == root) rootDiffs = latestDiff;
if (parent != null) {
parent.areaCoveredByChildren += area();
parent.diffsFromChildren += latestDiff;
parent.update();
}
}
void update() {
double oldValue = latestDiff;
calculateLatestDiff();
if (verbose) printVars update(+r, +latestDiff);
rootDiffs += latestDiff-oldValue;
if (updateInnerNodes && parent != null) {
parent.diffsFromChildren += latestDiff-oldValue;
if (verbose)
printVars update2(+r, +oldValue, +latestDiff,
dfc := parent.diffsFromChildren);
parent.update();
}
}
simplyCached int area() { ret rectArea(r); }
}
run {
assertEquals("Sizes of compared images have to be equal", img1.getSize(), img2.getSize());
assertEquals("Channel counts of compared images have to be equal", channels = img1.nChannels(), img2.nChannels());
factor = 1/(255.0*sqrt(channels));
root = new LookAtClip(null, imageRect(img1));
root.run();
}
// similarity between 0 and 1
// it's a best guess until the calculation is complete
public Double similarity aka get() {
ret 1-diff();
}
// difference (1-similarity) between 0 and 1
// (this can be more precise in floating point then similarity)
public double diff() {
ret /*root.latestDiff()*/rootDiffs/root.area();
}
int blocksCalculated() { ret blocksCalculated; }
}