Help translating Processing PImage code

Hi,

What would it be the equivalent OF code from this Processing snippet:

  
loadPixels();  
System.arraycopy(pixels, 0, canvas.pixels, 0, pixels.length);  
updatePixels();  

and

  
int pixel  = water.pixels[offset];   
pixels[y * width + x] = pixel;  

Where:
pixels[] is http://processing.org/reference/pixels.html
water is a PImage http://processing.org/reference/PImage.html

Any help will be much appreciated

Something like this pseudo-ish code:

  
// declare canvas pointer earlier  
  
ofImage screenImg;  
  
screenImg.grabScreen(0, 0, ofGetWidth(), ofGetHeight());  
  
unsigned char * pixels = screenImg.getPixels();  
  
for(int i = 0; i < YourPixelAmts; i++){  
  pixels[i] = canvas[i];  
}  
  
screenImg.update();  
screenImg.draw(0, 0, ofGetWidth(), ofGetHeight());  

and

  
unsigned char * waterpixels = water.getPixels();  
  
unsigned char pixel = waterpixels[offset];  
  
pixels[y * width + x] = pixel;  

Off the top of my head, but this should point you in the right direction. The snippet’s not much to go off, but I think I understand what you’re trying to do.

why pixels as unsigned char?

unsigned char is just a very light way to represent data between 0 and 255, i.e. the color of a particular pixel. The array of data is 3 values (RGB) for each pixel. Generally for speed purposes you want to use the lightest data type that still contains all the required data, so in this case the unsigned char is the best match.

@astellato thanks! I am trying to do the water ripple effect in OF, I have a working sketch in Processing which is a modified version of this one http://www.openprocessing.org/visuals/?visualID=668

For some reason I get 3 small images when I click and drag (check attach image)

It most be related to my pixel data manipulation, still difficult to digest how to translate the code, so this is what I do in P5

  
void setup() {  
  size(640, 480);  
    
  bgImg = loadImage("test-image.jpg");  
    
  canvas = createImage(width, height, RGB);  
  ripples = new Ripple(canvas);  
}  
  
void draw() {  
  background(bgImg);  
    
  refreshCanvas();  
  ripples.update();  
}  
  
void refreshCanvas() {  
  loadPixels();  
  System.arraycopy(pixels, 0, canvas.pixels, 0, pixels.length);  
  updatePixels();  
}  
  
void mouseDragged() {  
   ripples.makeTurbulence(mouseX, mouseY);  
}  

the ripple class is

  
class Ripple {  
  
  int heightMap[][][];  
  int space;   
  int radius, heightMax, density;   
  int page = 0;   
    
  float turbulence = 100.0f;  
    
  PImage water;  
  
  Ripple(PImage _water) {  
    water   = _water;  
    density = 6;   
    radius  = 30;   
    space   = width * height - 1;   
      
    initMap();  
  }  
  
  void update() {  
    waterFilter();   
    updateWater();  
    page ^= 1;   
  }  
  
  void initMap() {   
    // the height map is made of two "pages"   
    // one to calculate the current state, and another to keep the previous state  
    heightMap = new int[2][width][height];   
  }   
  
  void makeTurbulence(int cx, int cy) {  
    int r       = radius * radius;   
    int left    = cx < radius ? -cx + 1 : -radius;   
    int right   = cx > (width - 1) - radius ? (width - 1) - cx : radius;   
    int top     = cy < radius ? -cy + 1 : -radius;   
    int bottom  = cy > (height - 1) - radius ? (height - 1) - cy : radius;   
  
    for (int x = left; x < right; x++) {   
      int xsqr = x * x;   
      for (int y = top; y < bottom; y++) {   
        if (xsqr + (y * y) < r)  
          heightMap[page][cx + x][cy + y] += turbulence;  
      }  
    }   
  }  
  
  void waterFilter() {   
    for (int x = 0; x < width; x++) {   
      for (int y = 0; y < height; y++) {   
        int n = y - 1 < 0 ? 0 : y - 1;   
        int s = y + 1 > height - 1 ? height - 1 : y + 1;   
        int e = x + 1 > width - 1 ? width - 1 : x + 1;   
        int w = x - 1 < 0 ? 0 : x - 1;   
        int value = ((heightMap[page][w][n] + heightMap[page][x][n]   
                    + heightMap[page][e][n] + heightMap[page][w][y]   
                    + heightMap[page][e][y] + heightMap[page][w][s]   
                    + heightMap[page][x][s] + heightMap[page][e][s]) >> 2)   
                    - heightMap[page^1][x][y];  
  
        heightMap[page^1][x][y] = value - (value >> density);   
      }   
    }   
  }  
  
