Can you create a randomly generated image mask?

I would like to use a series of image masks, in which each would consist of a randomly placed ellipse. I’ve provided three examples of masks that would belong to the larger set of masks I would like to generate. I don’t want to have to draw out thousands of masks, generating each permutation by hand. Is there a way to do this without pre-creating each mask?

mask_1 Mask 1

mask_2 Mask 2

mask_3 Mask 3

Etc...

Tagged:

Answers

  • edited November 2013 Answer ✓

    yes, you can use a for loop i 0 to 100 or so and place a ellipse randomly and save it

    size (100, 100);
    
    for (int i = 0; i < 100; i++) {
      background (0);
      fill(255);
      stroke(255);
      ellipse (random (0, width), random (0, height), 10, 10);
      save( "name" + trim(str(i)) + ".jpg" );
    }
    
    println ("done");
    

    tested

    here the name is like name1.jpg, name2.jpg etc.

    [edited]

  • _vk_vk
    Answer ✓

    Yep, and use a PGraphic to mask an image:

    PImage img;
    PGraphics mask;
    
    void setup(){
      size (1000, 1000);
      img = loadImage("http://foglobe.com/data_images/main/frank-zappa/frank-zappa-06.jpg");
      mask = createGraphics(width, height);
      background(40);
    }
    
    void draw(){
    
      mask.beginDraw();
      mask.noStroke();
      mask.fill(255);
      mask.ellipse(random(width), random(height), 20, 20);
      mask.endDraw();
    
      img.mask(mask);
      image(img, 0 ,0);
    }
    
  • This question is an extension of the above question. I am trying to expand on the code mentioned above to do the following: Pulling from a data set of multiple images (let's say 6 images in this case, though it will be thousands in the final piece), draw a randomly placed ellipse from image 1, then draw a randomly placed ellipse from image 2, and so on. The below code appears to be close but I can't figure out what I'm doing wrong. (I've embedded the test images below in case they are useful.)

    PGraphics mask;
    int countB = 0; 
    int numImagesA = 6;
    PImage[] imgA = new PImage[numImagesA];
    
    void setup(){
      size (640, 360);
      mask = createGraphics(width, height);
      background(40);
    }
    
    void draw(){
      PImage imgA = loadImage("CarlSagan" + (countB) + ".jpg"); 
    
      mask.beginDraw();
      mask.noStroke();
      mask.fill(255);
      mask.ellipse(random(width), random(height), 50, 50);
      mask.endDraw();
    
      imgA.mask(mask);
      image(imgA, 0 ,0);
    
      countB++;
      if (countB == numImagesA) {
         countB = 0;  
       }
    
      println (countB);
    }
    

    CarlSagan0

    CarlSagan1

    CarlSagan2

    CarlSagan3

    CarlSagan5

  • _vk_vk
    edited November 2013

    Here what I came up with. Using a PGraphics to persist drawings avoiding a huge number of PGraphics. Is this that you want?

    PGraphics mask;
    PGraphics display;
    int numImagesA = 5;
    PImage[] imgA = new PImage[numImagesA];
    
    void setup() {
      size (640, 360);
      mask = createGraphics(width, height);
      display = createGraphics(width, height);
    
    
     String forumHack = "http:";
    
      imgA[0] = loadImage(forumHack + "//forum.processing.org/two/uploads/imageupload/002/OQZYC5GHBUKH.jpg");
      imgA[1] = loadImage(forumHack + "//forum.processing.org/two/uploads/imageupload/533/O6RUH8CZ40P5.jpg");
      imgA[2] = loadImage(forumHack + "//forum.processing.org/two/uploads/imageupload/847/K0Y60IVQ3G3I.jpg");
      imgA[3] = loadImage(forumHack + "//forum.processing.org/two/uploads/imageupload/455/E6D04N43B3CL.jpg");
      imgA[4] = loadImage(forumHack + "//forum.processing.org/two/uploads/imageupload/254/M5LRPT65XPJX.jpg");
    
    
    
      background(40);
    }
    
    void draw() {
    
    
      mask.beginDraw();
      //erase previous ellipse
      mask.background(0);
      mask.noStroke();
      mask.fill(255);
      mask.ellipse(random(width), random(height), 50, 50);
      mask.endDraw();
    
      // a circular counter
      int index = frameCount%imgA.length;
    
      //mask the image
      imgA[index].mask(mask);
    
       // update display
      display.beginDraw();
      display.image(imgA[index], 0, 0);
      display.endDraw();
    
      //display display
      image(display, 0, 0);
    }
    
  • Yes, what you've done is the end product that I need, but I need to be able to load thousands of images without writing them out as below:

      imgA[0] = loadImage(forumHack + "//forum.processing.org/two/uploads/imageupload/002/OQZYC5GHBUKH.jpg");
      imgA[1] = loadImage(forumHack + "//forum.processing.org/two/uploads/imageupload/533/O6RUH8CZ40P5.jpg");
      imgA[2] = loadImage(forumHack + "//forum.processing.org/two/uploads/imageupload/847/K0Y60IVQ3G3I.jpg");
      imgA[3] = loadImage(forumHack + "//forum.processing.org/two/uploads/imageupload/455/E6D04N43B3CL.jpg");
      imgA[4] = loadImage(forumHack + "//forum.processing.org/two/uploads/imageupload/254/M5LRPT65XPJX.jpg");
    

    My files will be named as follows: "pic1.jpg", "pic2.jpg", "pic3.jpg", up to maybe "pic9476.jpg".

    I'm quite new to arrays. What's be best way for me to load them?

  • _vk_vk
    edited November 2013

    like @chrisir said above...

    for (int i = 0; i < 100; i++) {
    
      loadImage( "pic" + trim(str(i)) + ".jpg" );
    }
    

    do it in setup().

    check out this great tutorial: http://wiki.processing.org/w/From_several_variables_to_arrays

  • Thanks _vk. It looks like I'm mostly there but I can't figure out how to invoke (correct word?) the array in the draw method.

    This line is currently a problem:

      imgA[index].mask(mask);
    

    And I'm guessing that this one will be also:

      display.image(imgA[index], 0, 0);
    

    I looked at the link you gave me and have tried to impliment it but I think I'm missing something key.

    This is what I currently have:

        PGraphics mask;
        PGraphics display;
        int numImagesA = 6;
        PImage[] imgA = new PImage[numImagesA];
    
        void setup() {
          size (640, 360);
          mask = createGraphics(width, height);
          display = createGraphics(width, height);
    
         for (int i = 0; i < 16; i++) {
          loadImage( "pic" + trim(str(i)) + ".jpg" );
        }
    
          background(40);
        }
    
        void draw() {
    
          mask.beginDraw();
          //erase previous ellipse
          mask.background(0);
          mask.noStroke();
          mask.fill(255);
          mask.ellipse(random(width), random(height), 30, 30);
          mask.endDraw();
    
          // a circular counter
          int index = frameCount%imgA.length;
    
          //mask the image
    
          callPic(0).mask(mask); 
    
          // update display
          display.beginDraw();
          display.image(callPic(0), 0, 0);
          display.endDraw();
    
          //display display
          image(display, 0, 0);
        }
    
        void callPic(int n){
           imgA[n];
        }
    

    I've tried to invoke the 'n'th number using a new method at the bottom of the code.

  • _vk_vk
    edited November 2013

    You are mixing things up a bit... I believe the error you get in line imgA[index].mask(mask); is "ArrayIndexOutOfBounds: 6" right? That's because the array has only 6 places, not 16... I made some changes and comments in your code: untested...

    PGraphics mask;
    PGraphics display;
    //int numImagesA = 6; // this is the size of your array. It will only fit 6 images...
    
    //lets' change:
    int numImagesA = 16 // you need 16 now right?
    
    PImage[] imgA = new PImage[numImagesA];
    
    void setup() {
      size (640, 360);
      mask = createGraphics(width, height);
      display = createGraphics(width, height);
    
    // here you try to access 16 places, but the array was only 6 in length...
    // so, now that the array length is 16 it would work, but best practice is to use the .length
    // of the array, so if you change it later code won't break
    // old -  for (int i = 0; i < 16; i++) {
    
     for (int i = 0; i < imgA.length; i++) {
      //also you need to assign each image to the one array slot..
    
     imgA[i] =  loadImage( "pic" + trim(str(i)) + ".jpg" );
    }
    
      background(40);
    }
    
    void draw() {
    
      mask.beginDraw();
      //erase previous ellipse
      mask.background(0);
      mask.noStroke();
      mask.fill(255);
      mask.ellipse(random(width), random(height), 30, 30);
      mask.endDraw();
    
      // a circular counter 
      int index = frameCount%imgA.length; 
    
      //mask the image
    
    //the function is void, so it's not returning something that you can call mask on...
    //more on that later
     // callPic(0).mask(mask); 
    
    // now this should work fine without the function
    imgA[index].mask(mask);
    
    
      // update display
      display.beginDraw();
      display.image(imgA[index], 0, 0);
      display.endDraw();
    
      //display display
      image(display, 0, 0);
    }
    
    
    // not in use, but if you like to do this, it should return a PImage... so
    //this would work as you have tried
    // but this way there is no guarantee that you 
    //would not pass an index bigger than array length...
    PImage callPic(int n){
      return  imgA[n];
    }
    
  • _vk_vk
    edited November 2013

    Updated the code assigning images to array slots... I haven't noticed that.

  • Your explanation of everything has been very clear--thank you so much. I have a much better understanding of what is going on now, and how each part of the code is working.

    I have two last questions for you: 1) The images I've been using are test images and are smaller (640 x 360). At some point between using 800 x 450px images (which work) and 1200 x 675 images (which don't) the program doesn't work. I don't get any error messages, just a grey display window where nothing happens. The images I want to use will likely range from 1920 x 1080, up to something like 4000 x 3000. Do you know what's causing this?

    2) I've been looking for ways to change the alpha of the dots, but from what I've seen it's not possible with PGraphics masks. Is that right?

  • edited November 2013

    Translucent masks are possible:

    http://bazaar.launchpad.net/~philho/+junk/Processing/view/head:/_QuickExperiments/MaskImage/MaskImage.pde

    Just draw the mask with gray, not with alpha.

  • Great; thanks PhiLho! That answers the seciond question perfectly. I just need to figure out the first question then--why I can't get the image data set to contain larger images (like 1920 x 1080 or 4000 x 3000).

  • I don't think so. I was using a data set of 4 images.

  • _vk_vk
    edited November 2013

    Maybe something related to the fact that mask() expects an image of the same dimensions as the one to be masked? Try narrow down the issue...

    • does images display fine without any mask ?

    • Is your handling of size (are you resizing? positioning bigger images?) working fine alone?

    • can you mask each image alone?

    and things like that...

  • I'm wondering if I can load the images one at a time before drawing each one (instead of pre-loading them all in the setup).

    Can this:

     for (int i = 0; i < imgA.length; i++) {    
     //assigns each image to the one array slot.
     imgA[i] =  loadImage( "pic" + trim(str(i)) + ".JPG" );
    }
    

    Happen one at a time in the draw method?

  • _vk_vk
    edited November 2013

    loading images is slow, if you load them during draw, the sketch will hang until it is loaded. Usually is recommended to load them at setup(). That said you can use a global var incremented in draw to build your file name, and then I think you don't need the array, like:

    UNTESTED

    // global
    PImage imageOfThisTurn;
    int index = 0;
    int numberOfImages; //=  total images number
    
    void draw(){
    imageOfThisTurn = loadImage( "pic" + trim(str(index)) + ".JPG" );
    
    // use imageOfThisTurn however needed
    
    // use modulo to go back to first image after the last
    index = (index + 1) % numberOfImages
    
    }
    
  • edited November 2013

    We're gonna need to know how many pictures you're gonna need and their expected dimensions.
    Also how many you're gonna need to display at a given time.
    Whether it's always forward, or do you need to get back to previous 1s. Are they numbered as well???

    Java offers a huge selection of structures to store objects.
    And choosing the right 1 w/ the right strategy (like using threads), anything can be overcome! >:/

  • Ok, thanks guys. I won't have time to test this for at least a few days, but when I do, I'll let you know how it works!

    To answer your question GoToLoop, the program is intended to handle a variety of data sets, each with varying numbers and dimensions. Having said that, I can say that likely dimensions will include: 1) 3000x4000px 2) 1920x1080px

    In terms of the number of images in each data set... this can range from high hundreds to several thousands or in some cases tens of thousands.

    Although it would be ideal to be able to play the program in realtime in the Processing viewer, I can also write in some export code (either as a still sequence or as a video) and handle output of the final work that way. In that case, loading images slowly wouldn't be a problem.

  • edited November 2013

    You gave more details, but at the same time haven't answered all of my requests. Like for example how many images per screen.

    In terms of the number of images in each data set...

    Seems like you got a group of images bound to some particular data set, is it so?
    Since a complete image loading involves reading from disk + decompressing + convert to internal format, it is indeed very slow!

    What I have in mind is for you implementing a separate Thread to deal in creating a pool of pre-loaded images.
    That'd involve some amount of loadImage() in advance and discard old 1s.

    But the key here is anticipation of which images to pre-load among them.
    Hence the main part of your program gotta request to that separate part
    a bunch of images early on, so it's ready available to be displayed w/o any loading delay.

Sign In or Register to comment.