+namespace
+{
+
+using ImageSimilarityCheckAbort = std::function<bool(gdouble)>;
+
+/*
+ * 4 rotations (0, 90, 180, 270) combined with two mirrors (0, H)
+ * generate all possible isometric transformations
+ * = 8 tests
+ * = change dir of x, change dir of y, exchange x and y = 2^3 = 8
+ */
+gdouble image_sim_data_compare_transfo(const ImageSimilarityData *a, const ImageSimilarityData *b, gchar transfo, const ImageSimilarityCheckAbort &check_abort)
+{
+ if (!a || !b || !a->filled || !b->filled) return 0.0;
+
+ gint sim = 0.0;
+ gint i2;
+ gint *i;
+ gint j2;
+ gint *j;
+
+ if (transfo & 1) { i = &j2; j = &i2; } else { i = &i2; j = &j2; }
+ for (gint j1 = 0; j1 < 32; j1++)
+ {
+ if (transfo & 2) *j = 31-j1; else *j = j1;
+ for (gint i1 = 0; i1 < 32; i1++)
+ {
+ if (transfo & 4) *i = 31-i1; else *i = i1;
+ sim += abs(a->avg_r[i1*32+j1] - b->avg_r[i2*32+j2]);
+ sim += abs(a->avg_g[i1*32+j1] - b->avg_g[i2*32+j2]);
+ sim += abs(a->avg_b[i1*32+j1] - b->avg_b[i2*32+j2]);
+ /* check for abort, if so return 0.0 */
+ if (check_abort(sim)) return 0.0;
+ }
+ }
+
+ return 1.0 - (static_cast<gdouble>(sim) / (255.0 * 1024.0 * 3.0));
+}
+
+gdouble image_sim_data_compare(const ImageSimilarityData *a, const ImageSimilarityData *b, const ImageSimilarityCheckAbort &check_abort)
+{
+ gchar max_t = (options->rot_invariant_sim ? 8 : 1);
+ gdouble max_score = 0;
+
+ for (gchar t = 0; t < max_t; t++)
+ {
+ max_score = std::max(image_sim_data_compare_transfo(a, b, t, check_abort), max_score);
+ }
+
+ return max_score;
+}
+
+} // namespace
+