Home > database >  convert coordinates from one resolution to another
convert coordinates from one resolution to another

Time:08-01

I have an image at a resolution of 512x512 pixels and I need to map a point in this image, selected through a mouse's click, to a point in the same image but at a resolution of 1024x1024.

I think that the problem is easy but I'm missing something. I tried calculating the mapping with a classical mathematical proportion like:

xp = x*1024/512

But it obviously doubles the value of x without actually making a map/conversion. How should I make this mapping?

EDIT As suggested in the comments, the core of the question is: How can I make a projection of a point in a 512x512 image to a 1024x1024 image?

CodePudding user response:

Your math checks out: if one image is 512x512 and the other is 1024x1024 the scale factor is 2 (multiplying x, y coordinates by 2 should do the trick.

Alternatively you can use map(), but in this trivial case it might be more simpler to just use the scale factor directly if you also need to maintain the mapped x,y values as integers.

Here's a basic sketch to demonstrate your mapping (and if you hold the mouse pressed it will use map() instead, though the results are the same and you'll notice no difference):

PImage img512, img1024;

void setup(){
  size(1536, 1024);
  strokeWeight(2);
  
  img512  = makeTestImage(512, 512);
  img1024 = makeTestImage(1024, 1024);
}

void draw(){
  background(0);
  image(img512, 0, 0);
  image(img1024, 512, 0);
  
  int x = mouseX;
  int y = mouseY;
  
  if((x >= 0 && x < 512) &&
     (y >= 0 && y < 512)){
     
       
      // for debugging pruposes compare with map() when mousePressed
      int xp, yp;
      if(mousePressed){
        xp = (int)map(x, 0, 512, 0, 1024);
        yp = (int)map(y, 0, 512, 0, 1024);
      }else{
        xp = x * 1024 / 512;
        yp = y * 1024 / 512;    
      }
      
      drawCrosshair(x, y, color(0), String.format("original [%d,%d]", x, y));
      // for visualisation purposes offset x ( since we're drawing the 1024 image at 512, 0 )
      drawCrosshair(xp   512, yp, color(255), String.format("mapped [%d,%d]", xp, yp));
  }
  
}

void drawCrosshair(float x, float y, color c, String label){
  stroke(c);
  // h
  line(0, y, width, y);
  // v
  line(x, 0, x, height);
  text(label, x - 100, y);
}

PImage makeTestImage(int w, int h){
  pushStyle();
  colorMode(HSB, 255, 255, 255);
  
  PImage out = createImage(w, h, RGB);
  
  out.loadPixels();
  
  for(int i = 0 ; i < out.pixels.length; i  ){
    out.pixels[i] = color(i % 255, 128, 128);
  }
  
  out.updatePixels();
  
  popStyle();
  
  return out;
}

Note that the mapped coordinate is displayed coorectly, but it's rendered with an offset of 512 pixels given the second PImage is rendered to the right of the first.

Here's a modified version that accesses pixels[] to copy a single pixel from one image to another:

PImage img512, img1024;

void setup(){
  size(1536, 1024);
  strokeWeight(2);
  
  img512  = makeTestImage(512, 512);
  img1024 = makeTestImage(1024, 1024);
}

void draw(){
  background(0);
  image(img512, 0, 0);
  image(img1024, 512, 0);
  
  int x = mouseX;
  int y = mouseY;
  
  if((x >= 0 && x < 512) &&
     (y >= 0 && y < 512)){
     
       
      // for debugging pruposes compare with map() when mousePressed
      int xp, yp;
      if(mousePressed){
        xp = (int)map(x, 0, 512, 0, 1024);
        yp = (int)map(y, 0, 512, 0, 1024);
        
        // test 1D pixel index
        copyPixel(img512, img1024, x, y);
        
      }else{
        xp = x * 1024 / 512;
        yp = y * 1024 / 512;    
      }
      
      drawCrosshair(x, y, color(0), String.format("original [%d,%d]", x, y));
      // for visualisation purposes offset x ( since we're drawing the 1024 image at 512, 0 )
      drawCrosshair(xp   512, yp, color(255), String.format("mapped [%d,%d]", xp, yp));
  }
  
}

void copyPixel(PImage from, PImage to, int xsrc, int ysrc){
  xsrc = constrain(xsrc, 0, from.width);
  ysrc = constrain(ysrc, 0, from.height);
  
  from.loadPixels();
  to.loadPixels();
  
  int fromIndex = xsrc   (ysrc * from.width);
  
  float scaleFactor = (float)to.width / from.width;
  int xdst = (int)(xsrc * scaleFactor);
  int ydst = (int)(ysrc * scaleFactor);
  
  int toIndex = xdst   (ydst * to.width);
  
  to.pixels[toIndex] = from.pixels[fromIndex];
  
  to.updatePixels();
}


void drawCrosshair(float x, float y, color c, String label){
  stroke(c);
  // h
  line(0, y, width, y);
  // v
  line(x, 0, x, height);
  text(label, x - 100, y);
}

PImage makeTestImage(int w, int h){
  pushStyle();
  colorMode(HSB, 255, 255, 255);
  
  PImage out = createImage(w, h, RGB);
  
  out.loadPixels();
  
  for(int i = 0 ; i < out.pixels.length; i  ){
    out.pixels[i] = color(i % 255, 128, 128);
  }
  
  out.updatePixels();
  
  popStyle();
  
  return out;
}

As you drag you'll notice colours around the white crosshair change. The above is more to demonstrate mapping from 2D x,y indices to an 1D pixels[] index. (If you simply want to swap a single pixel using PImage's get() and set() functions would be simpler.)

Alternatively you can call resize() on one image to match the dimensions of the other and have 1:1 mapping between pixels.

  • Related