Issue with resizing image

Require urgent help! What am I doing wrong??
Maths is correct, but…

Overview:
To display a source image (example 15000 X 5000 PX) on 1920 X 1080 destination output. (keeping the correct aspect for destination)

Due to source image being > destination size, am selecting initial random positions from source image, holding the correct aspect ratio to the destination, not exceeding an output > a selected area from source. (I.e magnified) , but scaled / reduced accordingly - keeping the original aspect to destination).
Random areas from source are initially calculated and scaled down accordingly (held in an array - top left, bottom right, so to define an area from source), then displayed to destination accordingly

Issue:
Maths is fine, but something wrong with code.
Will not update selected source outputs to display, unless current window is moved via mouse. (Not updating)

Current Code:
(Please help!!)

  PImage img;
    PImage newimg;

    int sxsize;
    int sysize;
   
    int xsize;
    int ysize;
   
    int points=100;
   
    int[] x1=new int[points+1];
    int[] x2=new int[points+1];
    int[] y1=new int[points+1];
    int[] y2=new int[points+1];
   
    int xpos;
    int ypos;
   
    int distx;
    int disty;
   
    int i;
   
    float t1;
    float t2;
   
    float aspect;


void setup(){

    //fullScreen(1);
    size (1920,1080);
    noSmooth();
    frameRate(25);
   
    img=loadImage("1.jpg"); // use image @ 15000 X 5000 PX
    sxsize=img.width;
    sysize=img.height;
   
    xsize=1920;
    ysize=1080;
    aspect=float(xsize)/float(ysize);
   
    // set points
    setpoints();
}



void draw(){
 
  // get= x,y start width,height
 
    for (i=1; i<=points; i++) {
 
    xpos=x1[i];
    ypos=y1[i];
   
    distx=(x2[i]-x1[i]);
    disty=(y2[i]-y1[i]);
   
    newimg=img.get(xpos,ypos,distx,disty); // grab image from 1.jgp @ correct aspect ratio already calculated
    newimg.resize(xsize,ysize);

    image(newimg,0,0);
   
    }
   
}





void setpoints(){
 
    for (i=1; i<=points; i++) {  
   
    // set y1,y2 in array points
     
    while(true){ // find distance in y> output screen size
    t1=int(random(sysize));
    t2=int(random(sysize));
   
   
    if(abs(t1-t2)>ysize){
    break;
    }
    }
   
    // if t1<t2 then OK
    y1[i]=int(t1);
    y2[i]=int(t2);
   
    if (y1[i]>y2[i]){ // if t1>t2 then swap
    y1[i]=int(t2);
    y2[i]=int(t1);
    } // end if
   
   
   
   
    // set x1,x2 points
   
    float xmaxsize=(y2[i]-y1[i])*aspect; // calc max grab width dependant on aspect ratio based upon y1,y2
    t1=int(random(sxsize-xmaxsize)); // select a random area from source image less xmagesize
    t2=int(((y2[i]-y1[i])*aspect))+t1; // add aspect amount to t1 so to have bottom right coordinate.
   
    x1[i]=int(t1);
    x2[i]=int(t2);
   
    if(x1[i]>x2[i]){
    x1[i]=int(t2);
    x2[i]=int(t1);
    }
   
   
    }
   
   
   
}

Your draw() function is looping through all 100 images and drawing them on top of each other. The only image you will see is the last one. Rather than using a for() loop in draw(), use

void draw() {
   i = frameCount % points;

  // and then the rest of the code in the body of the for loop

}

Keep in mind that your code will then flash each image for only 1/25 of a second since that is what you have the frameRate set to. Quite possibly it will run slower than that, however, since you are get()ing the subimages separately for every draw() call. If you want to loop through the same 100 subimages repeatedly, it would be faster to make an array of PImages once in setup() and just image() from the array. You’d have to do the math to determine if your video card can store all of those. You might get better performance using P2D.

A much more efficient method would be to use P2D, set your large image as a texture() and then each draw(), render a single full screen quad setting its texture coordinates to part of the image you want to show. That would take no additional memory and would let all the pixel fetching and image scaling happen entirely on the GPU.

1 Like

