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

168
LINES

< > BotCompany Repo | #1032203 // Minimal Recognizer [backup]

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

Uses 108K of libraries. Click here for Pure Java version (13374L/82K).

do not include class IntegralImage.
do not include class IIntegralImage.

srecord noeq MinimalRecognizer(BufferedImage inputImage) {
  replace Channel with int.

  IIntegralImage mainImage;
  
  static final int grayscale = 3; // channel number for grayscale
  
  abstract class IIntegralImage {
    // width and height of image
    int w, h;
    
    abstract double integralValue(int x, int y, Channel channel);
    
    BufferedImage render() {
      ret imageFromFunction(w, h, (x, y) -> rgbPixel(x, y, x+1, y+1) | fullAlphaMask());
    }

    double getPixel(Rect r, int channel) {
      ret getPixel(r.x, r.y, r.x2(), r.y2(), channel);
    }

    double getPixel(int channel) { ret getPixel(0, 0, w, h, channel); }
    
    // return value ranges from 0 to 1 (usually)
    double getPixel(int x1, int y1, int x2, int y2, int channel) {
      ret doubleRatio(rectSum(x1, y1, x2, y2, channel), (x2-x1)*(y2-y1)*255.0);
    }
    
    double rectSum(Rect r, int channel) {
      ret rectSum(r.x, r.y, r.x2(), r.y2(), channel);
    }
    
    double rectSum(int x1, int y1, int x2, int y2, int channel) {
      double bottomLeft  = integralValue(x1-1, y2-1, channel);
      double bottomRight = integralValue(x2-1, y2-1, channel);
      double topLeft     = integralValue(x1-1, y1-1, channel);
      double topRight    = integralValue(x2-1, y1-1, channel);
      ret bottomRight-topRight-bottomLeft+topLeft;
    }

    int rgbPixel(int x1, int y1, int x2, int y2) {
      int r = iround(clampZeroToOne(getPixel(x1, y1, x2, y2, 0))*255);
      int g = iround(clampZeroToOne(getPixel(x1, y1, x2, y2, 1))*255);
      int b = iround(clampZeroToOne(getPixel(x1, y1, x2, y2, 2))*255);
      ret rgbInt(r, g, b);
    }
    
    double liveliness(int channel) {
      // optimization (but no change in semantics):
      // if (w <= 1 && h <= 1) ret 0; // liveliness of single pixel is 0
      ret standardDeviation(map(q -> q.getPixel(channel), quadrants()));
    }

    L<IIntegralImage> descentShapes() {
      ret centerPlusQuadrants();
    }
    
    L<IIntegralImage> centerPlusQuadrants() {
      int midX = w/2, midY = h/2;
      Rect r = rectAround(midX, midY, max(midX/2, 1), max(midY/2, 1));
      ret itemPlusList(clip(r), quadrants());
    }
    
    L<IIntegralImage> quadrants() {
      if (w <= 1 && h <= 1) null; // let's really not have quadrants of a single pixel
      int midX = w/2, midY = h/2;
      ret mapLL clip(
        rect(0, 0, max(midX, 1), max(midY, 1)),
        rect(midX, 0, w-midX, max(midY, 1)),
        rect(0, midY, max(midX, 1), h-midY),
        rect(midX, midY, w-midX, h-midY)
      );
    }

    IIntegralImage liveliestQuadrant(int channel) {
      ret highestBy(q -> q.liveliness(channel), quadrants());
    }

    Clip clip(Rect r) { ret new Clip(this, r); }
    Clip clip(int x1, int y1, int w, int h) { ret clip(rect(x1, y1, w, h)); }
    
    Rect positionInImage(IIntegralImage mainImage) {
      if (this == mainImage) ret rect(0, 0, w, h);
      null;
    }
  }

  // virtual clip of an integral image
  class Clip extends IIntegralImage {
    IIntegralImage fullImage;
    int x1, y1;

    *(IIntegralImage *fullImage, Rect r) {
      x1 = r.x; y1 = r.y; w = r.w; h = r.h;
    }
     
    *(IIntegralImage *fullImage, int *x1, int *y1, int *w, int *h) {}
    
    public double integralValue(int x, int y, int channel) {
      ret fullImage.integralValue(x+x1, y+y1, channel);
    }

    // don't clip a clip - be smarter than that!
    Clip clip(Rect r) {
      ret new Clip(fullImage, translateRect(r, x1, y1));
    }

    Rect rectInImage() {
      ret rect(x1, y1, w, h);
    }

    Rect positionInImage(IIntegralImage mainImage) {
      try object Rect r = super.positionInImage(mainImage);
      if (fullImage == mainImage) ret rect(x1, y1, w, h);
      null;
    }

    toString { ret rectInImage() + " in " + fullImage; }
  }

  class IntegralImage extends IIntegralImage {
    int[] data;
     
    *(BufferedImage img) {
      w = img.getWidth(); h = img.getHeight();
      if (longMul(w, h) > 8000000) fail("Image too big: " + w + "*" + h);
      int[] pixels = pixelsOfBufferedImage(img);
      data = new int[w*h*3];
      int i = 0, j = 0;
      int[] sum = new[3];
      for y to h: {
        for c to 3: sum[c] = 0;
        for x to w: {
          int rgb = pixels[j++] & 0xFFFFFF;
          for c to 3: {
            data[i] = (sum[c] += rgb >> 16);
            if (y > 0)
              data[i] += data[i-w*3];
            i++;
            rgb = (rgb << 8) & 0xFFFFFF;
          }
        }
      }
    }
    
    public double integralValue(int x, int y, Channel channel) {
      if (channel == grayscale)
        ret doubleAvg(countIterator(3, c -> integralValue(x, y, c)));
        
      ret x < 0 || y < 0 ? 0
        : data[(min(y, h-1)*w+min(x, w-1))*3+channel];
    }
  }
  
  run {
    mainImage = new IntegralImage(inputImage);
    inputImage = null; // save space
    
    print(liveliness := mainImage.liveliness(grayscale));
    IIntegralImage clip = mainImage;
    clip = applyUntilEqual_goOneBackOnNull(c -> c.liveliestQuadrant(grayscale), clip);
    print(liveliestPoint := clip);
    showImageWithSelection(mainImage.render(), growRect(10, clip.positionInImage(mainImage)));
  }
}

Author comment

Began life as a copy of #1032199

download  show line numbers  debug dex  old transpilations   

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

No comments. add comment

Snippet ID: #1032203
Snippet name: Minimal Recognizer [backup]
Eternal ID of this version: #1032203/1
Text MD5: c343d8e8b52eb8d5426a77a556abdbf4
Transpilation MD5: 83cb647ad179ffbb182f80cdcc0f51f9
Author: stefan
Category:
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2021-08-20 05:09:28
Source code size: 5425 bytes / 168 lines
Pitched / IR pitched: No / No
Views / Downloads: 60 / 92
Referenced in: [show references]