Conversation From Processing to OF


#1

I am currently in the processing of converting code form Processing (Java), to be used for an OF project. I have would know if anyone has any replacement for the following:

index = constrain (index, 0, ofGetWidth() * ofGetHeight() - 1);

And

 float pixelBrightness = brightness(video.pixels[index])

Can I just replace it with this?

float pixelBrightness = brightness(vidGrabber.getPixels());
//vidGrabber would be instead of .video

There is the processing code:

// Text Rain (Processing Re-Code "cover version")
// Original by Camille Utterback and Romy Achituv (1999):
// http://camilleutterback.com/projects/text-rain/
// Implemented in Processing 2.0b7 by Golan Levin, January 2013
// This assumes that the participant is in front of a light-colored background. 


//===================================================================
// The live video camera Capture object:
import processing.video.*;
Capture video;

float letterGravity = 1.0;
int brightnessThreshold = 100;
float initialLetterYPosition = 10;
TextRainLetter poemLetters[];
int nLetters;

//-----------------------------------
void setup() {
  size (320,240); 
  
  // 640x480 is also a good option, but 320x240 is faster.
  // Note: this implementation of TextRain assumes that the camera capture 
  // is at the same resolution as the Processing canvas.
  video = new Capture (this, width,height);
  video.start();  

  String poemString = "A poem about bodies"; 
  // Camille provides the actual poem in her documentation online. 
  
  nLetters = poemString.length();
  poemLetters = new TextRainLetter[nLetters];
  for (int i=0; i<nLetters; i++) {
    char c = poemString.charAt(i);
    float x = width * ((float)(i+1)/(nLetters+1));
    float y = initialLetterYPosition;
    poemLetters[i] = new TextRainLetter(c,x,y);
  }
}

//-----------------------------------
void draw() {
  if (video.available()) {
    video.read();
    video.loadPixels();
    
    // this translate & scale flips the video left/right. 
    pushMatrix();
    translate (width,0); 
    scale (-1,1);
    image (video, 0, 0, width, height);
    popMatrix();
    
    for (int i=0; i<nLetters; i++) {
      poemLetters[i].update();
      poemLetters[i].draw();
    }
  }
}

//-----------------------------------
void keyPressed() {
  if (key == CODED) {
    if (keyCode == UP) {
      brightnessThreshold = min(255, brightnessThreshold+1);
      println("brightnessThreshold = " + brightnessThreshold); 
    } else if (keyCode == DOWN) {
      brightnessThreshold = max(0, brightnessThreshold-1);
      println("brightnessThreshold = " + brightnessThreshold);
    } 
  } else if (key == ' '){
    // pressing the spacebar reset the letters to the top of the canvas.
    for (int i=0; i<nLetters; i++) {
      poemLetters[i].reset();
    }
  }
}


//===================================================================
class TextRainLetter {
  // A class to contain a single letter in the TextRain poem. 
  // Basically, a particle that associates a position and a char.
  
  char  c;
  float x; 
  float y;
  
  TextRainLetter (char cc, float xx, float yy) {
    c = cc;
    x = xx;
    y = yy;
  }

  //-----------------------------------
  void update() {
    // Update the position of a TextRainLetter. 
    
    // 1. Compute the pixel index corresponding to the (x,y) location of the TextRainLetter.
    int flippedX = (int)(width-1-x); // because we have flipped the video left/right.
    int index = width*(int)y + flippedX;
    index = constrain (index, 0, width*height-1);
    
    // Establish a grayscale range around the threshold, 
    // within which motion is not required.
    int thresholdTolerance = 5;
    int thresholdLo = brightnessThreshold - thresholdTolerance;
    int thresholdHi = brightnessThreshold + thresholdTolerance;

    // 2. Fetch the color of the pixel there, and compute its brightness.
    float pixelBrightness = brightness(video.pixels[index]);
    
    // 3. If the TextRainLetter is in a bright area, move downwards.
    //    If it's in a dark area, move up until we're in a light area.
    if (pixelBrightness > thresholdHi) {
      y += letterGravity; //move downward
      
    } else {
      while ((y > initialLetterYPosition) && (pixelBrightness < thresholdLo)){
        y -= letterGravity; // travel upwards intil it's bright again
        index = width*(int)y + flippedX;
        index = constrain (index, 0, width*height-1);
        pixelBrightness = brightness(video.pixels[index]);
      }
    }
    
    if ((y >= height-1) || (y < initialLetterYPosition)){
      y = initialLetterYPosition;
    }
  }
  
