How to do a "random" image partition based on seeding points?

I'm new to image analysis with Mathematica, so far it looks it has great capabilities. I'm trying to do an image partition, similar to ImagePartition[], but "random". Suppose I have the image below:

myImage =

Now, I can do ImagePartition[myImage, {100,100}], to get sub-images of 100 by 100 pixels:

How could I, instead of this 'orderly' partition of the image, seed some random points in the image, and retrieve the {width, height} sub-images centered on each of the points. For instance, we generate some number of random points on the image:

myRndPts =
Table[{RandomInteger[ImageDimensions[myImage][[1]]],
RandomInteger[ImageDimensions[myImage][[2]]]}, 800];
Show[myImage, ListPlot[myRndPts,
PlotStyle -> Directive[Red, PointSize[Large]]]]


Then, from the center of each point, we make a sub-image of the desired {width, height}. In doing so, what to do with points that fall on the edges of the image? Maybe trim the window size, or add some extra 'padding'?

Currently, I'm thinking on doing simply ImagePartition[myImage,{width,height},{dw,dh}], with dw=dh=1, where dw and dh are the offset of the partition. This offset would --I believe-- sample all possible subpartitions of {width, height}. Then, from this list, I could select n random elements. However, this would not be efficient with large images, since it will generate a bunch of images I won't end up using.

Thanks

• See ImageTrim. Mar 8, 2021 at 1:00
• – kglr
Mar 8, 2021 at 2:00

For a given image (im), a list of 2D points (pts) and side length (radius), the function rectangleCoords finds the arguments of Rectangles centered at pts and forced to stay within the image rectangle.

We can use rectangleCoords directly with ImageTrim, or further process the output from rectangleCoords to generate row and column specs for ImageTake.

The function imageTake, given the same inputs, computes the parameters $$\{row_1, row_2\}$$ and $$\{col_1, col_2\}$$ to get the sub-image that spans $$row_1$$ to $$row_2$$ and $$col_1$$ to $$col_2$$ using ImageTake[im, {row_1, row_2}, {col_1,col_2}].

ClearAll[rectangleCoords, imageTake]

Transpose @ MapThread[Clip[#, {1, #2}] &] @
{Transpose[pts + # radius/2], ImageDimensions[im]} & /@ {-1, 1}];

imageTake[im_, pts_, radius_] := Module[{rowscols =
Map[Apply[{ImageDimensions[im][[2]] + 1 - Reverse @ #, #2} &] @*
Reverse @* Transpose] @ rectangleCoords[im, pts, radius]},
ImageTake[im, ##] & @@@ rowscols ]


Example:

myIm = ExampleData[{"TestImage", "Lena"}];

SeedRandom[1]
myPts = RandomSample[Tuples @ Range @ ImageDimensions @ myIm, 40];

Show[myIm,
Graphics[{PointSize[Large], Red, Point @ myPts,
EdgeForm[Blue], FaceForm[],
PlotRange -> All]


ImageTrim[myIm, rectangleCoords[myIm, myPts, myRadius]] //
Multicolumn[#, 8] &


imageTake[myIm, myPts, myRadius] // Multicolumn[#, 8] &


This is kind of fun - may not be what you want, however.

i = ExampleData[{"TestImage", "House"}]
ImageDimensions@i
(* {256, 256} *)


Create a VoronoiMesh and use those polygons as a mask.

pts = RandomReal[{20, 236}, {10, 2}];
mp = MeshPrimitives[VoronoiMesh[pts], 2];
Show[i, Epilog -> {FaceForm[None], EdgeForm[Thick], mp}]


RemoveBackground@ImageCrop@
ImageSubtract[i, Show[i, Graphics[{#}, PlotRange -> 256]]] & /@ mp


• This is cool, maybe I'll use this for another application, haha. But yeah, I'm just trying to generate a bunch of squared sub-images, so unfortunately the Voronoi tesselation won't do the trick here. But this is cool. Mar 8, 2021 at 2:17

Okay, in case it is of any use to somebody, following the comment by @C.E. I took a look into ImageTrim[]. It was only a matter of finding out the specific format of the arguments of the function.

(*Load image*)
myIm = Import["https://i.stack.imgur.com/5f46D.jpg"];
(*Generate some random points*)
myPts = Table[{RandomInteger[ImageDimensions[myIm][[1]]],
RandomInteger[ImageDimensions[myIm][[2]]]}, 100];
(*Radius from each point, to make a square*)
(*This generates the coordinates of each sub-image*)
mySubIms = Table[
{i, 1, Length[myPts]}];
(*This is the list of all sub-images*)
mySubImages = ImageTrim[myIm, mySubIms];

(*We can visualize the overlayed sub-images*)

Show[myIm,
Table[Graphics[{FaceForm[None],
EdgeForm[Directive[Dashed, Thickness[0.005], Blue]],
Rectangle[mySubImages[[i]][[1]], mySubImages[[i]][[2]]]}],
{i, 1, Length[mySubImages]}]]


As you can see, it seems that the sub-images on the edges are simply trimmed, which for my application is fine. Maybe adding some padding would be preferred for some other applications.

Feel free to improve or make this method more efficient. I wrote things step by step, for clarity, but maybe there are some performance improvements if needed for large images.