Mathematica Asked on May 10, 2021
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
For a given image (im
), a list of 2D points (pts
) and side length (radius
), the function rectangleCoords
finds the arguments of Rectangle
s 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]
rectangleCoords[im_, pts_, radius_] := Transpose[
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];
myRadius = 60;
Show[myIm,
Graphics[{PointSize[Large], Red, Point @ myPts,
EdgeForm[Blue], FaceForm[],
Rectangle @@@ rectangleCoords[myIm, myPts, myRadius]}],
PlotRange -> All]
ImageTrim[myIm, rectangleCoords[myIm, myPts, myRadius]] //
Multicolumn[#, 8] &
imageTake[myIm, myPts, myRadius] // Multicolumn[#, 8] &
Correct answer by kglr on May 10, 2021
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
Answered by bobthechemist on May 10, 2021
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*)
myRadius = 10;
(*This generates the coordinates of each sub-image*)
mySubIms = Table[
{{myPts[[i]][[1]] - (myRadius - 1),
myPts[[i]][[2]] - (myRadius - 1)},
{myPts[[i]][[1]] + (myRadius - 1),
myPts[[i]][[2]] + (myRadius - 1)}},
{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.
Answered by TumbiSapichu on May 10, 2021
Get help from others!
Recent Questions
Recent Answers
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP