Fill() function for negative space

Hi there, I’m looking for a simple way to fill the space AROUND a shape rather than the space WITHIN a shape.

Ideally I’m wanting this function so that when I use OpenCV on a webcam feed, processing puts a square around the face and then blocks out the rest of the image with a sold fill. So all you can see is the image inside the shape.

Increasing the stroke does not do this.

Any help greatly received!

Thanks

Well if you’re going to do that with OpenCV, what you could do is instead of having a square go around the face like I think the default OpenCV Facial Recognition has it, just have it make another shape that goes along with that rectangle, but is super big so it covers your screen. I’m sure you could use PShape for that, so it can be an object. Personally, that is what I would do :grin:

Hope this helps, and I’d be glad to help out further,

EnhancedLoop7

2 Likes

Thats a good point actually! I’ll start with that and see if its what I’m after! Thanks!

1 Like

Hopefully it is, and if not I’d be glad to help out further!

EnhancedLoop7

Maybe check out beginContour()?

1 Like

Sounds like you’re looking for the mask() function:

https://processing.org/reference/PImage_mask_.html

1 Like

Probably not exactly what you need, but your question inspired me to create a simple class to draw inverted shapes :slight_smile: Maybe it can be useful to create what you need.

Inverted inv;
void setup() {
  size(600, 600, P2D);
  frameRate(3);
  inv = new Inverted(width, height, P2D);
}

void draw() {
  inv.fill(random(255), random(80), random(40));
  inv.ellipse(random(width), random(height), 600, 600);
}

class Inverted {
  PGraphics img, mask;
  Inverted(int w, int h, String mode) {
    img = createGraphics(w, h, mode);
    mask = createGraphics(w, h, mode);
  }
  void fill(float r, float g, float b) {
    img.beginDraw();
    img.background(r, g, b);
    img.endDraw();
  }
  void ellipse(float x, float y, float w, float h) {
    mask.beginDraw();
    mask.background(255);
    mask.fill(0);
    mask.ellipse(x, y, w, h);
    mask.endDraw();
    img.mask(mask);
    image(img, 0, 0);
  }
  // one could implement here other methods like
  // colorMode, rect, translate, rotate, scale...
}

2 Likes

@hamoid - interesting! I wasn’t sure how fast mask() is with P2D, although does look like it’s done on the GPU. Still, led me to another thought for doing this with one image and blendMode(REPLACE); and fill(0,0); which allows you to cut out transparent bits of the background.

Inverted inv;
void setup() {
  size(600, 600, P2D);
  frameRate(3);
  inv = new Inverted(width, height, P2D);
}

void draw() {
  inv.fill(random(255), random(80), random(40));
  inv.ellipse(random(width), random(height), 600, 600);
}

class Inverted {
  PGraphics mask;
  Inverted(int w, int h, String mode) {
    mask = createGraphics(w, h, mode);
  }
  void fill(float r, float g, float b) {
    mask.beginDraw();
    mask.background(r, g, b);
    mask.endDraw();
  }
  void ellipse(float x, float y, float w, float h) {
    mask.beginDraw();
    mask.blendMode(REPLACE);
    mask.fill(0,0);
    mask.ellipse(x, y, w, h);
    mask.endDraw();
    image(mask, 0, 0);
  }
  // one could implement here other methods like
  // colorMode, rect, translate, rotate, scale...
}
2 Likes

Very nice @neilcsmith :slight_smile: I was wondering how to do it with one pgraphics.

To improve the antialias, the class can be further tweaked like this:

class Inverted {
  PGraphics mask;
  Inverted(int w, int h, String mode) {
    mask = createGraphics(w, h, mode);
  }
  void fill(float r, float g, float b) {
    mask.beginDraw();
    mask.background(r, g, b);
    mask.blendMode(REPLACE);
    mask.fill(r, g, b, 0);
    mask.noStroke();
    mask.endDraw();
  }
  void ellipse(float x, float y, float w, float h) {
    mask.beginDraw();
    mask.ellipse(x, y, w, h);
    mask.endDraw();
    image(mask, 0, 0);
  }
  // one could implement here other methods like
  // colorMode, rect, translate, rotate, scale...
}

One cool thing of this approach is that it allows you to specify a stroke color and weight in the same pass.

Sorry for diverging a bit from the original question :slight_smile:

3 Likes

Ah, good call - work around Processing’s broken alpha blending! :smile: These should be equivalent (and are in PraxisLIVE).