  //-----------------------------------
  void reset(){
    y = initialLetterYPosition;
  }

  //-----------------------------------
  void draw() {
    // Draw the letter. Use a simple black "drop shadow"
    // to achieve improved contrast for the typography. 
    fill(0,0,0);
    text (""+c, x+1,y+1); 
    text (""+c, x-1,y+1); 
    text (""+c, x+1,y-1); 
    text (""+c, x-1,y-1); 
    fill(255,255,255);
    text (""+c, x,y);
  }
}

#2

Hi and welcome to the forum!

OF has a similar constrain function to Processing: ofClamp. So you can do:

index = ofClamp(index, 0, ofGetWidth() * ofGetHeight() - 1);  

Regarding the brightness, you are in the right track but need to go a few steps forward:

float pixelBrightness = vidGrabber.getPixels().getColor(index).getBrightness();

By doing getPixels() you are accessing the full array of pixels.
Then you need to say which pixel you want to get info from, getColor(). You can do it by index or (x and y) positions.
And only then you can say getBrightness().

This is a very descriptive way of getting the data you need. You can check other ways in the examples/video folder that comes with OF.

And that’s it! Any other questions, feel free!


#3

Thank you for the response and for the warm welcome!

I am currently working on converting a TextRain from processing to an OF project. Another question I had was able how the class TextRainLetter and how its being handled in the code.

Below is my ofApp.cpp and ofApp.h.

Here are some of the questions I had or confusion I have:

  • I am not understanding what my variables that were initialized in my .h not being read in my .cpp. Looking at the processing file, is this different in scope?
    These were things that were called undeclared:
    -brightnessThreshold
    -vidGrabber
    -letterGravity
    -initialLetterYPosition
    -Basically all the variables.

Processing file is on the previous post

 nLetters = poemString.length();
    poemLetters = new TextRainLetter[nLetters];
    for (int i=0; i<nLetters; i++) {
        char c = poemString.at(i);
        float x = width * ((float)(i+1)/(nLetters+1));
        float y = initialLetterYPosition;
        poemLetters[i] = new TextRainLetter (c,x,y);
    }
}
  • TextRainLetter is being said it is not the right name although I did initialize it in my .h file

This is my ofApp.cpp

#include "ofApp.h"
#include <string>

//--------------------------------------------------------------
void ofApp::setup() {
    
    vidGrabber.initGrabber(1280, 720);
    
    // 640x480 is also a good option, but 320x240 is faster.
    // Note: this implementation of TextRain assumes that the camera capture
    // is at the same resolution as the Processing canvas.
//    video = new Capture (this, width,height);
//    video.start();
    
    string poemString = "A poem about bodies";
    // Camille provides the actual poem in her documentation online.
    
    nLetters = poemString.length();
    poemLetters = new TextRainLetter[nLetters];
    for (int i=0; i<nLetters; i++) {
        char c = poemString.at(i);
        float x = width * ((float)(i+1)/(nLetters+1));
        float y = initialLetterYPosition;
        poemLetters[i] = new TextRainLetter (c,x,y);
    }
}

class TextRainLetter {
    // A class to contain a single letter in the TextRain poem.
    // Basically, a particle that associates a position and a char.
    
    char  c;
    float x;
    float y;
    
    TextRainLetter (char cc, float xx, float yy) {
        c = cc;
        x = xx;
        y = yy;
    }
    
    //-----------------------------------
    void update() {
        // Update the position of a TextRainLetter.
        
        // 1. Compute the pixel index corresponding to the (x,y) location of the TextRainLetter.
        int flippedX = (int)(ofGetWidth() - 1 - x); // because we have flipped the video left/right.
        int index = ofGetWidth() *(int)y + flippedX;
        index = ofClamp(index, 0, ofGetWidth() * ofGetHeight() - 1);
        
        // Establish a grayscale range around the threshold,
        // within which motion is not required.
        int thresholdTolerance = 5;
        int thresholdLo = brightnessThreshold - thresholdTolerance;
        int thresholdHi = brightnessThreshold + thresholdTolerance;
        
        // 2. Fetch the color of the pixel there, and compute its brightness.
      //  float pixelBrightness = brightness(video.pixels[index]);
        float pixelBrightness = vidGrabber.getPixels().getColor(index).getBrightness();
        
        // 3. If the TextRainLetter is in a bright area, move downwards.
        //    If it's in a dark area, move up until we're in a light area.
        if (pixelBrightness > thresholdHi) {
            y += letterGravity; //move downward
            
        } else {
            while ((y > initialLetterYPosition) && (pixelBrightness < thresholdLo)){
                y -= letterGravity; // travel upwards intil it's bright again
                index = ofGetWidth() *(int)y + flippedX;
                index = ofClamp(index, 0, ofGetWidth() * ofGetHeight() - 1);
                pixelBrightness = brightness(video.pixels[index]);
            }
        }
        
        if ((y >= ofGetHeight()-1) || (y < initialLetterYPosition)){
            y = initialLetterYPosition;
        }
    }
    
