brendan-duncan / image

Dart Image Library for opening, manipulating, and saving various different image file formats.
MIT License
1.18k stars 268 forks source link

Copying Rotated Rectangles from an Image #429

Open cdigit opened 1 year ago

cdigit commented 1 year ago

I'm in a similar situation to this question where I want to be able to rotate and transform the bounding box coordinates that copyRectify uses. I'm not so concerned about the structure to hold coordinates, but whether this is even possible: How to Transform Coordinates using a Matrix4

I took a whack at it using the Image Library and vector_math Library like the code below. Output: I am getting some rotation, but It is the image piece itself along with another portion of the larger image outside of the original bounding box (that's another problem when rotating too much): (top=original image piece, bottom=rotated) https://imgur.com/82WNCP6

Expected: I want the "bounding box/selection" to be rotated and then the image copied from there. For example, If I applied the rotation transformation to 30 degrees, then the output would be a normal, non-rotated image that has been cropped with rotated sides that look more rhomboid than square like this: https://imgur.com/WKXBKs1

Question Why is the entire image rotated and not the "bounding box"? Is it even possible to use CopyRectify to copy a piece of an image inside of a rotated rectangle or is my approach wrong?

 // initialize integers for initial points 
 // x2 is width ; y2 is height
 x1=0; y0=y; x2=100; y2=100;

// create 4 points of a rectangle for topLeft to bottomRight
  imglib.Point p1 = imglib.Point(x1, y1);
  imglib.Point p2 = imglib.Point(x2, y1);
  imglib.Point p3 = imglib.Point(x1, y2); 
  imglib.Point p4 = imglib.Point(x2, y2);

// put the 4 points in 4 vectors
  vector_math.Vector3 v1 = vector_math.Vector3(x1.toDouble() , y1.toDouble(), 1);
  vector_math.Vector3 v2 = vector_math.Vector3(x2.toDouble() , y1.toDouble(), 1);
  vector_math.Vector3 v3 = vector_math.Vector3(x1.toDouble() , y2.toDouble(), 1);
  vector_math.Vector3 v4 = vector_math.Vector3(x2.toDouble() , y2.toDouble(), 1);

// Create a matrix4, rotate it and apply it to all 4 points/vectors
 vector_math.Matrix4  T = vector_math.Matrix4.rotationZ(vector_math.radians(45));  
  v1 = T.transform3(v1);
  v2 = T.transform3(v2);
  v3 = T.transform3(v3);
  v4 = T.transform3(v4); 

// pull the new rotated point values out of the vectors: 
  p1.x = v1[0];
  p1.y =v1[1];
  p2.x = v2[0];
  p2.y =v2[1];
  p3.x = v3[0];
  p3.y =v3[1];
  p4.x = v4[0];
  p4.y =v4[1];

// copyRectify the source image with transformed points
imglib.Image angledSlice = imglib.copyRectify(
        srcImage, 
        topLeft: p1, 
        topRight: p2, 
        bottomLeft: p3, 
        bottomRight: p4,
         );
brendan-duncan commented 1 year ago

I'm not completely following you for what you want, but it sounds like your approach is wrong.

copyRectify will warp the image , mapping the pixels within the given point coordinates to the new image pixels.

It sounds to me like what you are wanting is a rectangle mask that can be rotated.

If that is the case, unfortunately I don't have much for masking type of functions currently. It would be good to add those.

cdigit commented 1 year ago

Yes, a better way to put it is to rotate the mask as you put it. This way the copied image is not rotated but the only the mask, which will leave the image with slanted edges. Thanks for letting me know what the capabilities are.