  void updateWater() {   
    loadPixels();  
    for (int y = 0; y < height - 1; y++) {   
      for (int x = 0; x < width - 1; x++) {  
        int deltax  = heightMap[page][x][y] - heightMap[page][x + 1][y];   
        int deltay  = heightMap[page][x][y] - heightMap[page][x][y + 1];   
        int offsetx = (deltax >> 3) + x;   
        int offsety = (deltay >> 3) + y;   
  
        offsetx = (offsetx > width) ? width - 1 : (offsetx < 0) ? 0 : offsetx;   
        offsety = (offsety > height) ? height - 1 : (offsety < 0) ? 0 : offsety;   
  
        int offset = (offsety * width) + offsetx;   
        offset     = (offset < 0) ? 0 : (offset > space) ? space : offset;  
        int pixel  = water.pixels[offset];   
        pixels[y * width + x] = pixel;   
      }   
    }   
    updatePixels();   
  }  

For OF I am not using a ripple class instead I am doing everything in the testApp until I get it working, here it is

testApp.h

  
void waterFilter();  
void updateWater();  
void makeTurbulence( int x, int y );  
	  
int heightMap[2][640][480];  
	  
int space;  
int radius;  
int heightMax;  
int density;  
int page;  
	  
float turbulence;  
	  
unsigned char *pixels;  
	  
ofImage screenImage;  
ofImage water;  
ofImage canvas;  

testApp.cpp

  
void testApp::setup(){  
	page		= 0;  
	density	= 6;  
	radius	= 30;  
	space		= ofGetWidth() * ofGetHeight() - 1;  
	  
	turbulence = 100.0f;  
	  
	canvas.loadImage( "water.gif" );  
	water.allocate( 640, 480, OF_IMAGE_COLOR );  
	water.setFromPixels( canvas.getPixels(), 640, 480, OF_IMAGE_COLOR, true );  
}  
  
void testApp::update(){  
	//water.setFromPixels( pixels, 640, 480, OF_IMAGE_COLOR, true );  
	  
	waterFilter();  
	updateWater();  
	  
	page ^= 1;  
}  
  
void testApp::draw(){  
	/*screenImage.grabScreen( 0, 0, ofGetWidth(), ofGetHeight() );  
	pixels = screenImage.getPixels();  
	for ( int i = 0; i < ofGetWidth()*ofGetHeight(); i++ ) {  
		pixels[i] = canvas.getPixels()[i];  
	}  
	screenImage.update();  
	screenImage.draw( 0, 0, ofGetWidth(), ofGetHeight() );  
	*/  
	  
	water.update();  
	water.draw( 0, 0, ofGetWidth(), ofGetHeight() );  
}  
  
void testApp::waterFilter() {  
	for ( int x = 0; x < ofGetWidth(); x++ ) {  
		for ( int y = 0; y < ofGetHeight(); y++ ) {  
			int n = y - 1 < 0 ? 0 : y - 1;  
			int s = y + 1 > ofGetHeight() - 1 ? ofGetHeight() - 1 : y + 1;  
			int e = x + 1 > ofGetWidth() - 1 ? ofGetWidth() - 1 : x + 1;  
			int w = x - 1 < 0 ? 0 : x - 1;  
			  
			int value = ((heightMap[page][w][n] + heightMap[page][x][n]  
						+ heightMap[page][e][n] + heightMap[page][w][y]  
						+ heightMap[page][e][y] + heightMap[page][w][s]  
						+ heightMap[page][x][s] + heightMap[page][e][s]) >> 2)  
						- heightMap[page^1][x][y];  
			  
			heightMap[page^1][x][y] = value - (value >> density);  
		}  
	}  
}  
  
void testApp::updateWater() {  
	for ( int y = 0; y < ofGetHeight() - 1; y++ ) {  
		for ( int x = 0; x < ofGetWidth() - 1; x++ ) {  
			int deltaX	= heightMap[page][x][y] - heightMap[page][x + 1][y];  
			int deltaY	= heightMap[page][x][y] - heightMap[page][x][y + 1];  
			int offsetX	= (deltaX >> 3) + x;  
			int offsetY = (deltaY >> 3) + y;  
			  
			offsetX = (offsetX > ofGetWidth()) ? ofGetWidth() - 1 : (offsetX < 0) ? 0 : offsetX;  
			offsetY = (offsetY > ofGetHeight()) ? ofGetHeight() - 1 : (offsetY < 0) ? 0 : offsetY;  
			  
			int offset	= (offsetY * ofGetWidth()) + offsetX;  
			offset		= (offset < 0) ? 0 : (offset > space) ? space : offset;  
			  
			unsigned char pixel	= water.getPixels()[offset];  
			pixels				= water.getPixels();  
			pixels[y * ofGetWidth() + x] = pixel;  
		}  
	}  
}  
  
void testApp::makeTurbulence( int cx, int cy ) {  
	int r		= radius * radius;  
	int left	= cx < radius ? -cx + 1 : -radius;  
	int right	= cx > (ofGetWidth() - 1) -radius ? (ofGetWidth() - 1) - cx : radius;  
	int top	= cy < radius ? -cy + 1 : -radius;  
	int bottom	= cy > (ofGetHeight() - 1) -radius ? (ofGetHeight() - 1) - cy : radius;  
	  
	for ( int x = left; x < right; x++ ) {  
		int xsqrt = x * x;  
		for ( int y = top; y < bottom; y++ ) {  
			if ( xsqrt + (y * y) < r ) {  
				heightMap[page][cx+x][cy+y] += turbulence;  
			}  
		}  
	}  
}  

Any help on the pixels data will be much appreciated

@nardove - Sorry, I was assuming a monochrome image. Some updated code follows with some very useful methods which come from the Pixel by Pixel course in OpenFrameworks.

When you are dealing with an RGB image, you have to use a slightly different math.

thisPixel = 3*(w * vertical + horizontal);

Your index should be multiplied by the number of colors. If you were using rgba the 3 should be 4 instead.

Here’s the code that works for my machine:

testApp.h

  
#ifndef _TEST_APP  
#define _TEST_APP  
  
// Pixel by Pixel Course Methods courtesy Danny Rozin  
// [http://itp.nyu.edu/varwiki/Syllabus/Pixels-S09](http://itp.nyu.edu/varwiki/Syllabus/Pixels-S09)  
  
#include "ofMain.h"  
  
class testApp : public ofBaseApp{  
  