    //-----------------------------------
    void reset(){
        y = initialLetterYPosition;
    }
    
    //-----------------------------------
    void draw() {
//        // Draw the letter. Use a simple black "drop shadow"
//        // to achieve improved contrast for the typography.
//        fill(0,0,0);
//        text (""+c, x+1,y+1);
//        text (""+c, x-1,y+1);
//        text (""+c, x+1,y-1);
//        text (""+c, x-1,y-1);
//        fill(255,255,255);
//        text (""+c, x,y);
    }
};


//--------------------------------------------------------------
void ofApp::update(){
    vidGrabber.update();
}

//--------------------------------------------------------------
void ofApp::draw(){
    if (video.available()) {
        video.read();
        video.loadPixels();
        
        // this translate & scale flips the video left/right.
        pushMatrix();
        translate (width,0);
        scale (-1,1);
        image (video, 0, 0, width, height);
        popMatrix();
        
        for (int i=0; i<nLetters; i++) {
            poemLetters[i].update();
            poemLetters[i].draw();
        }
    }
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key){
    if (key == OF_KEY_UP) {
        brightnessThreshold = min(255, brightnessThreshold + 1);
        cout << "Brightness Threshold:" << brightnessThreshold << endl;
    } else if (key == OF_KEY_DOWN) {
        brightnessThreshold = max(0, brightnessThreshold - 1);
        cout << "Brightness Threshold:" << brightnessThreshold << endl;
    } else if (key == 49){
        for (int i = 0; i < nLetters; i++) {
            poemLetters[i].reset();
        }
    }
}

//--------------------------------------------------------------
void ofApp::keyReleased(int key){

}

//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y ){

}

//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseEntered(int x, int y){

}

//--------------------------------------------------------------
void ofApp::mouseExited(int x, int y){

}

//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){

}

//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){

}

//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){ 

}

This is my OfApp.h
#pragma once

#include "ofMain.h"

class ofApp : public ofBaseApp{

	public:
		void setup();
		void update();
		void draw();

		void keyPressed(int key);
		void keyReleased(int key);
		void mouseMoved(int x, int y );
		void mouseDragged(int x, int y, int button);
		void mousePressed(int x, int y, int button);
		void mouseReleased(int x, int y, int button);
		void mouseEntered(int x, int y);
		void mouseExited(int x, int y);
		void windowResized(int w, int h);
		void dragEvent(ofDragInfo dragInfo);
		void gotMessage(ofMessage msg);
    
    float letterGravity = 1.0;
    int brightnessThreshold = 100;
    float initialLetterYPosition = 10;
    TextRainLetter poemLetters[];
    int nLetters;
		
};

#4

Imagine that these files are like paper and what you write is like a story. When you do include you are kind of grabbing whatever you wrote on that specific file and place it there. And the story has to make sense, this is not a David Lynch language. : )

So when you write your class in the middle of the ofApp.cpp file, the ofApp.h file as no ideia what you are talking about. This is because you are including ofApp.h in ofApp.cpp before your class definition.

You can do a few things. For example, you can write your class in ofApp.h after #include “ofMain.h” and before the definition of ofApp. So when you call it, it knows what you are talking about.

Or you can create an TextRainLetter.h file (or both .h and .cpp files) in the src folder, add them to the project, place your code there and after #include “ofMain.h” you do #include “TextRainLetter.h”.

These questions are related to C++ in general, not to openFrameworks. You can learn a bit more about C++ in websites like this one, check other users questions on StackOverflow, or also on Youtube playlists like this.

But don’t feel like you can’t ask C++ questions here. : )