Simulating long exposure shots on Processing

edited January 11 in Library Questions

Hello everyone,

I am trying to create a sketch that simulates a long exposure shot captured on camera. I searched for smth similar on the web and found this reference which proposes to append different layers using different opacities. I did that with the following code, but it doesn't seem to quite do the job properly.

Anybody tried to do that before?

Any other suggestions?

Thanks for your time! :-)

// This patch proposes to simulate a long exposure shot using Processing.

import processing.video.*;

Capture video;

void setup() {
  size(640, 480);
  printArray(Capture.list());
  video = new Capture(this, 640, 480, 30);
  video.start();
}

void mousePressed()
{
  int steps = 10;  // also means amount of pictures taken and merged later
  long opac = 255 / steps; 

  for (int i = 1; i <= steps; i++) 
  {
    if (video.available())
    {
      video.read();
      image(video, 0, 0);
      tint(255, opac * i);    // changes the opacity every step
      delay (100);            // delay between each step
      print(i); 
      println(" " + opac * i);
    }
  }
}

void keyPressed()
{
  background(0);
}

void draw() {
  // Step 5. Display the video image.
}

Answers

  • Just figured that I had increasing opacity values as the step counter went up. Inverting the opacity value from ascending to descending produced my desired effect. changed

    for (int i = 1; i <= steps; i++) 
      {
        if (video.available())
        {
          video.read();
          image(video, 0, 0);
          tint(255, opac * i);    // changes the opacity every step
          delay (100);            // delay between each step
          print(i); 
          println(" " + opac * i);
        }
      }
    

    to

     for (int i = 1; i <= steps; i++) 
      {
        if (video.available())
        {
          video.read();
          tint(255, opac * (steps - i));    // changes the opacity every step
          delay (500);            // delay between each step
          print(i); 
          println(" " + opac * (steps - i));
        }
        image(video, 0, 0);
      }
    
  • It is still not polished. Doesn't seem to merge images properly. Maybe because the opacity declines in a linear way? Is there a way to change blending mode on Processing? anyone? thanks !

  • re:

    Is there a way to change blending mode on Processing?

    You probably don't need to freeze the sketch between frames in the mousePressed function and use delay() -- instead, you could just use draw and frameRate()

    Changing the opacity over time doesn't actually model how a long exposure photgraph works. Instead, set a fixed opacity and blendMode, and simple draw to the canvas without clearing. This will "expose" the canvas over time.

    Due to how float-based averaging works, some blend modes will never reach a perfectly black or perfectly bright frame, no matter how long they are shown a still exposure -- they will max out at ~10-240 instead of 0-255.

  • Hey Jeremy, thanks for your reply! I noticed in other posts that's possible to use framerate instead of using delay. I'm actually using it to be sure how long the capture will be. I'd like it to take around 3.2 seconds to do it all.

    I'm also trying to store each frame in an Array, but with no luck. I managed to record each frame in jpegs but i can't access the images on the array. I guess I'm missing something...

    Also I have to use a kinect as a webcam for what i'm developing, so I changed my original code a little bit.

    Also couldn't get the real difference between ArrayList and Array[]... :-(

    thanks again for your help !

    // trying to implement a long exposure feature using kinect rgb camera.
    // when trying to flick thru images on the array, it doesn't seem to be saving images properly on array.
    // 
    // p.s. - could use onboard webcam too, just have to use kinect because that's the 
    // camera installed 
    
    import org.openkinect.freenect.*;
    import org.openkinect.processing.*;
    Kinect kinect;
    
    
    int totalTime = 3200; // in miliseconds   
    int steps = 32;       // also means amount of pictures taken and merged later
    ArrayList<PImage> secondArray = new ArrayList<PImage>(steps+1);
    
    int delayPhotos = totalTime/ steps;
    long opac = 255 / steps; 
    
    void setup() {
      background(0);
      frameRate(15);
      size(640, 480);
    
    
      kinect = new Kinect(this);
      kinect.initVideo(); // inicia video rgb do kinect
    }
    
    void mousePressed()
    {
      PImage imageKinect = kinect.getVideoImage();
    
      for (int i = 1; i <= steps; i++) 
      {
        secondArray.add(imageKinect);           // saves frames no array
        imageKinect.save("image" + i + ".jpg"); // saves images to disk
        tint(255, opac * (steps - i));    // changes the opacity every step
        delay (delayPhotos);              // delay between each step
        blendMode(BLEND);
        print(i); 
        println(" " + opac * (steps - i));
        save("combined.jpg");
        image(imageKinect, 0, 0);
      }
    }
    
    void keyPressed()
    {
      println(key);
      if (key == 'p' || key == 'P') 
      {
        println("Prints sequence of images in Muybridge style");
        background(0);
    
        // trying temporarily for 32 images
        int w = 80;
        int h = 60; 
        int x = 0;
        int y = 0;
        tint(255, 255);
        image(secondArray.get(1), x, y, w, h);
        image(secondArray.get(5), 80, y, w, h);
        image(secondArray.get(8), 160, y, w, h);
        image(secondArray.get(15), 240, y, w, h);
        image(secondArray.get(20), 320, y, w, h);
        image(secondArray.get(22), 400, y, w, h);
    
        // error: can't get different images from array. seems to be
        //getting latest frame from camera, instead
    }
    }
    
    void draw() {
    
      //image(kinect.getVideoImage(), 0, 0);
    }
    
  • edited January 11

    Can you be more specific than saying you didn't have luck, or you couldn't access the images? What happened when you tried?

    Edit: I see now in your comments that the frames all show the latest. (Please include this information outside your code so it's easy to read.)

    My guess is you need to copy the current frame into a new image, and then store that image in your ArrayList.

    And the difference between an array and an ArrayList is an ArrayList allows you to add elements to it, and it will automatically resize itself. Arrays are fixed-size.

  • edited January 13

    Re:

    I'm actually using it to be sure how long the capture will be. I'd like it to take around 3.2 seconds to do it all.

    That is what frameRate() does -- and the sketch keeps running and accepts input if you don't use delay().

    If you set it to 10 in setup(), thats one frame every 100ms.

    frameRate(10);
    

    Then in your header create a global shutter flag and duration value:

    boolean shutterOpen = false;
    int duration = 3200; // 3.2 seconds
    int closeTime = 0;
    

    ...and in keyPressed() open the shutter and set a timer:

    if(key == 'p' || key == 'P'){
       shutterOpen = True;
       closeTime = millis() + duration;
    }
    

    ...and in draw() do something each moment the shutter is open -- draw is your loop:

    if(shutterOpen = True){
      // do something!
    }
    

    ...and don't forget in draw() to close the shutter once it gets to a draw frame when you are done.

    if(millis() > closeTime){
      shutterOpen = False;
    }
    

    With this approach, you could set the exposure duration for 30 seconds -- or 10 minutes -- and you could still still interact with the sketch, see a preview of the results forming on the screen, or hit cancel -- and the sketch would respond. With the delay approach, you just locked the sketch up for 10 minutes, and forcing it to quit entirely is your only escape.

Sign In or Register to comment.