TransWikia.com

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

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 =

enter image description here

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

enter image description here

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]]]]

enter image description here

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

3 Answers

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]

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]

enter image description here

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

enter image description here

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

enter image description here

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}]

enter image description here

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

enter image description here

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]}]]

enter image description here

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

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP