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

201
LINES

< > BotCompany Repo | #1027270 // Image Recognition for Vector Spike v2 (two levels)

JavaX source code (Dynamic Module) [tags: use-pretranspiled] - run with: Stefan's OS

Uses 911K of libraries. Click here for Pure Java version (10273L/54K).

!7

// multi-resolution image search
// uses only one prototype image

cmodule ImageRecogSpike {
  switchable S prototypeImageID = #1102884;
  switchable S inputImageID = #1102883;
  switchable bool showResizedProtos;
  switchable int numberOfCandidatesToShow = 3;
  switchable int nTimes = 10;

  // how big do we think the prototype is in the whole image
  // (percentage by height)
  switchable double assumedPrototypeHeightPercentage = 70;
  
  transient L<Int> widths = ll(1, 2, 4, 8, 16, 32, 64, 128);
  transient new L<IBWIntegralImage> integralImages;
  transient BWIntegralImage baseImage;
  transient JTabbedPane tabs = jTabbedPane();
  transient ImageSurface isResult;
  transient BWImage prototypeImage;
  transient new L<OneLevel> levels; // recognizers for each granularity
  
  transient new Best<Rect> allBest;
  transient S status;

  class OneLevel extends SteppableAndBest<Rect> {
    IBWIntegralImage ii; // scaled integral image
    BWImage image;       // scaled image
    BWImage prototype;   // scaled prototype
    float minSimilarity = 0.5f;
    ImageSurface is;
    new Map<Rect, Double> allScores;

    // candidates are top-left corner of rect to try in our coordinates
    L<Pt> candidatesQueue = syncLinkedList();
    new Set<Pt> candidatesTried;
    Iterator<Pt> candidatesStream;
    
    void reset {
      clear(allScores);
      best.clear();
      clear(candidatesQueue);
      clear(candidatesTried);
      makeCandidatesStream();
    }

    *(IBWIntegralImage *ii) {
      image = iBWIntegralImageToBWImage(ii);
      // get assumed height of prototype in scaled-down image
      int ph = max(1, iround(ii.getHeight()*assumedPrototypeHeightPercentage/100.0));
      // resize prototype
      prototype = bwResizeToHeightSmooth(prototypeImage, ph);
      if (showResizedProtos)
        addTab(tabs, "proto " + ii.getWidth(),
          jFullCenterScroll(jPixelatedZoomedImageSurface(4.0, prototype)));
      makeCandidatesStream();
    }
    
    void makeCandidatesStream {
      candidatesStream = mapI rectTopLeftCorner(allSubRectsOfSizeIterator(prototype.getWidth(), prototype.getHeight(),
        imageRect(image)));
    }
    
    int width() { ret ii.getWidth(); }
    int height() { ret ii.getHeight(); }
    
    public bool step() {
      Pt p = nextCandidate();
      if (p != null) ret true with tryCandidate(p);
      false;
    }

    Pt nextCandidate() {
      try object Pt p = popFirst(candidatesQueue);
      ret nextFromIterator(candidatesStream);
    }

    void tryCandidate(Pt p) {
      if (!candidatesTried.add(p)) ret;

      int x = p.x, y = p.y, wp = prototype.getWidth(), hp = prototype.getHeight();

      float maxError = (1f-minSimilarity)*wp*hp;
      float diff = bwImageSectionsSimilarity(image, prototype, x, y, maxError);
      if (diff <= maxError)
        putInBestAndMap(best, allScores, new Rect(x, y, wp, hp), 1-diff/(wp*hp);
    }

    void showBest() {
      overlaySelectionsOnImageSurface(is, nBest(numberOfCandidatesToShow));
    }
    
    L<Rect> nBest(int n) {
      ret topTenKeysByValue(n, allScores);
    }
  }
  
  start-thread {
    dm_watchField numberOfCandidatesToShow(r showBest);
    if (baseImage == null)
      baseImage = BWIntegralImage(loadImage2(inputImageID));
    addTab(tabs, "Result", isResult = jPixelatedZoomedImageSurface(1.0, iBWIntegralImageToBWImage(baseImage)));
    if (prototypeImage == null)
      prototypeImage = loadBWImage(prototypeImageID);
    for (int w : widths) {
      IBWIntegralImage ii = scaledIBWIntegralImage(baseImage, w);
      integralImages.add(ii);
      ImageSurface is = jPixelatedZoomedImageSurface(
        doubleRatio(baseImage.getWidth(), w), iBWIntegralImageToBWImage(ii));
      addTab(tabs, "w=" + w, jFullCenterScroll(is));
      levels.add(setAll(new OneLevel(ii), +is));
    }
    addTab(tabs, "Prototype", jFullCenterScroll(jPixelatedZoomedImageSurface(4, prototypeImage)));

    repeat nTimes {
      recogWithTiming();
    }
    showBest();
  }

  void recogWithTiming {  
    time "Recognition" { 
      recog();
    }
    setField(status := "Recognized in " + lastTiming() + " ms: " + allBest);
  }
  
  void recog {
    reset();
    //fullSearch();
    twoLevels(16, 128, 5);
  }
  
  void fullSearch {
    print("Steps: " + stepAll_roundRobin(levels));
    copyBestFromLevel(last(levels));
  }
  
  void copyBestFromLevel(OneLevel lvl) {
    if (lvl.best.has())
      allBest.put(scaleBetweenWidths(lvl.width(), baseImage.getWidth(), lvl.best!), lvl.best.score);
  }
  
  void twoLevels(int width1, int width2, int candidatesToUse) {
    int spiralSize = width2/width1*2;
    int pixelsPerSpiral = sqr(spiralSize);
    print("Spiral size: " + spiralSize + " / " + pixelsPerSpiral);
    
    int i1 = indexOf(widths, width1), i2 = indexOf(widths, width2);
    if (i1 < 0) fail("Width " + width1 + " not in list: " + widths);
    if (i2 < 0) fail("Width " + width2 + " not in list: " + widths);
    OneLevel lvl1 = levels.get(i1), lvl2 = levels.get(i2);
    
    // Full search in level 1
    stepAll(lvl1);
    
    // Circle around n best candidates found in level 1
    L<Pt> candidates = scaleBetweenLevels(lvl1, lvl2, map topLeftCorner(lvl1.nBest(candidatesToUse)));
    for (Pt p : combineIterators_roundRobin(map(candidates, c ->
      pixelSpiral(c.x, c.y, lvl2.width(), lvl2.height(), pixelsPerSpiral))))
      lvl2.tryCandidate(p);
      
    copyBestFromLevel(lvl2);
  }
  
  Rect scaleBetweenWidths(int w1, int w2, Rect r) {
    ret scaleRect(doubleRatio(w2, w1), r);
  }
  
  Pt scaleBetweenWidths(int w1, int w2, Pt p) {
    ret scalePt(doubleRatio(w2, w1), p);
  }
  
  Pt scaleBetweenLevels(OneLevel lvl1, OneLevel lvl2, Pt p) {
    ret scaleBetweenWidths(lvl1.width(), lvl2.width(), p);
  }
  
  L<Pt> scaleBetweenLevels(OneLevel lvl1, OneLevel lvl2, Iterable<Pt> l) {
    ret map(l, p -> scaleBetweenLevels(lvl1, lvl2, p));
  }

  void showBest {  
    for (OneLevel l : levels) l.showBest();
    setImageSurfaceSelection(isResult, allBest!);
    print("Best: " + allBest);
    print("Candidates tried: " + mapNonNulls(levels, l ->
      empty(l.candidatesTried) ? null : l(l.candidatesTried) + " for w=" + l.width()));
  }
  
  void reset {
    for (OneLevel l : levels) l.reset();
    allBest.clear();
  }

  visual withCenteredButtons(tabs,
    vstackWithSpacing(
      withLabel("# of candidates to show:", dm_fieldSpinner numberOfCandidatesToShow(1, 100)),
      dm_centeredLabel status()));
}

Author comment

Began life as a copy of #1027204

download  show line numbers  debug dex  old transpilations   

Travelled to 7 computer(s): bhatertpkbcr, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tvejysmllsmz, vouqrxazstgt, xrpafgyirdlv

No comments. add comment

Snippet ID: #1027270
Snippet name: Image Recognition for Vector Spike v2 (two levels)
Eternal ID of this version: #1027270/27
Text MD5: 5f97ffea279f3895b98801d784d9ac4d
Transpilation MD5: 79b14b73336418e7e0c898e9d6c61655
Author: stefan
Category: javax / image recognition
Type: JavaX source code (Dynamic Module)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2020-02-29 17:40:37
Source code size: 6669 bytes / 201 lines
Pitched / IR pitched: No / No
Views / Downloads: 171 / 1359
Version history: 26 change(s)
Referenced in: [show references]