	public:  
		void setup();  
		void update();  
		void draw();  
  
		void mouseDragged(int x, int y, int button);  
	  
		//*********************************************** Pixel by Pixel course method prototypes **************************************************************  
		void setPixel(int horizontal,int vertical,unsigned char R,unsigned char G,unsigned char B,int width, unsigned char pixels[]);  
		void setPixel(int horizontal,int vertical,unsigned char R,unsigned char G,unsigned char B,unsigned char A,int width, unsigned char pixels[]);  
		void getPixel(int horizontal,int vertical,unsigned char* R,unsigned char* G,unsigned char* B,int width, unsigned char  pixels[]);  
		void getPixel(int horizontal,int vertical,unsigned char* R,unsigned char* G,unsigned char* B,unsigned char* A,int width, unsigned char  pixels[]);  
	  
		void waterFilter();  
		void updateWater();  
		void makeTurbulence( int x, int y );  
	  
		int heightMap[2][640][480];  
	  
		int space;  
		int radius;  
		int heightMax;  
		int density;  
		int page;  
	  
		float turbulence;  
	  
		unsigned char *pixels;  
	  
		ofImage water;  
		ofImage canvas;  
};  
  
#endif  
  

testApp.cpp

  
#include "testApp.h"  
  
void testApp::setup(){  
	page		= 0;  
	density	= 6;  
	radius	= 30;  
	space		= ofGetWidth() * ofGetHeight() - 1;  
	  
	turbulence = 100.0f;  
	  
	canvas.loadImage( "test_image.jpg" );  
	water.allocate( 640, 480, OF_IMAGE_COLOR );  
	water.setFromPixels( canvas.getPixels(), 640, 480, OF_IMAGE_COLOR, true );  
	  
	for(int i = 0; i < 2; i++){  
		for(int j = 0; j < 640; j++){  
			for(int k = 0; k < 480; k++){  
				heightMap[i][j][k] = 0;  
			}  
		}  
	}  
}  
  
void testApp::update(){  
	waterFilter();  
	updateWater();  
	  
	page ^= 1;  
}  
  
void testApp::draw(){  
	water.update();  
	water.draw( 0, 0, ofGetWidth(), ofGetHeight() );  
}  
  
void testApp::waterFilter() {  
	for ( int x = 0; x < ofGetWidth(); x++ ) {  
		for ( int y = 0; y < ofGetHeight(); y++ ) {  
			int n = y - 1 < 0 ? 0 : y - 1;  
			int s = y + 1 > ofGetHeight() - 1 ? ofGetHeight() - 1 : y + 1;  
			int e = x + 1 > ofGetWidth() - 1 ? ofGetWidth() - 1 : x + 1;  
			int w = x - 1 < 0 ? 0 : x - 1;  
			  
			int value = ((heightMap[page][w][n] + heightMap[page][x][n]  
						  + heightMap[page][e][n] + heightMap[page][w][y]  
						  + heightMap[page][e][y] + heightMap[page][w][s]  
						  + heightMap[page][x][s] + heightMap[page][e][s]) >> 2)  
							- heightMap[page^1][x][y];  
			  
			heightMap[page^1][x][y] = value - (value >> density);  
		}  
	}  
}  
  
void testApp::updateWater() {  
	unsigned char * canvasPixels = canvas.getPixels();  
	unsigned char r, g, b;  
	for ( int y = 0; y < ofGetHeight() - 1; y++ ) {  
		for ( int x = 0; x < ofGetWidth() - 1; x++ ) {  
			int deltaX	= heightMap[page][x][y] - heightMap[page][x + 1][y];  
			int deltaY	= heightMap[page][x][y] - heightMap[page][x][y + 1];  
			int offsetX	= (deltaX >> 3) + x;  
			int offsetY = (deltaY >> 3) + y;  
			  
			offsetX = (offsetX > ofGetWidth()) ? ofGetWidth() - 1 : (offsetX < 0) ? 0 : offsetX;  
			offsetY = (offsetY > ofGetHeight()) ? ofGetHeight() - 1 : (offsetY < 0) ? 0 : offsetY;  
			  
			  
			int offset	= (offsetY * ofGetWidth()) + offsetX;  
			offset		= (offset < 0) ? 0 : (offset > space) ? space : offset;  
			pixels				= water.getPixels();  
			  
			getPixel(offsetX, offsetY, &r, &g, &b, ofGetWidth(), canvasPixels);  
			setPixel(x, y, r, g, b, ofGetWidth(), pixels);  
		}  
	}  
}  
  
void testApp::makeTurbulence( int cx, int cy ) {  
	int r		= radius * radius;  
	int left	= cx < radius ? -cx + 1 : -radius;  
	int right	= cx > (ofGetWidth() - 1) -radius ? (ofGetWidth() - 1) - cx : radius;  
	int top	= cy < radius ? -cy + 1 : -radius;  
	int bottom	= cy > (ofGetHeight() - 1) -radius ? (ofGetHeight() - 1) - cy : radius;  
	  
	for ( int x = left; x < right; x++ ) {  
		int xsqr = x * x;  
		for ( int y = top; y < bottom; y++ ) {  
			if ( xsqr + (y * y) < r ) {  
				heightMap[page][cx+x][cy+y] += turbulence;  
			}  
		}  
	}  
}  
  
//--------------------------------------------------------------  
void testApp::mouseDragged(int x, int y, int button){  
	makeTurbulence(x, y);  
}  
  
//**********************  Pixel by Pixel course method that sets a pixel RGB in an x, y position in a pixel array ***********************  
  
void testApp::setPixel(int horizontal,int vertical,unsigned char R,unsigned char G,unsigned char B,int w, unsigned char pixels[]){  
	int thisPixel;  
	thisPixel = 3*(w * vertical +horizontal);  
	pixels[thisPixel]=R;  
	pixels[thisPixel+1]=G;  
	pixels[thisPixel+2]=B;  
}  
  
//**********************  Pixel by Pixel course method that sets a pixel RGBA in an x, y position in a pixel array ***********************  
  
void testApp::setPixel(int horizontal,int vertical,unsigned char R,unsigned char G,unsigned char B,unsigned char A,int w, unsigned char pixels[]){  
	int thisPixel;  
	thisPixel = 4*(w * vertical +horizontal);  
	pixels[thisPixel]=R;  
	pixels[thisPixel+1]=G;  
	pixels[thisPixel+2]=B;  
	pixels[thisPixel+3]=A;  
}  
  
  
//**********************  Pixel by Pixel course method that sets a pixel RGB in an x, y position in a pixel array ************************  
  
void testApp::getPixel(int horizontal,int vertical,unsigned char* R,unsigned char* G,unsigned char* B,int w, unsigned char pixels[]){  
	int thisPixel;  
	thisPixel = 3*(w * vertical +horizontal);  
	*R= pixels[thisPixel];  
	*G= pixels[thisPixel+1];  
	*B= pixels[thisPixel+2];  
}  
  
//**********************  Pixel by Pixel course method that sets a pixel RGBA in an x, y position in a pixel array ************************  
  
void testApp::getPixel(int horizontal,int vertical,unsigned char* R,unsigned char* G,unsigned char* B,unsigned char* A,int w, unsigned char pixels[]){  
	int thisPixel;  
	thisPixel = 4*(w * vertical +horizontal);  
	*R= pixels[thisPixel];  
	*G= pixels[thisPixel+1];  
	*B= pixels[thisPixel+2];  
	*A= pixels[thisPixel+3];  
}  
  
  

Sweet algorithm for the ripples, is it yours?

@astellato you’re the man! thanks a lot for helping me out I am learning lots form this code

This algorithm is a modification from this one http://www.openprocessing.org/visuals/?visualID=668 is pretty much the same I remove the extra bits and leave the bare bones to get it working

I want to learn how to hardware accelerate this code, so if anyone can provide any information regarding what I need to do will be much appreciated, my knowledge of OpenGL and computer graphic techniques is on a beginner level but once I get pointed in the right direction I manage to get by, so any comments are welcome.

Cheers

  • rS