This will show random portions of your image that are aspect correct and always greater than your display. I’m assuming here that your large image has a wider aspect than your display as in your example (15000/5000 is greater than 1920/1080), so I start by choosing a random height then set the width to match the display aspect. Then choose x and y that keep the subimage contained within the full image.

Leave your frameRate at the default 60 and you can adjust the variable framesToShow below to keep the image constant for that many frames. I set it to 180 so you’ll see each subimage for 3 seconds.

int framesToShow = 180;
float x = 0, y = 0, w = 0, h = 0;

void draw() {
  if( frameCount % framesToShow == 1 ) {
    h = random( height, img.height );
    w = h * width / height;
    x = random( 0, img.width-w );
    y = random( 0, img.height-h );
  }
  noStroke();
  beginShape();
  texture( img );
  vertex( 0, 0, x, y );
  vertex( width, 0, x+w, y );
  vertex( width, height, x+w, y+h );
  vertex( 0, height, x, y+h );
  endShape(CLOSE);
}
1 Like

Many thanks for your help!

Currently, this / was just test code.
Eventually, my aim was to lerp() from each entry in the array, showing different selected regions from the source image in a smooth transition to screen.

Am sure there must be a simpler method?

I used a PGraphics in this example just to create a sample image. You can use your PImage for the texture(). framesToLerp and framesToShow are assuming 60 fps, so lerp for 2 seconds and show for 3.

I switched to my own iFrame counter instead of using frameCount since mine starts at 0 while frameCount starts at 1. Starting at 0 makes it easier to compute the lerp time.

int framesToLerp = 120;
int framesToShow = 180;

int totalFrames = framesToLerp + framesToShow;

PGraphics img;
float x0=0, y0=0, w0=0, h0=0;
float x1=0, y1=0, w1=0, h1=0;

void setup() {
  size( 1920, 1080, P2D );

  // create some random image to show
  img = createGraphics( 15000, 5000, P2D );
  img.beginDraw();
  img.background(0);
  img.noStroke();
  img.textSize( 96 );
  for( int j=0; j<img.height/500; j++ ) {
    for( int i=0; i<img.width/500; i++ ) {
      img.fill( random( 128,255), random(128, 255), random(128, 255 ) );
      img.rect( i*500, j*500, 500, 500 );
      img.fill(0);
      img.text( nf(i)+"    "+nf(j), i*500+150, j*500+250 );
    }
  }
  img.endDraw();
  
  computeCoords();
}

void computeCoords() {
  x0 = x1;   y0 = y1;
  w0 = w1;   h0 = h1;
  h1 = random( height, img.height );
  w1 = h1 * width / height;
  x1 = random( 0, img.width-w1 );
  y1 = random( 0, img.height-h1 );
}

int iFrame = 0;
void draw() {
  float x, y, w, h;
  iFrame = (iFrame+1) % totalFrames;
  if( iFrame == 0 ) {
    computeCoords();
  }
  if( iFrame < framesToLerp ) {
    float t = float(iFrame)/framesToLerp;
    t = t * t * (3 - 2*t);   // smooth the ease in/out
    x = lerp( x0, x1, t );
    y = lerp( y0, y1, t );
    w = lerp( w0, w1, t );
    h = lerp( h0, h1, t );
  } else {
    x = x1;   y = y1;
    w = w1;   h = h1;
  }
  
  noStroke();
  beginShape();
  texture( img );
  vertex( 0, 0, x, y );
  vertex( width, 0, x+w, y );
  vertex( width, height, x+w, y+h );
  vertex( 0, height, x, y+h );
  endShape(CLOSE);
}

Many thanks once again for your input.
Will possibly try out your code tonight if I get the time.
I did get my version running correctly after your explanation. The only issue I have now is due to being scaled real-time, it runs very slow on occasions (because of reducing large areas from source).
Am sure that there may be a way of pre-calculating and storing frames in memory, then display once calculated. Then to run all over again using the initial end points as start points and selecting new end points. Repeat indefinitely.

Currently storing x1,y1,x2,y2 positions (source coordinates) in an array and selecting randomly

Again - many thanks for your support!!

Looks like your code runs a lot smoother, but am having an issue with loading my image to be displayed.
How do I do this via your code??
Image name 1.jpg

(Sorry - not very good with coding in Processing)

