Process images in a directory other than the sketchPath location

edited December 2016 in How To...

Greetings - I am very new to JAVA so bear with me please :) I'm using Processing 3.2.3 on a Windows 7 workstation

I am trying to work with images that are stored on a network drive and not in the sketch directory. As I read through the forum, I am confused - is this even possible? It would seem that by just using selectFolder and the resulting selection.getAbsolutPath - I should be able to change the directory I'm looking at. However, when I try this I can't seem to view / display anything using image(img,0,0) - where "img" is my loaded image. I just see a blank window. I suspect it has to do with the sketch not actually reading in the image - but don't know how to prove this.

I ran across mylink and it describes several possible options:
sketchPath(""); sketchFile(""); dataPath(""); dataFile("");

But frankly - being so new to JAVA and Processing, I know I am in over my head and don't know what to do with these operators - if anything. Any help is appreciated!

Answers

  • I now see that "[mylink]" really means - type the link description. Learned something already!

  • @ScottChabineau===

    i have done that but some years ago! - so i am not absolutely sure about the answer; yet you cannot use neither selectFolder nor anything like dataPath() and so on which are relative to processing and your sketch; supposing you are (are you???) on a LAN you have to use the mac adress or ip from your LAN, then the path to your file... But as soon as i get some free time i ll look to my old code, which worked on my LAN...

  • Thank you for the response - I look forward to seeing how you solved this. It sounds like you are saying I have to hardcode a mac address! That seems very odd - since all I am trying to do is: 1. select the folder where the images are (currently on a LAN~ but I would like them to be selectable no matter where the folder is located.
    2. work with the images stored in that folder.

    This is a very basic file function and I am truly surprised at how difficult this seems to be. It seems that everyone just accepts that you have to first copy all your data into the same folder as the sketch resides in (or sub folder of). I am finding it hard to digest.

  • edited December 2016

    @scottchabineau=== supposing that you have to use your images from web???? selectFolder()???? !!!

  • I did a quick search on java accessing a file through lan network and maybe this link provides some ideas

    http://stackoverflow.com/questions/2011264/how-to-read-a-file-from-remote-system-using-java

    I would think that if you can access it through the command prompt or the explorer using one of the lines provided above, then you could access it through a java call in Processing. However I don't think I can test that.

    What is important is to make sure your code works first. I suggest you run a provided example loading an image if you haven't done that.

    From my experience, when a file cannot be accessed, then whenever I try to access the PImage object, I get a null pointer error.

    Kf

  • @akenaton: I will not be working with any images on the web - only an internal network drive or local drive.

    @kfrajer and @ akenaton: to further illustrate my lack of knowledge... to be clear on my use of the acronym LAN - I am referring to my networked drives within windows. I would call that my local area network. Am I using the term correctly?

    @kfrajer: I will look into the link provided - Thanks!

  • @ScottChabineau -- from @kfrajer's link, this is the advice you probably want:

    HTTP is an option. However, if these are Windows machines on the same LAN, it would be easier to expose the directory on the remote machine via a file share and access the file through a regular file path. Similarly, if these are Unix-like machines, you could use regular file paths if you're using NFS. FTP's yet another option.

    Can you mount a file share to the remote machine? Then:

    1. confirm that you can load a file in your local data folder -- confirm you are doing loading right.
    2. confirm that you can load another file in your local directory structure -- use a local path, and check that you see the image
    3. now try the path of your mounted remote file share. It should act just like a normal path -- Java shouldn't be able to tell the difference. Did it work?
  • edited December 2016

    @ScottChabineau===

    -- Can you know the IP adresses of the other computers on your lan?

    -- If yes you can acceed to them and save with save(your path)

    -- of course you must have rights (read/write) for that OR you must put your files in a shared dir

    -- Note that if you know the IP, they can change dynamically; only mac Adresses are static (except if you create manually static ip)

  • @akenaton - I do not control the IP address and it may change. Hard coding the mac address seems like a very poor way to solve this - especially if the code gets shared. It becomes a security risk that I am not willing to take.

    @jeremydouglass - If you are referring to within my normal Windows environment, the answer is Yes, I have full read/write access to the directory I want to access. If you are referring to within Processing - I don't know how to confirm this (I have less than 10 hours of learning Processing).

    I do have code written and working that uses the selectFolder method to choose a path on my server and then uses mkdir() to create a new directory. I am even able to copy images into that folder - except when I open the images in Windows, they are all blank (solid grey).

    This is what has lead me try to understand what Processing is actually seeing when I load the image. However, at this point even the basic image(img,0,0) is eluding me. I have created a debug program with just the basic framework, and it runs without errors - only I can't seem to display an image.

    Breaking my code down even further by removing the selectFolder option works if the file is in the sketchPath. But as soon as I add selectFolder routine, the image will not display - even though I am selecting the sketchPath directory. No errors - debug seems to indicate it loads the image - just nothing comes out.

    Is this the forum/ thread to post the code or should I start a new thread over in "Programming Questions"?

  • What I mean is something like Start > Computer > Tools > Map Network Drive. Then access your remote content using the local path that you 'mapped'.

  • Yes, I can do that - and have full access.

  • Great! Then you don't need IP addresses etc etc. Does that work when you test it as per my instructions above?

  • I have - per my earlier reply:

    I can use the very basic loadImage and Image commands in the directory that the sketch is saved in. However, if I try to change the folder I'm looking at via selectFolder - I can select the folder and the code runs with no errors, only nothing is displayed - the image is blank. This is the case even when the folder i select is the same folder the sketch is in!

    Further, I can even create directories and save images into that directory on my network - but again, the images are blank. It's almost like the data gets dumped before the Image(img,0,0) occurs if the path is not specifically within the sketch folder. It's driving me a little bonkers... and I suspect it will be a simple - your using the wrong operator - sort of answer.

  • Ah -- I see. Given your problems with local folders it sounds like this might be a coding error, not a LAN problem. Perhaps if you post a simple example sketch here someone with a windows machine can test / help you. Be sure to format your code as per the Format Your Code post.

  • This code runs and displays in image

    void setup() {
      size(1482, 1482);
    }
    
    void draw() 
    {
      PImage img;
      img = loadImage("slice_1.png"); 
      image(img, 0, 0);
    }
    

    This code will run with no errors, but no image.

    void setup() {
      size(1482, 1482);
      selectFolder("Select a folder to process:", "folderSelected");
    }
    
    void folderSelected(File selection) {
      String NewPath;
      if (selection == null) {
        println("Window was closed or the user hit cancel.");
        NewPath = null;
      } else {
        NewPath = selection.getAbsolutePath()+"\\";
        draw(NewPath);
      }
    }
    
    void draw(String NewPath)
    {
      PImage img;
      img = loadImage(NewPath+ "slice_1.png");
      image(img, 0, 0);
    }
    
  • edited December 2016

    @ScootChabineau===

    ----as for selectfolder() see below; this code is for an old version of P5, because i have not P3X today, but i am quite sure you can easily adapt it; note also that i use a file separator which is not (i think) for windows but for mac. Of course i cannot see what your "double file separator" means, as i am not a windows expert, yet it seems to me rather strange...

    ---but i thought that your question was about a lan and that t s why i talked about IP adresses (manually fixed); i (think) to understand now that you have complete access and path to your network drive; in this case it is very simple to save with save("http://your path+name of the folder") or to load() from this path...

                 String newPath;
                 PImage img;
    
                void setup() {
    
    
                  size(1482, 1482);
                  newPath = selectFolder("choisissez un dossier...");
                  println(newPath);
                  if(newPath != null){
                  img = loadImage(newPath + "/yourimage.jpg");
                  }else{
    println("path is null");
    }
                }
    
                void draw(){
                  image(img, 0,0);
    
                }
    
  • Thank you akenaton - however, I am not able to make it work. Likely my inexperience...

    selectFolder wants 2 string arguments, that when I add the sencond one, results in

    'Type Mismatch: "void" does not match with "java.lang.String"'

    When I try the same logic in my code, where you call img = loadImage(NewPath+ "slice_1.png"); outside of the draw() routine - it fails. If I move image(img,0,0) into the same void routine, then it runs, but I still have no image displayed.

     PImage img;
    
    void setup() {
      size(1482, 1482);
      selectFolder("Select a folder to process:", "folderSelected");
    }
    
    void folderSelected(File selection) {
      String NewPath;
      if (selection == null) {
        println("Window was closed or the user hit cancel.");
        NewPath = null;
      } else {
        NewPath = selection.getAbsolutePath()+"\\";
          img = loadImage(NewPath+ "slice_1.png");
          image(img, 0, 0);
      }
    }
    
  • Answer ✓

    try this code (today i can use P3x)

        String newPath;
        PImage img;
        boolean loaded;
    
    
    
        void setup() {
          size(900,600);
          background(255);
          selectFolder("Select a folder to process:", "folderSelected");
        };
    
        void draw(){
    
          background (255);
    
          if(loaded ){
            image (img ,0,0); 
    
          }
        };
        void folderSelected(File selection) {
          if (selection == null) {
            println("Window was closed or the user hit cancel.");
          } else {
            println("User selected " + selection.getAbsolutePath());
            newPath = selection.getAbsolutePath();
            newPath = newPath+"/your.jpg";
            img = loadImage(newPath);
            loaded = true;
          }
        }
    
  • WOW! That actually worked! I can now at least get the image to display on my screen no matter where it is located on the network.

    It appears that the addition of the boolean variable is the real key. Can you explain why this is?

    Here is my final code:

    String NewPath;
    PImage img;
    boolean loaded;
    
    void setup() {
      size(1482, 1482);
      selectFolder("Select a folder to process:", "folderSelected");
    }
    
    void folderSelected(File selection) {
      if (selection == null) {
        println("Window was closed or the user hit cancel.");
        NewPath = null;
      } else {
        NewPath = selection.getAbsolutePath()+"\\";
        img = loadImage(NewPath+ "slice_1.png");
        loaded = true;
      }
    }
    void draw() {
      if (loaded) {
        image(img, 0, 0);
      }
    }
    

    My next step is to include this in a program that prompts the user to select the folder where the files are located, create a new sub-folder, make modifications to all the files in the main folder, and save the changes to the new subfolder.

  • For those who want the fewest lines of code possible, I was able to eliminate String NewPath variable and directly insert selection.getAbsolutePath into loadImage()

    PImage img;
    boolean loaded;
    
    void setup() {
      size(1482, 1482);
      selectFolder("Select a folder to process:", "folderSelected");
    }
    
    void folderSelected(File selection) {
      if (selection == null) {
        println("Window was closed or the user hit cancel.");
      } else {
        img = loadImage(selection.getAbsolutePath()+"\\"+ "slice_1.png");
        loaded = true;
      }
    }
    void draw() {
      if (loaded) {
        image(img, 0, 0);
      }
    }
    

    I welcome any further advice. Thanks again akenaton and jeremydouglass

  • I think there could be a delay loading the image. You could try using requestImage() instead and then you have to check for your image's dimension to be bigger than zero. This last means that the image has been successfully uploaded as it is run in its own thread. See the documentation.

    In your previous example use requestImage instead of loadImageand then your draw would be:

    void draw() {
      if (image.width>0) {
        image(img, 0, 0);
      }
      else
        text("Waiting for image...",width/2,height/2);
    }
    

    Kf

  • Interesting - Would this impact any post processing I want to do since the image is not "loaded"? Speed is important, but not if I can't work with the image.

    In the final program, I will not actually display the image at all. I will be processing through a series of images to make modifications to the width and height. The reason for displaying the image now is to verify that the image is actually being loaded. Before this point I would only get a blank window and the images were being saved as blank too. Now that I can see the image, I am hopeful the rest will fall into place.

  • @ScottChabineau=== the callback is on its own thread, so it happens that the draw() starts before the image is really loaded; that is the reason i created the boolean; of course you can also use kfrager solution, testing the width of the image...

  • @ScottChabineau

    I tossed the requestImage reference here because it is relevant to the topic. Either solution would work for you at the end, either checking for size/requestImage or boolean/loadImage. It is great you are testing this loading operation. That is exactly what I would do too.

    Kf

  • Thanks again - I am a bit more educated now! :)

  • OK - so I have completed the code and it again runs with no error messages. The only problem is I am still getting blank images saved. It appears that the image loads in "instance of processing.core.PImage", but since I am not trying to display it first, it stays in the background (separate thread?) and never actually gets processed by the rest of the code.

    So, how do get the image out of the background without drawing it on the screen?

    I will want to be able to parse through 2000+ files and I thing forcing a screen refresh will slow things down further.

    Here is my code:

    PImage img;
    boolean loaded;
    int iA;
    
    void setup() {
      size(1482, 1482);
      noStroke();
      noSmooth();
      selectFolder("Select a folder to process:", "folderSelected");
    }
    
    void folderSelected(File selection) {
      if (selection == null) {
        println("Window was closed or the user hit cancel.");
      } else {
    
        //create a new output directory in the selected folder path
        String folderPath = selection.getAbsolutePath() + "\\Output\\";
        File file = new File(folderPath);
        if (!file.exists()) {
          if (file.mkdir()) {
            System.out.println("Directory is created!");
          } else {
            System.out.println("Failed to create directory!");
          }
        }
    
        // convert a set of slice images (typically 1280x800) for use in pattern mode 
        // by padding them with black to 1482x1482
        for (int i = 1;; i++) 
        {
          //define filename as slice_XXXX.png
          String filename = "slice_" + nf(i, 1) + ".png";
    
          // see if this slice exists
          File f = new File(selection.getAbsolutePath() +"\\"+ filename);
          System.out.println("Looking for file "+ f);
          if (!f.exists())
            break;
    
          // load the existing slice image
          PImage img;
          img = loadImage(selection.getAbsolutePath() + "\\"+ filename);
          img.loadPixels();
          loaded = true;
          background(0);
    
          //check to see if image is loaded and display it
          if (loaded) {
            image(img, 0, 0);
          } else
            text("Waiting for image...", width/2, height/2);
    
          // expand to new image size
          copy(img, 0, 0, img.width, img.height, 
            (1482 - img.width) / 2, (1482 - img.height) / 2, img.width, img.height);
    
          //save resized image to output directory
          save(folderPath + filename);
          System.out.println("Saving file " + folderPath + filename);
    
          //calculate white area of slice_n
          int cP = 0;
          for (color c : img.pixels) if (c == -1)  ++cP; // -1 is white color value unconverted
          iA = 1024000 - cP;  //102400 is maximum build area in pixels 
          println("Surface Area = " +iA);
        }
        println("done");
      }
    }
    
  • Notice that after you read the first image, your boolean loaded is true. You need to set it to false before loading the next image. As an alternative, requestImage could work better as you can check the size of the image before you do any processing on it. Keep in mind that you should run a mini-test first to confirm requestImage works for you as you intended. In other words, do the same test as you did before but instead of using boolean loaded/loadImage() function use img.width/requestImage() function.

    Kf

  • Hello again - so this problem is not going away. No matter what I do, I cannot get this to work. The underlying problem seems to be that for some maddening reason, I have to have the images in the sketch directory - I must be missing something fundamental here. I can't be the only person needing to work with multiple images already created that are not stored in the sketchPath!

    So, perhaps someone can help me approach this differently. Can I have the program prompt me for the initial file location, 'copy and paste' all the files in that location to a preset folder in the sketchPath, perform a operation on them, then 'cut and paste' them back in the original location AFTER the work has been done?

  • Bump - I wish there was a way to removed the 'answered' flag. While @akenaton did find a solution to one problem, it has not solved the larger issue of not being able to work on imaged not located in the sketchPath Please, can anyone please help?

  • still can use some more help here...

  • Wait a second, didn't you say you could display the images even if they were located on a network drive?

    That actually worked! I can now at least get the image to display on my screen no matter where it is located on the network.

  • @LofG ~~~ Thank you for asking!

    While I was successful in displaying one image in a networked directory - that I was prompted to select using selectFolder("Select a folder to process:", "folderSelected"), it ultimately did not solve the main issue. It seemed to be a step in the right direction - but I cannot get beyond that initial step.

    What I need to do is prompt the user to select a folder on the network, then process ALL the images in that folder. The processing includes opening an image, changing the image size, and save a copy in a new sub folder created in the selected network location.

    It seems basic to me, but I am quickly learning that JAVA is not the same as VB and the underlying logic and purpose is different enough to stymie a newbie like me.

    The problem I am having NOW is that even though my code seems to run flawlessly (no errors), the processed images end up blank. It currently allows me to select the network folder, creates the sub directory, then will save the correct number of image files at the new size in the sub directory (based on the number of files in the main folder) - only the image files created are blank!

    It would seem that the original image is not getting loaded into the draw() thread. I prematurely believed that by being able to display the image (as answered by @akenaton), I could then simply drop this solution into the main program. But it doesn't work! ~X(

  • Suggestion: in your last post, line 59 repmace save(...) with img.save(...)

    Kf

  • @kfrajer~~~

    That's getting there! now the images are saved---- BUT--- they are the original images, not the processed images. It would seem that the processed images are not getting loaded into the right 'memory'.

    I think I need something after the copy() statement to replace the originally loaded image with the new 'copy'. Or maybe there is another command that can be used to change the image width and height, instead of copy().

  • Yes... I knew it wasn't the image you needed but it is a good start. Instead of copy, use get() and use a PImage container to store ur processed img before you call save. It seems the problem is calling save on a PGrapgics obj. However it works on a PImage. This requures further investigation... maybe a bug?

    Kf

  • I'll look @ get()

    This is where my lack of knowledge really shines... I have no idea what you mean by PImage container ~ can you elaborate or point me to examples?

    Thanks!

  • edited January 2017

    Yes calling save on a PGraphics object does seem to cause problem at least in Android mode.
    A possible solution is suggested in this question : https://forum.processing.org/two/discussion/20023/saved-image-is-empty#latest.

  • A possible solution :

    PImage img = loadImage("path");
    PGraphics pg = createGraphics(img.width, img.height);
    pg.beginDraw();
    pg.image(img, 0, 0);
    // Now do whatever image processing you want
    pg.endDraw();
    img = pg.get();
    img.save("path"); 
    
  • Hmmm - does copy() actually create a PGraphics obj? If not, I'm a bit confused since I am using PImage.

  • Well, it doesn't crash - but still is only saving the original img.

    (I tried moving the PGraphics to the top to make it global - didn't affect anything)

    PImage img;
    boolean loaded;
    int iA;
    PGraphics pg;
    
    void setup() {
      size(1482, 1482);
      noStroke();
      noSmooth();
      selectFolder("Select a folder to process:", "folderSelected");
    }
    
    void folderSelected(File selection) {
      if (selection == null) {
        println("Window was closed or the user hit cancel.");
      } else {
    
        //create a new output directory in the selected folder path
        String folderPath = selection.getAbsolutePath() + "\\Output\\";
        File file = new File(folderPath);
        if (!file.exists()) {
          if (file.mkdir()) {
            System.out.println("Directory is created!");
          } else {
            System.out.println("Failed to create directory!");
          }
        }
    
        // convert a set of slice images (typically 1280x800) for use in pattern mode 
        // by padding them with black to 1482x1482
        for (int i = 1;; i++) 
        {
          //define filename as slice_XXXX.png
          String filename = "slice_" + nf(i, 1) + ".png";
    
          // see if this slice exists
          File f = new File(selection.getAbsolutePath() +"\\"+ filename);
          System.out.println("Looking for file "+ f);
          if (!f.exists())
            break;
    
          // load the existing slice image
          PImage img;
          img = loadImage(selection.getAbsolutePath() + "\\"+ filename);
          img.loadPixels();
          loaded = true;
          background(0);
          pg = createGraphics(img.width, img.height);
    
          //check to see if image is loaded and display it
          if (loaded) {
            image(img, 0, 0);
          } else
            text("Waiting for image...", width/2, height/2);
    
          // expand to new image size
          pg.beginDraw();
          pg.image(img, 0, 0);
          copy(img, 0, 0, img.width, img.height, 
            (1482 - img.width) / 2, (1482 - img.height) / 2, img.width, img.height);
    
          //save resized image to output directory
          pg.endDraw();
          img = pg.get();
          img.save(folderPath + filename);
          System.out.println("Saving file " + folderPath + filename);
    
          //calculate white area of slice_n
          int cP = 0;
          for (color c : img.pixels) if (c == -1)  ++cP; // -1 is white color value unconverted
          iA = 1024000 - cP;  //102400 is maximum build area in pixels 
          println("Surface Area = " +iA);
        }
        println("done");
      }
    }
    
  • copy on line 59 copies inside the main canvas. Not in the PGraphics.
    Make it pg.copy, and put img in the end and not start.

  • Making progress!

    By making in pg.copy ---The image is changing! Just not the way it's intended. Since I'm not 100% sure what you mean by "put img in the end and not start" I didn't change that. You have been so very helpful so perhaps you can elaborate...

    do you mean change all the img references before the PGraphics?

  • PS - here is what the image now looks like... a copy is created over the top and shifted

    slice_1

  • edited January 2017

    @ScottChabineau===

    • its a stupid idea here to create a pGraphics
    • dont forget that the folder call back is a call back!!!
    • Though i am not a windows users i think that your paths are strange, but why not?
    • i have tried with my initial code modifying it in order that the paths are from UNIX and that it resize the images and so on
    • everything works fine

    if you want i can put here the code; yet i think that you can find by yourselves!

  • @Akenaton - While PGraphics may not make sense - it seems to be almost working (in that I can now see a change in the saved image). However, it would be ideal if can be achieved only using PImage.

    Is this the code you are referring to? I looked at this link: https://forum.processing.org/two/discussion/20023/saved-image-is-empty#latest.

    I will need to really look at it more closely, since I'm not sure what is really different from what I am doing. I was getting lost in all the other functions of this code and having a hard time tracking down the code pertinent to me.

    If you got code to run in UNIX - and all you changed was the paths, I would love to see it.

  • your link is a code for another problem:: solution was get(), i give it... not any problem: try only to understand... main problem is that your call back is in a thread and i ll show you the solution ...to morow because now tired out to explain

  • Oops, sorry, my mistake. You don't need to do that. I read the documentation wrong.
    You cannot achieve this using only PImage. Why? Because PImage is not for drawing on onto.
    @akenaton Can you explain yourself:

    its a stupid idea here to create a pGraphics

  • @ScottChabineau What did you intend should happen?

    Just not the way it's intended

  • edited January 2017

    @ScottChabineau=== try this::

                    PImage img;
                    ArrayList<PImage> tableauIm = new ArrayList<PImage>();
                    boolean loaded;
        int iA;
                    String folderPath;
                    String filename;
                    int nbre = 0;
    
                    void setup() {
                      size(800, 600);
                      noStroke();
                      noSmooth();
                      selectFolder("Select a folder to process:", "folderSelected");
                    };
    
                    void draw(){
    
                       background(0);
    
                       if(loaded){
                         PImage limage = tableauIm.get(nbre);
                         image (limage, 300,300);
                       }
    
                       if(nbre<tableauIm.size()-1){
                       nbre++;
                       }
                    };
    
    
    
                    void folderSelected(File selection) {
                      if (selection == null) {
                        println("Window was closed or the user hit cancel.");
                      } else {
    
                        //create a new output directory in the selected folder path
                       folderPath = selection.getAbsolutePath() + "/" + "Output/";
                        File file = new File(folderPath);
                        if (!file.exists()) {
                          if (file.mkdir()) {
                            System.out.println("Directory is created!");
                          } else {
                            System.out.println("Failed to create directory!");
                          }
                        }
    
                        // convert a set of slice images (typically 1280x800) for use in pattern mode 
                        // by padding them with black to 1482x1482
    
                        for (int i = 1;; i++) //here i think that it is better to indicate i<.....
                        {
                          //define filename as slice_XXXX.png
                         filename = "slice_" + nf(i, 1) + ".png";
    
                          // see if this slice exists
    
                          File f = new File(folderPath  + filename);
                          System.out.println("Looking for file "+ f);
                          if (!f.exists())/// because filename has been created before break
                          break;
    
    
                          img = loadImage(folderPath + filename);
    
                          img.resize(120,80);// put what values you want
    
                          image(img, 0, 0);
    
                            PImage temp = img.get();
    
                            temp.save(folderPath + filename);
    
                            tableauIm.add(temp);// i create an arrayList for the new images: could be useful!
    
    
                          //calculate white area of slice_n
                          int cP = 0;
                          for (color c : img.pixels) if (c == -1)  ++cP; // -1 is white color value unconverted
                          iA = 1024000 - cP;  //102400 is maximum build area in pixels 
                          println("Surface Area = " +iA);
                        }
                        println("done");
                        loaded=true;// happens when all images are loaded
                      }
                    }
    
Sign In or Register to comment.