AxeFire
AxeFire

Reputation: 11

Detecting when a PNG image has been "wiped transparent" in Processing?

i'm trying to create a game using Kinect where you have to use your hand movements to wipe away an image to make it disappear revealing another image beneath it within 30 seconds. Now I have already done the code for the loosing condition where if you do not wipe away the image under 30 seconds, the loosing screen will pop up.

However, I am not sure how to code the part to detect when the entire PNG image has been "wiped away". Does this involve using get()? I am not sure how to approach this.

Imagine there are 2 Pimages moondirt.png and moonsurface.png

The Kinect controls the wiping and making Pimage moondirt.png transparent to reveal moonsurface.png

void kinect() {

//----------draw kinect------------

  // Draw moon surface
  image(moonSurface, 0, 0, width, height);

  // Draw the moon dirt
  image(moonDirt, 0, 0, width, height);

  // Threshold the depth image
  int[] rawDepth = kinect.getRawDepth();
  for (int i=0; i < rawDepth.length; i++) {
    if (rawDepth[i] >= minDepth && rawDepth[i] <= maxDepth) {
      depthImg.pixels[i] = color(255);
      maskingImg.pixels[i] = color(255);
    } else {
      depthImg.pixels[i] = color(0);
    }
  }

  //moonDirt.resize(640, 480);  //(640, 480);
  moonDirt.loadPixels();
  for (int i=0; i < rawDepth.length; i++) {
    if ( maskingImg.pixels[i] == color(255) ) {
      moonDirt.pixels[i] = color( 0, 0, 0, 0 );
    }
  }

  moonDirt.updatePixels();

  image(moonDirt, 0, 0, width, height); 
   color c = moonDirt.get(width, height);

updatePixels();

     //--------timer-----     
if (countDownTimer.complete() == true){
  if (timeLeft > 1 ) {
      timeLeft--;
      countDownTimer.start();
    } else {
      state = 4;
          redraw();
    }
  }
  //show countDown TIMER
  String s = "Time Left: " + timeLeft;
  textAlign(CENTER);     
  textSize(30);
  fill(255,0,0);
  text(s, 380, 320);

}

//timer
class Timer {
  int startTime;
  int interval;

  Timer(int timeInterval) {
    interval = timeInterval;
  }

  void start() {
    startTime = millis();
  }

  boolean complete() {
    int elapsedTime = millis() - startTime;
    if (elapsedTime > interval) {
      return true;
    }else {
      return false;
    }
  }
}

Upvotes: 1

Views: 47

Answers (1)

George Profenza
George Profenza

Reputation: 51837

I see the confusion in this section:

moonDirt.loadPixels();
  for (int i=0; i < rawDepth.length; i++) {
    if ( maskingImg.pixels[i] == color(255) ) {
      moonDirt.pixels[i] = color( 0, 0, 0, 0 );
    }
  }

  moonDirt.updatePixels();

  image(moonDirt, 0, 0, width, height); 
  color c = moonDirt.get(width, height);

You are already using pixels[] which is more efficient than get() which is great. Don't forget to call updatePixels() when you're done. You already do that for moonDirt, but not for maskingImg

If you want to find out if an image has been cleared (where clear means transparent black (color(0,0,0,0)) in this case).

It looks like you're already familiar with functions that take parameters and return values. The count function will need to:

  1. take 2 arguments: the image to process and the colour to check and count
  2. return the total count
  3. iterate through all pixels: if any pixels match the 2nd argument, the total count increments

Something like this:

/**
*  countPixels - counts pixels of of a certain colour within an image
* @param image - the PImage to loop through
* @param colorToCount - the colour to count pixels present in the image
* return int - the number of found pixels (between 0 and image.pixels.length)
*/
int countPixels(PImage image,color colorToCount){
  // initial transparent black pixel count
  int count = 0;
  // make pixels[] available
  image.loadPixels();
  // for each pixel
  for(int i = 0 ; i < image.pixels.length; i++){
    // check if it's transparent black
    if(image.pixels[i] == colorToCount){
      // if so, increment the counter
      count++; 
    }
  }
  // finally return the count
  return count;
}

Within your code you could use it like so: ...

// Threshold the depth image
  int[] rawDepth = kinect.getRawDepth();
  for (int i=0; i < rawDepth.length; i++) {
    if (rawDepth[i] >= minDepth && rawDepth[i] <= maxDepth) {
      depthImg.pixels[i] = color(255);
      maskingImg.pixels[i] = color(255);
    } else {
      depthImg.pixels[i] = color(0);
    }
  }
  maskingImg.updatePixels();


  //moonDirt.resize(640, 480);  //(640, 480);
  moonDirt.loadPixels();
  for (int i=0; i < rawDepth.length; i++) {
    if ( maskingImg.pixels[i] == color(255) ) {
      moonDirt.pixels[i] = color( 0, 0, 0, 0 );
    }
  }

  moonDirt.updatePixels();

  image(moonDirt, 0, 0, width, height); 

  int leftToReveal = moonDirt.pixels.length;
  int revealedPixels = countPixels(moonDirt,color(0,0,0,0));
  int percentageClear = round(((float)revealedPixels / leftToReveal) * 100);
  println("revealed " + revealedPixels + " of " + leftToReveal + " pixels -> ~" + percentageClear + "% cleared");

...

You have the option to set the condition for all pixels to be cleared or a ratio/percentage (e.g. if more 90% is clear, that's good enough) to then change the game state accordingly.

Upvotes: 1

Related Questions