Horizontal flip on Blob Detection library sketch

edited November 2017 in Library Questions

Hello,

I am using the BlobDetection library for a project and I would like to be able to flip the resulting video horizontally (so that it is like a mirror). I have so far only been able to flip the underlying video, but not the video output that the blobs show on.

I have tried and tried, so if anyone has any insight as to how to accomplish this I would be so grateful!

This is the code I am trying to use to do the flip, but it only works on the underlying video.

  scale (-1,1);
  image(img, -width, height);

This is the entire sketch :

// - Super Fast Blur v1.1 by Mario Klingemann <http://incubator.quasimondo.com>;
// - BlobDetection library

import processing.video.*;
import blobDetection.*;

Capture cam;
BlobDetection theBlobDetection;
PImage img;
boolean newFrame=false;

void setup()
{
  size(640, 480);
  cam = new Capture(this, 40*4, 30*4, 15);
        cam.start();

  // BlobDetection
  // img which will be sent to detection (a smaller copy of the cam frame);
  img = new PImage(80,60); 
  theBlobDetection = new BlobDetection(img.width, img.height);
  scale (-1,1);
  image(img, -width, height);
  theBlobDetection.setPosDiscrimination(true);
  theBlobDetection.setThreshold(0.5f); // will detect bright areas whose luminosity > 0.2f;
}

void captureEvent(Capture cam)
{
  cam.read();
  newFrame = true;
}

void draw()
{
  if (newFrame)
  {
    newFrame=false;
    image(cam,0,0,width,height);
    img.copy(cam, 0, 0, cam.width, cam.height, 
        0, 0, img.width, img.height);
    fastblur(img, 2);
    theBlobDetection.computeBlobs(img.pixels);
    drawBlobsAndEdges(false,true);  

    loadPixels();
  color R =  color (255,0,0);   
  for (int x= 0; x < width; x++){
    int check = 0;
    for (int y = 0; y < height; y++){
     if  (pixels[x+y*width] == R) {
     pixels[x+y*width] = R;
     } else if(x == R){
       //pixels[x+y*width] =

     }
    }
  }
updatePixels();
  }
}

void drawBlobsAndEdges(boolean drawBlobs, boolean drawEdges)
{
  Blob b;
  EdgeVertex eA,eB;
  for (int n=0 ; n<theBlobDetection.getBlobNb() ; n++)
  {
    b=theBlobDetection.getBlob(n);
    if (b!=null)
    {
      // Edges
      if (drawEdges)
      {
        strokeWeight(3);
        fill(0,255,0);
        stroke(255,0,0);
          beginShape();



        for (int m=0;m<b.getEdgeNb();m++)
        {
          eA = b.getEdgeVertexA(m);
          eB = b.getEdgeVertexB(m);
          if (eA !=null && eB !=null){
              vertex(eA.x*width, eA.y*height);
              vertex(eB.x*width, eB.y*height);
          }

        }
        endShape(CLOSE);
      }

      // Blobs
      if (drawBlobs)
      {
        strokeWeight(1);
        stroke(0,255,0);
        rect(
          b.xMin*width,b.yMin*height,
          b.w*width,b.h*height
          );
      }

    }

      }
}

// ==================================================
// Super Fast Blur v1.1
// by Mario Klingemann 
// <http://incubator.quasimondo.com>;
// ==================================================
void fastblur(PImage img,int radius)
{
 if (radius<1){
    return;
  }
  int w=img.width;
  int h=img.height;
  int wm=w-1;
  int hm=h-1;
  int wh=w*h;
  int div=radius+radius+1;
  int r[]=new int[wh];
  int g[]=new int[wh];
  int b[]=new int[wh];
  int rsum,gsum,bsum,x,y,i,p,p1,p2,yp,yi,yw;
  int vmin[] = new int[max(w,h)];
  int vmax[] = new int[max(w,h)];
  int[] pix=img.pixels;
  int dv[]=new int[256*div];
  for (i=0;i<256*div;i++){
    dv[i]=(i/div);
  }

  yw=yi=0;

  for (y=0;y<h;y++){
    rsum=gsum=bsum=0;
    for(i=-radius;i<=radius;i++){
      p=pix[yi+min(wm,max(i,0))];
      rsum+=(p & 0xff0000)>>16;
      gsum+=(p & 0x00ff00)>>8;
      bsum+= p & 0x0000ff;
    }
    for (x=0;x<w;x++){

      r[yi]=dv[rsum];
      g[yi]=dv[gsum];
      b[yi]=dv[bsum];

      if(y==0){
        vmin[x]=min(x+radius+1,wm);
        vmax[x]=max(x-radius,0);
      }
      p1=pix[yw+vmin[x]];
      p2=pix[yw+vmax[x]];

      rsum+=((p1 & 0xff0000)-(p2 & 0xff0000))>>16;
      gsum+=((p1 & 0x00ff00)-(p2 & 0x00ff00))>>8;
      bsum+= (p1 & 0x0000ff)-(p2 & 0x0000ff);
      yi++;
    }
    yw+=w;
  }

  for (x=0;x<w;x++){
    rsum=gsum=bsum=0;
    yp=-radius*w;
    for(i=-radius;i<=radius;i++){
      yi=max(0,yp)+x;
      rsum+=r[yi];
      gsum+=g[yi];
      bsum+=b[yi];
      yp+=w;
    }
    yi=x;
    for (y=0;y<h;y++){
      pix[yi]=0xff000000 | (dv[rsum]<<16) | (dv[gsum]<<8) | dv[bsum];
      if(x==0){
        vmin[y]=min(y+radius+1,hm)*w;
        vmax[y]=max(y-radius,0)*w;
      }
      p1=x+vmin[y];
      p2=x+vmax[y];

      rsum+=r[p1]-r[p2];
      gsum+=g[p1]-g[p2];
      bsum+=b[p1]-b[p2];

      yi+=w;
    }
  }

}

