3
$\begingroup$

I use ImageBoundingBoxes to get the bounding boxes of objects in an image. I then want to crop out each object and I tried directly passing the Rectangle objects from ImageBoundingBoxes to ImageTake, but it does not work. I also tried converting the rectangle to a list of points by doing

{rect[[1]],rect[[2]]}

and passing that to ImageTake, but that also did not work, probably because ImageTake expects row and col number, which start from the top left corner, whereas Rectangle contains x and y which start from the bottom left corner. How can I convert Rectangle to a form that I can pass to ImageTake so that I can crop out the part of the image that the bounding box covers?

EDIT: I looked at ImageTrim and wrote the following function to to get a list of the four corners of a Rectangle object so that it can be passed to ImageTrim:

rectToList[rect_] := {rect[[1]], rect[[2]], {rect[[1, 1]], rect[[2, 2]]}, {rect[[2, 1]], rect[[1, 2]]}};

Then, I was able to crop out the bounding box portion as follows:

croppedImg = ImageTrim[img,rectToList[rect]];

Is this the best way to crop out the bounding box portion of an image?

$\endgroup$
4
  • 2
    $\begingroup$ Have you seen ImageTrim? $\endgroup$
    – C. E.
    Mar 11 at 21:36
  • $\begingroup$ @C.E. Thank you for the suggestion. ImageTrim requires a list of points, so I wrote a simple function that makes a list of the four corners of the rectangle. Is this the best way? $\endgroup$
    – sepehr78
    Mar 11 at 21:49
  • 1
    $\begingroup$ I think it can work to pass the rectangles. ImageTrim can, as the documentation says, take a region of interest (or a list of regions). Consider the examples under "Application" for example. Say, the FindFaces example. FindFaces returns Rectangle objects and yet it works. $\endgroup$
    – C. E.
    Mar 11 at 21:54
  • $\begingroup$ @C.E. Yes, you are right. I forgot that FindFaces returned Rectangle. Thanks. $\endgroup$
    – sepehr78
    Mar 12 at 6:45
4
$\begingroup$

As C.E. noted, easiest way is to use ImageTrim[image, rectangles] as ImageTrim accepts Rectangle objects as the trimming spec.

You can also to use ImageTake by converting rectangle coordinates to a form that can be used row and column specs in ImageTake:

ClearAll[imageTake]

imageTake[im_, r : {__Rectangle}] :=  Module[{rowscols = 
    Map[Apply[{ImageDimensions[im][[2]] + 1 - Reverse@#, #2} &]@* Reverse@*Transpose]@
      (r /. Rectangle -> List)}, 
    ImageTake[im, ##] & @@@ rowscols] 

Example: Using the image from the first example in ImageBoundingBoxes:

img = Import["https://i.stack.imgur.com/8xQHy.png"]

enter image description here

rectangles = ImageBoundingBoxes[img, Entity["Species", "Class:Aves"]] 
 {Rectangle[{130.885, 18.5558}, {166.549, 92.807}], 
  Rectangle[{91.2438, 38.0867}, {130.923, 101.634}]} 
imageTake[img, rectangles] // Map[ImageResize[#, 300] &] 

enter image description here

We get the same result using ImageTrim directly with rectangles:

ImageTrim[img, rectangles] // Map[ImageResize[#, 300] &] 
 same picture.
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.