Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

137
LINES

< > BotCompany Repo | #1032159 // ImageSimilarityAtScale [seems OK] - check how similar 2 images are on a given scale, probabilistically approximating from below

JavaX fragment (include) [tags: use-pretranspiled]

Libraryless. Click here for Pure Java version (6584L/39K).

1  
// Approximate pixel-by-pixel similarity of 2 images very quickly
2  
// (probabilistically)
3  
4  
// Note: If my math is correct - and it always is -, floating-point
5  
// rounding errors should not occur even for the largest images.
6  
// Note 2: The data structures can get pretty big if you go to a
7  
// very high detail level.
8  
srecord noeq ImageSimilarityAtScale(
9  
  IIntegralImage img1,
10  
  IIntegralImage img2,
11  
  int featureSize // smallest block size to be looked at (w/h in pixels)
12  
) extends Probabilistic implements IF0<Double> {
13  
  
14  
  int channels;
15  
  LookAtClip root;
16  
  int blocksCalculated;
17  
  bool verbose;
18  
  bool updateInnerNodes;
19  
  
20  
  double factor;
21  
  double rootDiffs;
22  
  
23  
  // key = area in pixels
24  
  // Hmm. stil working this out. How to get the proper diff at
25  
  // different feature sizes?
26  
  //Map<Int, RatioAccumulator> diffAtScale = autoMap(() -> new RatioAccumulator);
27  
  
28  
  /*void updateDiffAtScale(int area, Double change) {
29  
    addToDoubleValueMap(diffAtScale, area, change, area);
30  
  }*/
31  
  
32  
  record LookAtClip(LookAtClip parent, Rect r) implements Runnable {
33  
    L<LookAtClip> children;
34  
35  
    // diffs are in range [0;sqrt(channels)*pixelsCovered]
36  
    double initialDiff, diffsFromChildren, areaCoveredByChildren;
37  
    double latestDiff;
38  
    
39  
    double latestDiff() { ret latestDiff; }
40  
    
41  
    double calculateLatestDiff() {
42  
      double area = area();
43  
      double areaLeft = 1-areaCoveredByChildren/area;
44  
      latestDiff = initialDiff*areaLeft+diffsFromChildren;
45  
      if (verbose) printVars(+r, +latestDiff, +initialDiff, +areaLeft, +diffsFromChildren);
46  
      ret latestDiff;
47  
    }
48  
    
49  
    run {
50  
      // make initial guess
51  
      
52  
      double sum = 0;
53  
      for channel to channels: {
54  
        double sum1 = img1.rectSum(r, channel);
55  
        double sum2 = img2.rectSum(r, channel);
56  
        sum += sqr(sum1-sum2);
57  
        //if (verbose) printVars(+r, +sum1, +sum2, +sum);
58  
      }
59  
      setInitialDiff(sqrt(sum)*factor);
60  
      ++blocksCalculated;
61  
62  
      if (r.w > r.h) {
63  
        if (r.w > featureSize)
64  
          splitHorizontally();
65  
      } else {
66  
        if (r.h > featureSize)
67  
          splitVertically();
68  
      }
69  
    }
70  
    
71  
    void splitHorizontally {
72  
      split(asList(splitRectInHorizontalHalves(r)));
73  
    }
74  
    
75  
    void splitVertically {
76  
      split(asList(splitRectInVerticalHalves(r)));
77  
    }
78  
    
79  
    void split(L<Rect> parts) {
80  
      double p = 0.99;
81  
      children = map(parts, r -> new LookAtClip(this, r));
82  
      scheduleAllRelative(p, children);
83  
    }
84  
85  
    void setInitialDiff(double initialDiff) {    
86  
      this.initialDiff = initialDiff;
87  
      //updateDiffAtScale(area(), initialDiff);
88  
      calculateLatestDiff();
89  
      if (verbose) printVars setInitialDiff(+r, +initialDiff, +latestDiff);
90  
      if (this == root) rootDiffs = latestDiff;
91  
      if (parent != null) {
92  
        parent.areaCoveredByChildren += area();
93  
        parent.diffsFromChildren += latestDiff;
94  
        parent.update();
95  
      }
96  
    }
97  
    
98  
    void update() {
99  
      double oldValue = latestDiff;
100  
      calculateLatestDiff();
101  
      if (verbose) printVars update(+r, +latestDiff);
102  
      rootDiffs += latestDiff-oldValue;
103  
      if (updateInnerNodes && parent != null) {
104  
        parent.diffsFromChildren += latestDiff-oldValue;
105  
        if (verbose)
106  
          printVars update2(+r, +oldValue, +latestDiff,
107  
            dfc := parent.diffsFromChildren);
108  
        parent.update();
109  
      }
110  
    }
111  
    
112  
    simplyCached int area() { ret rectArea(r); }
113  
  }
114  
  
115  
  run {
116  
    assertEquals("Sizes of compared images have to be equal", img1.getSize(), img2.getSize());
117  
    assertEquals("Channel counts of compared images have to be equal", channels = img1.nChannels(), img2.nChannels());
118  
    factor = 1/(255.0*sqrt(channels));
119  
    
120  
    root = new LookAtClip(null, imageRect(img1));
121  
    root.run();
122  
  }
123  
  
124  
  // similarity between 0 and 1
125  
  // it's a best guess until the calculation is complete
126  
  public Double similarity aka get() {
127  
    ret 1-diff();
128  
  }
129  
  
130  
  // difference (1-similarity) between 0 and 1
131  
  // (this can be more precise in floating point then similarity)
132  
  public double diff() {
133  
    ret /*root.latestDiff()*/rootDiffs/root.area();
134  
  }
135  
  
136  
  int blocksCalculated() { ret blocksCalculated; }
137  
}

download  show line numbers  debug dex  old transpilations   

Travelled to 3 computer(s): bhatertpkbcr, mqqgnosmbjvj, pyentgdyhuwx

No comments. add comment

Snippet ID: #1032159
Snippet name: ImageSimilarityAtScale [seems OK] - check how similar 2 images are on a given scale, probabilistically approximating from below
Eternal ID of this version: #1032159/57
Text MD5: 59d05c7d0a30a27c6b6a09fb0bbdc93c
Transpilation MD5: 928b42a9d21b64a12667f8d773a46aab
Author: stefan
Category: javax
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2021-09-08 03:10:16
Source code size: 4315 bytes / 137 lines
Pitched / IR pitched: No / No
Views / Downloads: 228 / 453
Version history: 56 change(s)
Referenced in: [show references]