Answers

  • edited November 2017

    ********EDITED, set at the end.

    This previous post is for reference: https://forum.processing.org/two/discussion/comment/95798/#Comment_95798. It seems image() doesn't play well with scale, or I am just not using it correctly.

    For my reference: https://github.com/processing/processing/blob/master/core/src/processing/core/PImage.java#L1654
    https://github.com/processing/processing/blob/master/core/src/processing/core/PImage.java#L1857
    https://github.com/processing/processing/blob/master/core/src/processing/core/PImage.java#L1889
    https://github.com/processing/processing/blob/master/core/src/processing/core/PApplet.java#L12597
    https://github.com/processing/processing/blob/master/core/src/processing/core/PMatrix2D.java#L224

    I have modified your code below. I invert the image before it gets processed by your different or external functions. Notice that additional to your newFrame flag, I have a locking flag to make sure the cam object is intact during the operation. You might not needed at the end...

    Kf

    import processing.video.*;
    import blobDetection.*;
    
    boolean lockAnyCopying=false;
    
    Capture cam;
    BlobDetection theBlobDetection;
    PImage img;
    boolean newFrame=false;
    
    void setup()
    {
      size(640, 480);
      cam = new Capture(this, width/2, height/2, 15);
      cam.start();
    
      // BlobDetection
      // img which will be sent to detection (a smaller copy of the cam frame);
      img = new PImage(80, 60); 
      theBlobDetection = new BlobDetection(img.width, img.height);
      //scale (-1, 1);
      image(img, width, height);
      theBlobDetection.setPosDiscrimination(true);
      theBlobDetection.setThreshold(0.5f); // will detect bright areas whose luminosity > 0.2f;
    }
    
    
    void draw()
    {
      if (newFrame)
      {
        newFrame=false;
        image(cam, 0, 0, width, height);
    
        img=invertNow(cam);
        img.resize(80, 60);
        //img.copy(cam, 0, 0, cam.width, cam.height, 
        //  0, 0, img.width, img.height);
        fastblur(img, 2);    
    
        image(img, 0, 0);
        theBlobDetection.computeBlobs(img.pixels);
        drawBlobsAndEdges(false, true);  
    
        loadPixels();
        color R =  color (255, 0, 0);   
        for (int x= 0; x < width; x++) {
          int check = 0;
          for (int y = 0; y < height; y++) {
            if  (pixels[x+y*width] == R) {
              pixels[x+y*width] = R;
            } else if (x == R) {
              //pixels[x+y*width] =
            }
          }
        }
        updatePixels();
      }
    }
    
    void captureEvent(Capture cam)
    {
    
      if (!lockAnyCopying) {
        cam.read();
        newFrame = true;
      } else
        println("Coying at frame "+frameCount+" was blocked");
    }
    
    
    PImage invertNow(final PImage c1) {
    
      lockAnyCopying=true;
    
      //c1.resize(width, height);
      PImage c2=createImage(c1.width, c1.height, RGB);
      c1.loadPixels();
      c2.loadPixels();
    
      for (int i=0; i<c1.width; i++)
        for (int j=0; j<c1.height; j++) {
          int loc=i+j*c1.width;  //Current pixel location
          int iloc=(c1.width-i-1)+j*c1.width;  //Pixel counting from opposite edge
          c2.pixels[loc]=c1.pixels[iloc];  //Invert pixel positions
        }
    
      c2.updatePixels();
    
      lockAnyCopying=false;
    
      return c2;
    }
    
    void drawBlobsAndEdges(boolean drawBlobs, boolean drawEdges)
    {
      Blob b;
      EdgeVertex eA, eB;
      for (int n=0; n<theBlobDetection.getBlobNb(); n++)
      {
        b=theBlobDetection.getBlob(n);
        if (b!=null)
        {
          // Edges
          if (drawEdges)
          {
            strokeWeight(3);
            fill(0, 255, 0);
            stroke(255, 0, 0);
            beginShape();
    
    
    
            for (int m=0; m<b.getEdgeNb(); m++)
            {
              eA = b.getEdgeVertexA(m);
              eB = b.getEdgeVertexB(m);
              if (eA !=null && eB !=null) {
                vertex(eA.x*width, eA.y*height);
                vertex(eB.x*width, eB.y*height);
              }
            }
            endShape(CLOSE);
          }
    
          // Blobs
          if (drawBlobs)
          {
            strokeWeight(1);
            stroke(0, 255, 0);
            rect(
              b.xMin*width, b.yMin*height, 
              b.w*width, b.h*height
              );
          }
        }
      }
    }
    
    // ==================================================
    // Super Fast Blur v1.1
    // by Mario Klingemann 
    // <<a href="http://incubator.quasimondo.com>;" target="_blank" rel="nofollow">http://incubator.quasimondo.com></a>;
    // ==================================================
    void fastblur(PImage img, int radius)
    {
      if (radius<1) {
        return;
      }
      int w=img.width;
      int h=img.height;
      int wm=w-1;
      int hm=h-1;
      int wh=w*h;
      int div=radius+radius+1;
      int r[]=new int[wh];
      int g[]=new int[wh];
      int b[]=new int[wh];
      int rsum, gsum, bsum, x, y, i, p, p1, p2, yp, yi, yw;
      int vmin[] = new int[max(w, h)];
      int vmax[] = new int[max(w, h)];
      int[] pix=img.pixels;
      int dv[]=new int[256*div];
      for (i=0; i<256*div; i++) {
        dv[i]=(i/div);
      }
    
      yw=yi=0;
    
      for (y=0; y<h; y++) {
        rsum=gsum=bsum=0;
        for (i=-radius; i<=radius; i++) {
          p=pix[yi+min(wm, max(i, 0))];
          rsum+=(p & 0xff0000)>>16;
          gsum+=(p & 0x00ff00)>>8;
          bsum+= p & 0x0000ff;
        }
        for (x=0; x<w; x++) {
    
          r[yi]=dv[rsum];
          g[yi]=dv[gsum];
          b[yi]=dv[bsum];
    
          if (y==0) {
            vmin[x]=min(x+radius+1, wm);
            vmax[x]=max(x-radius, 0);
          }
          p1=pix[yw+vmin[x]];
          p2=pix[yw+vmax[x]];
    
          rsum+=((p1 & 0xff0000)-(p2 & 0xff0000))>>16;
          gsum+=((p1 & 0x00ff00)-(p2 & 0x00ff00))>>8;
          bsum+= (p1 & 0x0000ff)-(p2 & 0x0000ff);
          yi++;
        }
        yw+=w;
      }
    
      for (x=0; x<w; x++) {
        rsum=gsum=bsum=0;
        yp=-radius*w;
        for (i=-radius; i<=radius; i++) {
          yi=max(0, yp)+x;
          rsum+=r[yi];
          gsum+=g[yi];
          bsum+=b[yi];
          yp+=w;
        }
        yi=x;
        for (y=0; y<h; y++) {
          pix[yi]=0xff000000 | (dv[rsum]<<16) | (dv[gsum]<<8) | dv[bsum];
          if (x==0) {
            vmin[y]=min(y+radius+1, hm)*w;
            vmax[y]=max(y-radius, 0)*w;
          }
          p1=x+vmin[y];
          p2=x+vmax[y];
    
          rsum+=r[p1]-r[p2];
          gsum+=g[p1]-g[p2];
          bsum+=b[p1]-b[p2];
    
          yi+=w;
        }
      }
    }
    

    *******EDIT:

    Actually this does it. I just modified the draw() function from my prev example.

    Kf

    void draw()
    {
      if (newFrame)
      {
        newFrame=false;
        image(cam, 0, 0, width, height);
        translate(width, 0); // move to far corner
        scale(-1.0, 1.0);    // flip x-axis backwards
        image(cam, 0, 20, width/2, height);
    
        img=cam.get();
        //img=invertNow(cam);
        img.resize(80, 60);
        //img.copy(cam, 0, 0, cam.width, cam.height, 
        //  0, 0, img.width, img.height);
        fastblur(img, 2);    
    
        //image(img, 0, 0);
        theBlobDetection.computeBlobs(img.pixels);
        drawBlobsAndEdges(false, true);  
    
        loadPixels();
        color R =  color (255, 0, 0);   
        for (int x= 0; x < width; x++) {
          int check = 0;
          for (int y = 0; y < height; y++) {
            if  (pixels[x+y*width] == R) {
              pixels[x+y*width] = R;
            } else if (x == R) {
              //pixels[x+y*width] =
            }
          }
        }
        updatePixels();
      }
    }
    
  • @kfrajer works perfectly, thanks so much! :)

Sign In or Register to comment.