Altering images for later recall

edited January 2014 in How To...

Hi All,
Funny, but I can't seem to find this anywhere on the forums/web: I'm using Processing as an automated alternative to Photoshop, so to speak, taking advantage of randomness and other unique factors. But I can't figure out how to store manipulations to an image in an array, within my program. I load an image, apply a random tint, repeat with a second image, and would like to, say, average the colors of each pixel between the two images. So, using Processing IDE:

PImage []gram = new PImage [8]; //number of source images; needs to = n[max]
PImage []tempgram = new PImage [8]; //same number as above
int d = 0; //source image number (ie, Photogram0)
int e = 0; //second source number
int x = 69; //number of total possible source images
int t = 0;

void setup(){
  size(3508, 2550); //standardized image size
  background(0);
  noStroke();
  loadPixels();
  for (int a = 0; a < 8; a++){ //a < n[max] 
    tempgram[a] = loadImage("asize.jpg"); //all white image, at dimensions of program canvas
  }
}

void draw(){
  if (t < 1000){ //number of iterations 
    float n = int(random(4, 8)); //randomize the number of sources used
    background(0);
    for (int i = 0; i < n; i=i){ 
      if (i == 0){ //will load first image
        d = int(random(0, x)); //pick a random image
        gram[i] = loadImage("Photogram" + d + ".jpg"); //load images
        gram[i].loadPixels();
        gram[i].filter(INVERT); //invert source image
        tint(random(255), random(255), random(255)); //random light color
        gram[i].updatePixels();
//        background(gram[i]); //I tried applying these changes to the bg and loading those px into another image
        tempgram[i].set();
        image(tempgram[i], 0, 0); //display image
        i++;
      }
… //more conditionals for 0 < i < n (secondary images), and i == n (final manipulations and save to disk). 
}


I tried writing to a PGraphics buffer; applying filters to the background and copying background pixels into a temp image array; I tried updatePixels and loadPixels; basically, everything short of writing to a new file and reading from that file, which is unsustainable when I'm working with between 3000-9000 images at 3508*2550px each.
OSX, Processing 2.1.1

Answers

  • Lines 13 to 15 are totally useless: no point in loading several times the same image, as you can use copy() or get() to copy one image. And if, per the comment, the image is white, you can just create it from scratch.

    You should at least add a noLoop() to setup(): apparently, you do a kind of batch processing, so there is no point in repeating the process 60 times per second (even if it is not even possible because of the processing time).
    Unless, of course, you have an exit() at the end of draw()...

    I don't understand what the line 31 is supposed to do, there is no set() method (without parameters) in PImage.

    And, lastly, I don't see what is your question. I don't see any in your post. Where are you stuck?

  • edited January 2014

    My question is how to create transformations using pixel data from two image files that have each been loaded and manipulated? So, I load a file, and apply a random tint. I do the same for a second file. Now I'd like to draw an image to screen composed of the halfway average (lerp 0.5) of the two images I've tinted:

    newImage.pixels[0] = lerpColor(imageOne.pixels[0], imageTwo.pixels[0], 0.5);
    

    The trouble I'm having is that the above code finds the original data of imageOne and imageTwo, not the tinted data. I want the average of the tinted images.
    I suppose the code I posted originally is misleading, because I'm not looking for errors thee, I'm just looking for a way to make this transformation happen.

  • edited February 2014 Answer ✓

    PImage objects got some nice methods indeed, but it's not that many!
    Take a look at the available list of methods below:

    http://processing.org/reference/PImage.html

    As you can see, there's no tint() method there. @-) That's a Processing's function instead:

    http://processing.org/reference/tint_.html

    If we need to use those graphics functions directly over a particular image, we gotta have a PGraphics layer:

    http://processing.org/reference/PGraphics.html

    So, if imageOne is a PImage, we can get a PGraphics outta it by issuing its get() method w/ empty argument:

    final PGraphics layerOne = imageOne.get();
    layerOne.tint((color) random(#000000));
    layerOne.endDraw();
    

    Now tint() is applied to this particular PGraphics and anything drawn in it! :bz

    And there's an extra bonus: The PGraphics class is also a PImage! \m/
    So it also inherits all PImage's methods and can be used anywhere a PImage is demanded! $-)

    An interesting feature is that an empty get() method returns a pure PImage object outta PGraphics now! :-))

  • Maybe I was a bit quick on the draw in accepting that answer. I get a "cannot convert from PImage to PGraphics" error.

    PImage sourceOne;
    PGraphics tempOne;
    
    void setup(){
      sourceOne = loadImage("Photogram0.jpg");
    }
    
    void draw(){
      final PGraphics tempOne = sourceOne.get();
      tempOne.tint((random(0-255)), (random(0-255)), (random(0-255)));
      tempOne.endDraw();
    }
    

    In addition to this conversion error, can you explain what the command "final" on line 9 is doing? From the documentation, I would think this would prevent me from applying transformations to the PGraphics.

    Thanks for all your help on this!

  • edited February 2014

    So sorry mon! Dunno how blind I was to even think that a PImage's method would ever spit out a PGraphics object!!! b-(

    http://processing.org/reference/PImage_get_.html

    Truth is, all graphics-related get() calls w/o arguments yield a PImage always! :O)

    This time, I've made-up a sketch, compiled & run it. See if that works for ya too:

    /** 
     * Tint-o-Matic (v1.31)
     * by  GoToLoop (2014/Feb)
     *
     * forum.processing.org/two/discussion/2728/
     * altering-images-for-later-recall
     */
    
    PImage picture;
    PGraphics layer;
    
    static final String URL = "http://" + 
    "upload.wikimedia.org/wikipedia/commons/9/9e/";
    
    static final String ARCHIVE = "Diqing,_Yunnan,_China.jpg";
    
    void setup() {
      size(800, 600);
      frameRate(1);
      smooth(4);
      imageMode(CENTER);
      clear();
    
      picture = loadImage(URL + ARCHIVE);  // online download
      //picture = loadImage(ARCHIVE);  // local load
    
      layer = createGraphics(picture.width, picture.height);
    
      layer.beginDraw();
      layer.smooth(4);
      layer.imageMode(CORNER);
      layer.endDraw();
    }
    
    void draw() {
      layer.tint((color) random(#000000));
      layer.image(picture, 0, 0);
      layer.endDraw();
    
      //image(layer, width>>1, height>>1);
      set((width - picture.width)>>1, (height - picture.height)>>1, layer);
    
      frame.setTitle("Tint-o-Matic\t\tShot #" + frameCount);
      saveFrame(dataPath("####.jpg"));
    }
    
  • edited February 2014

    tint() won't color the PGraphics object, just the things you are rendering onto the PGraphics object. A quick example how to use it correctly:

    PImage someImage;
    PGraphics canvas;
    
    void setup() {
    
        size(600, 600);
        canvas = createGraphics(width, height);
        someImage = loadImage("http" + "://upload.wikimedia.org/wikipedia/commons/9/9e/Diqing,_Yunnan,_China.jpg");
    
        canvas.beginDraw();
        canvas.tint(0, 0, 255); // Set the tint for future rendering methods (e.g. image())
        canvas.image(someImage, 0, 0, canvas.width, canvas.height); // Render the image onto the canvas (stretched)
        canvas.endDraw();
    
        canvas.save("test.jpg"); // Save the image
    
    }
    
    void draw(){
        image(canvas, 0, 0); // The PGraphics object itself behaves like an image
    }
    

    Btw.: random(0-255) will output values from -255 to 0. Use random(255) or random(0, 255).

    Edit.: This time you were faster @GoToLoop. :D

  • edited February 2014

    I would think this would prevent me from applying transformations to the PGraphics.

    Keyword final merely disallows a variable from being reassigned later.
    It doesn't affect an object referenced by that variable at all! :P

    I use it mostly as both guarantee & reminder that it's gonna keep its value till the end of its scoped lifespan! :>
    However, if that's a primitive or a String field w/ known values, final has the bonus of compiling it as a literal constant! \m/

    Edit.: This time you were faster @GoToLoop. :D

    But it doesn't mean I can't use your wallpaper link in my updated sample too! :))

  • @GoToLoop: How could you?! :D

  • Thanks for all this help. I got the script working with multiple images, I think. I also get the idea of final though I need my variables to be reassigned (or write a lot of workaround code). The way that tint is used here is unfamiliar to me, though.

    tempGram[i].filter(INVERT);
    tempGram[i].tint((color) random(#000000));
    

    I'd usually use tint(r, g, b) and color(r, g, b), but this only seems to work with (color) [hexadecimal]. How does this work? I ask because my invert filter on line 1 doesn't affect the image, and I imagine I have to change the way I write the command. Also, why am I only able to use hexadecimal notation for colors here? In the future I'd like to apply transformations based on a 0-256 scale.

    By the way, this is great. I'm spending a few hours a day coding, and it's never held my interest before.

  • edited February 2014 Answer ✓

    Seems like filter() got a different timing behavior:

    http://processing.org/reference/filter_.html
    http://processing.org/reference/PImage_filter_.html

    While most settings affect future drawings, filter() modifies everything already rendered and doesn't stick:

    layer.tint((color) random(#000000)); // affects everything after
    layer.image(picture, 0, 0);
    layer.filter(INVERT);                // affects everything before
    layer.endDraw();
    
  • edited February 2014 Answer ✓

    Well, it means that filter() is not a setting, but an action, like background() or ellipse(). A filter applies to an image, to alter it, while tint() acts on further drawings, coloring them.

Sign In or Register to comment.