Change the global variable PGraphics img; back to your PImage img; and delete most of my code from setup(). It could just be

void setup() {
  size( 1920, 1080, P2D );
  img = loadImage( "1.jpg" );
}

You have been such a massive help in this project and I thank you so very very much!

Your code runs supper smooth and does exactly what was initially required.

Unfortunately am not as advanced in coding as yourself.

Am now looking to altering the output screen using the lerp() function to tint from one random RGB hue to another, then so on - similar to how the movement works, but at random times and not dependant to when the image stops moving.

Is this the last thing you could help with??
If not, then no problem at all. Am just so happy and thankful that you have got me this far!!

Irigima.

See if this is what you have in mind.

int framesToLerp = 120;
int framesToShow = 180;

int tintFramesToLerp = 60;
int tintMinFramesToHold = 60;
int tintMaxFramesToHold = 240;

int totalFrames = framesToLerp + framesToShow;

int tintHoldFramesRemaining = 1;
int tintLerpFramesRemaining = 0;

float x0=0, y0=0, w0=0, h0=0;
float x1=0, y1=0, w1=0, h1=0;
color c0 = 0, c1 = 0;

PGraphics img;

void setup() {
  size( 1920, 1080, P2D );

  // create some random image to show
  img = createGraphics( 15000, 5000, P2D );
  img.beginDraw();
  img.background(0);
  img.textSize( 96 );
  for( int j=0; j<img.height/500; j++ ) {
    for( int i=0; i<img.width/500; i++ ) {
      img.fill( random( 128,255), random(128, 255), random(128, 255 ) );
      //img.fill( random(128, 255 ) );
      img.noStroke();
      img.rect( i*500, j*500, 500, 500 );
      img.fill(0);
      img.text( nf(i)+"    "+nf(j), i*500+150, j*500+250 );
      img.noFill();
      img.stroke(0);
      img.circle( i*500+250, j*500+250, 480 );
    }
  }
  img.endDraw();
  
  computeCoords();
}

void computeCoords() {
  x0 = x1;   y0 = y1;
  w0 = w1;   h0 = h1;
  h1 = random( height, img.height );
  w1 = h1 * width / height;
  x1 = random( 0, img.width-w1 );
  y1 = random( 0, img.height-h1 );
}

int iFrame = 0;
void draw() {
  float x, y, w, h;
  iFrame = (iFrame+1) % totalFrames;
  if( iFrame == 0 ) {
    computeCoords();
  }
  if( iFrame < framesToLerp ) {
    float t = float(iFrame)/framesToLerp;
    t = t * t * (3 - 2*t);   // smooth the ease in/out
    x = lerp( x0, x1, t );
    y = lerp( y0, y1, t );
    w = lerp( w0, w1, t );
    h = lerp( h0, h1, t );
  } else {
    x = x1;   y = y1;
    w = w1;   h = h1;
  }
  
  color c = color( 255, 255, 255 );
  if( tintHoldFramesRemaining > 0 ) {
    c = c1;
    if( --tintHoldFramesRemaining == 0 ) {
      c0 = c1;
      // choose our new tint color
      c1 = color( random( 128, 255 ), random( 128, 255 ), random( 128, 255 ) );
      tintLerpFramesRemaining = tintFramesToLerp;
    }
  } else {
    c = lerpColor( c0, c1, 1.-float(tintLerpFramesRemaining)/tintFramesToLerp );
    if( --tintLerpFramesRemaining == 0 ) {
      tintHoldFramesRemaining = int(random( tintMinFramesToHold, tintMaxFramesToHold ));
    }
  }
  
  noStroke();
  beginShape();
  texture( img );
  tint( c );
  vertex( 0, 0, x, y );
  vertex( width, 0, x+w, y );
  vertex( width, height, x+w, y+h );
  vertex( 0, height, x, y+h );
  endShape(CLOSE);
}

This is PERFECT!!

Does exactly as required and now messing around with parameters / real images I have previously rendered.
Been adding some text etc.
Absolutely fantastic and so happy with it so-far!

Will forward you an animation link once uploaded to YT.
If on Reddit - look me up and see some of my work - in which I will be using, then you will see why I needed this to work.

A billion thanks for all your support in this project!

Irigima.

Glad it worked for you.