+#ifdef EXPLAIN
+ reg1 = sig1->reg + i;
+ reg2 = sig2->reg + j;
+ MSG("[%u, %u] s=%u d=%u df=(%d", i, j, s, d, (int)reg1->f[0] - (int)reg2->f[0]);
+ for (uns i = 1; i < IMAGE_VEC_F; i++)
+ MSG(" %d", (int)reg1->f[i] - (int)reg2->f[i]);
+ if (!((sig1->flags | sig2->flags) & IMAGE_SIG_TEXTURED))
+ {
+ MSG(") dh=(%d", (int)reg1->h[0] - (int)reg2->h[0]);
+ for (uns i = 1; i < IMAGE_REG_H; i++)
+ MSG(" %d", (int)reg1->h[i] - (int)reg2->h[i]);
+ }
+ MSGL(")");
+#endif
+ }
+
+ d = sum / 32;
+
+ uns a = sig1->cols * sig2->rows;
+ uns b = sig1->rows * sig2->cols;
+ if (a < 2 * b && b < 2 * a)
+ d = d * 2;
+ else if (a < 4 * b && b < 4 * a)
+ d = d * 3;
+ else
+ d = d * 5;
+
+ a = sig1->cols * sig1->rows;
+ b = sig2->cols * sig2->rows;
+
+ if ((a < 1000 && b > 5000) || (b < 1000 && a > 5000))
+ d = d * 2;
+ else if ((a < 5000 && b > 20000) || (b < 5000 && a > 20000))
+ d = d * 3 / 2;
+
+ return d;
+}
+
+#ifndef EXPLAIN
+static uns
+image_signatures_dist_fuzzy(struct image_signature *sig1, struct image_signature *sig2)
+#else
+static uns
+image_signatures_dist_fuzzy_explain(struct image_signature *sig1, struct image_signature *sig2, void (*msg)(byte *text, void *param), void *param)
+#endif
+{
+#ifdef EXPLAIN
+ byte buf[1024], *line = buf;
+ MSGL("Fuzzy matching");
+ explain_signature(sig1, msg, param);
+ explain_signature(sig2, msg, param);
+#endif
+
+ /* FIXME: do not mux textured and non-textured images (should be split in clusters tree) */
+ if ((sig1->flags ^ sig2->flags) & IMAGE_SIG_TEXTURED)
+ {
+ MSGL("Textured vs non-textured");
+ return ~0U;
+ }
+
+ uns cnt1 = sig1->len;
+ uns cnt2 = sig2->len;
+ struct image_region *reg1 = sig1->reg;
+ struct image_region *reg2 = sig2->reg;
+ uns mf[IMAGE_REG_MAX][IMAGE_REG_MAX], mh[IMAGE_REG_MAX][IMAGE_REG_MAX];
+ uns lf[IMAGE_REG_MAX * 2], lh[IMAGE_REG_MAX * 2];
+ uns df = sig1->df + sig2->df, dh = sig1->dh + sig2->dh;
+
+ /* Compute distance matrix */
+ for (uns i = 0; i < cnt1; i++)
+ for (uns j = 0; j < cnt2; j++)
+ {
+ uns d = 0;
+ for (uns k = 0; k < IMAGE_VEC_F; k++)
+ {
+ int dif = reg1[i].f[k] - reg2[j].f[k];
+ d += image_sig_cmp_features_weights[k] * dif * dif;
+ }
+ mf[i][j] = d;
+ d = 0;
+ for (uns k = 0; k < IMAGE_REG_H; k++)
+ {
+ int dif = reg1[i].h[k] - reg2[j].h[k];
+ d += image_sig_cmp_features_weights[k + IMAGE_VEC_F] * dif * dif;
+ }
+ mh[i][j] = d;
+ }
+
+ uns lfs = 0, lhs = 0;
+ for (uns i = 0; i < cnt1; i++)
+ {
+ uns f = mf[i][0], h = mh[i][0];
+ for (uns j = 1; j < cnt2; j++)
+ {
+ f = MIN(f, mf[i][j]);
+ h = MIN(h, mh[i][j]);
+ }
+ lf[i] = (df * 0x10000) / (df + fast_sqrt_u32(f));
+ lh[i] = (dh * 0x10000) / (dh + fast_sqrt_u32(h));
+ lfs += lf[i] * (6 * reg1[i].wa + 2 * reg1[i].wb);
+ lhs += lh[i] * reg1[i].wa;