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

172
LINES

< > BotCompany Repo | #1035858 // G22CriticalPixelSearch - find best pixel to split list of masks at

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

Transpiled version (29124L) is out of date.

sclass G22CriticalPixelSearch is Steppable {
  // input
  settable IG22MasksHolder<?> masksHolder;
  settable bool keepAllEntries;
  settable bool sortPixelsFirst = true;
  
  // internal
  int w, h;
  Iterator<Pt> pixelIterator;
  
  // output
  new Best<Pt> bestPixel;
  Entry bestEntry;
  Pt lastPixelLookedAt;
  Entry lastEntry;
  Entry[] pixelEntries;
  float[] pixelScores;
  int nPixelsTested;
  
  // stores all subsets of masks found if not null
  CompactHashSet<HashedByteArray> subSets;
  
  *() {}
  *(IG22MasksHolder *masksHolder) {}
  
  class Entry {
    Pt pixel;
    // child mask holders for pixel dark or pixel bright
    //IG22MasksHolder darkChild, brightChild;
    gettable L<IG22Mask> darkMasks;
    gettable L<IG22Mask> brightMasks;
    G22GhostImage darkGhost;
    G22GhostImage brightGhost;
    
    simplyCached IG22MasksHolder darkHolder() {
      ret new G22HashedMasks(darkMasks, darkGhost);
    }
    
    simplyCached IG22MasksHolder brightHolder() {
      ret new G22HashedMasks(brightMasks, brightGhost);
    }
    
    void calcGhosts {
      if (l(darkMasks) < l(brightMasks)) {
        darkGhost = new G22GhostImage(lmapMethod image(darkMasks));
        brightGhost = masksHolder().ghost().minus(darkGhost);
      } else {
        brightGhost = new G22GhostImage(lmapMethod image(brightMasks));
        darkGhost = masksHolder().ghost().minus(brightGhost);
      }
    }
    
    toString {
      ret commaCombine(
        "Split at " + pixel,
        "dark=" + darkHolder().renderCountAndCertainty(),
        "bright=" + brightHolder().renderCountAndCertainty());
    }
  }
  
  public bool step() {
    if (w == 0) {
      if (!masksHolder.canSplit()) false;
      
      meta-for w also as h { w = masksHolder.maskSize().w(); }
      pixelEntries = new Entry[w*h];
      pixelScores = new float[w*h];
      arrayfill(pixelScores, -1);
      pixelIterator = makePixelIterator();
    }
    
    if (!pixelIterator.hasNext()) false;
    lastPixelLookedAt = pixelIterator.next();
    testPixel(lastPixelLookedAt);
    true;
  }
  
  int idx(Pt p) { ret p.y*w+p.x; }
  
  void testPixel(Pt p) {
    double score;
    Entry e = null;
    ++nPixelsTested;
    
    // Find out if pixel is the same in all masks
    float ghostBrightness = masksHolder.ghost().getFloatPixel(p);
    if (ghostBrightness == 0 || ghostBrightness == 1)
      // Pixel is determined, not usable for splitting
      score = -2;
    else {
      // Pixel is not determined - let's make the 2 subsets
      
      e = new Entry;
      e.pixel = p;
      lastEntry = e;
      if (keepAllEntries)
        pixelEntries[idx(p)] = e;
        
      L<IG22Mask> masks = wideningListCast(masksHolder.masks());
      int n = l(masks);
      
      // bit is 1 when pixel is bright
      byte[] brightBits = byteArrayForNBits(n);

      // calculate the split
      for i to n:
        if (masks.get(i).image().getBoolPixel(p))
          setBit(brightBits, i);
          
      subSets?.add(new HashedByteArray(brightBits));
      
      var splitMasks = filterAntiFilterByBitSet(masks, brightBits);
      e.brightMasks = splitMasks.a;
      e.darkMasks = splitMasks.b;
      e.calcGhosts();

      score = scoreEntry(e);
    }
    
    pixelScores[idx(p)] = (float) score;
    if (score > 0 && bestPixel.put(p, score))
      bestEntry = e;
  }
  
  swappable double scoreEntry(Entry e) {
    double c1 = e.darkGhost.certainty();
    double c2 = e.brightGhost.certainty();
    
    // ret avg(c1, c2);
    ret min(c1, c2);
  }
  
  double bestScore() {
    ret bestPixel.score();
  }
  
  BWImage scoreImage() {
    double min = masksHolder.certainty();
    double max = bestPixel.score();
    ret bwImageFromFunction(w, h,
      (x, y) -> transformToZeroToOne(pixelScores[y*w+x], max, min));
  }
  
  G22PixelSplitMasks<?> splitMasksHolder() {
    if (!bestPixel.has()) null;
    ret new G22PixelSplitMasks()
      .splitPixel(bestPixel!)
      .darkHolder(bestEntry.darkHolder())
      .brightHolder(bestEntry.brightHolder());
  }
  
  IG22MasksHolder makeBestTree aka bestTree aka get() {
    stepAll(this);
    G22PixelSplitMasks<?> split = splitMasksHolder();
    if (split == null) ret masksHolder;
    split.transformSubHolders(subHolder
      -> new G22CriticalPixelSearch(subHolder).makeBestTree());
    ret split;
  }
  
  void collectSubSets {
    subSets if null = new CompactHashSet;
  }
  
  Iterator<Pt> makePixelIterator() {
    if (sortPixelsFirst)
      // try least certain pixels first
      ret iterator(pixelsByBrightness(masksHolder().ghost().certaintyImage()));
    else
      ret new WeightlessShuffledIterator<Pt>(pixelsInImage(w, h));
  }
}

download  show line numbers  debug dex  old transpilations   

Travelled to 3 computer(s): elmgxqgtpvxh, mqqgnosmbjvj, wnsclhtenguj

No comments. add comment

Snippet ID: #1035858
Snippet name: G22CriticalPixelSearch - find best pixel to split list of masks at
Eternal ID of this version: #1035858/61
Text MD5: 2ca7213890235ca20d11062a4a943c7a
Author: stefan
Category: javax / gazelle 22
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2023-02-13 22:43:02
Source code size: 4836 bytes / 172 lines
Pitched / IR pitched: No / No
Views / Downloads: 278 / 628
Version history: 60 change(s)
Referenced in: #1003674 - Standard Classes + Interfaces (LIVE continued in #1034167)