7
$\begingroup$

I have binary images like this one

Mathematica graphics

and I want to be able to interactively select its components and rotate them around its centroid by a different angle for each component.

I may also want to apply different Image transformations such as translations, dilations, etc., always on a per-component basis

Please keep in mind that the original component partition should be preserved, so if as a result of a given transformation two or more components get merged, they should still be considered as different components for the next transformation.

$\endgroup$

1 Answer 1

7
$\begingroup$

This implements the rotation part. Still pondering which is the better way to implement the interface for multiple transformations:

perComponentTransform[img_Image] := 
 Module[{mc, m, col, colRuls, centerRuls, maskDataRuls, mask},
  mc = MorphologicalComponents[img];
  m = Max@mc;
  col = Colorize[mc, ColorFunction -> "Rainbow"];
  colRuls = Union@Flatten[MapThread[Rule, {mc, ImageData@col}, 2], 1];
  {centerRuls, maskDataRuls} = 
                 Transpose[Thread /@ ComponentMeasurements[img, {"Centroid", "Mask"}]];
  mask = maskDataRuls /. (n_ -> a_SparseArray) :> 
                            ColorReplace[Image@a, White -> RGBColor @@ (n /. colRuls)];

  DynamicModule[{maskd = mask, k = 0, angle = Array[0 &, m], angleResv = Array[0 &, m]},
   Panel@Dynamic@
     Column[{
       Row[{Image[col, ImageSize -> 200],
         Column[
          Table[With[{i = j},
            DynamicModule[{y = angleResv[[i]]},
             Row@{
               Graphics[{RGBColor @@ (i /. colRuls), Rectangle[]}, ImageSize -> 15],
               Slider[Dynamic[y, (k = i; angle[[i]] = y = #) &], {0, 2 Pi}],
               Dynamic[y]}]], {j, m}]]}],
       If[! $ControlActiveSetting && k != 0,
        maskd[[k]] = ImageTransformation[mask[[k]], 
                         RotationTransform[-angle[[k]], k /. centerRuls], 
                         DataRange -> Full];
        angleResv = angle; k = 0];
       Image[Fold[ImageAdd, maskd], ImageSize -> 400]}]]]

Usage:

img = Binarize@Import@"https://i.sstatic.net/4SYJS.png";
perComponentTransform[img]

Mathematica graphics

Due credit to Algohi for solving a nasty problem with ControlActive for arrays of controls

$\endgroup$
6
  • $\begingroup$ Sorry for these busy days.You make a good job.But the perComponentTransform is a challenge for my computer.Due to ImageForwardTransformation is a power-wasting function.I'm look forward to the MorphologicalTransform can do those thransform in next version. $\endgroup$
    – yode
    Commented Mar 1, 2016 at 8:59
  • $\begingroup$ @yode Please re-check the speed now. I have a faster alternative if it is still too slow. (I am using ImageTransformation now instead of ImageForwardTransformation) $\endgroup$ Commented Mar 2, 2016 at 15:34
  • $\begingroup$ @Thanks for your concern this.And some tips for the efficiency.1.mask=ImageMultiply[col,Image[#]]&/@Values[ComponentMeasurements[col,"Mask"]];.2.ImageAdd[maskd] instead of Fold[ImageAdd, maskd].Anyway your method is best than what I have writed. $\endgroup$
    – yode
    Commented Mar 2, 2016 at 15:39
  • $\begingroup$ Another thinking in my mind is ImageCrop the every component.Then *Transform it.In the last.we move back to the Centroid.But I havenot try it.It will save many computer the pixel of 0. $\endgroup$
    – yode
    Commented Mar 2, 2016 at 15:42
  • $\begingroup$ @yode. Re suggestion 1: mask is calculated only once, so there is no much gain in it. Re suggestion 2: ImageAdd accepts only two args in V9. Re Suggestion 3: It can be done ... but how's the performance right now? $\endgroup$ Commented Mar 2, 2016 at 16:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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