7

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.

Dr. belisarius
  • 115,881
  • 13
  • 203
  • 453

1 Answers1

7

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.stack.imgur.com/4SYJS.png";
perComponentTransform[img]

Mathematica graphics

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

Dr. belisarius
  • 115,881
  • 13
  • 203
  • 453
  • 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. – yode Mar 01 '16 at 08:59
  • @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) – Dr. belisarius Mar 02 '16 at 15:34
  • @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. – yode Mar 02 '16 at 15:39
  • 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. – yode Mar 02 '16 at 15:42
  • @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? – Dr. belisarius Mar 02 '16 at 16:08
  • Re 3.Just suggestion for a more large image. Yes.the efficency is better than before in my PC.And do if use the $ControlActiveSetting then we cannot realize the effect like as ContinuousAction -> True? – yode Mar 02 '16 at 16:26