I am trying to analyze images of elliptical laser beams that are striking 'ground glass' surfaces. I need to determine the size, position and orientation of the ellipse that represents the boundary of the beam. The images are grainy due to random scattering from the irregular surface of the ground glass and in some cases, only a partial ellipse is visible (see the example image below). I would also like to use a mostly circular reference feature (see CAD drawing here) in the image which I know has a diameter of 25.4 mm to convert the spatial coordinates from pixels to mm.

image of elliptical laser beam

Adjust Image Brightness and Contrast

I use ImageAdjust to make the circular reference feature and the elliptical beam shape stand out more clearly in the image. FindImageShapes (available in v13.3) appears to successfully locate the two features.

img = Import["https://i.sstatic.net/UGqaR.png"];
imgBRIGHT = ImageAdjust[img, {1, 15}]
e = FindImageShapes[GradientFilter[imgBRIGHT, 3], "Ellipse"]
HighlightImage[imgBRIGHT, Graphics@MaximalBy[e, RegionMeasure, 2]] 

The output for e is a GeometricTransformation that I do not understand. I took a look at ComponentMeasurements but I couldn't figure out how to apply this to e.

Is there a simple way to extract the centers, major and minor axes, and orientation of the found ellipses?

  • $\begingroup$ The PDF of CAD drawing you provided doesn't work. $\endgroup$
    – Domen
    Commented Jul 21, 2023 at 21:10
  • $\begingroup$ The link to the CAD drawing was fixed. $\endgroup$
    – Drotar
    Commented Jul 22, 2023 at 0:55

1 Answer 1


You can directly extract the centroid and semi-axes from the Circle and orientation angle from the rotation (!) matrix inside GeometricTransform. The following function extractEllipse will return a list with centroid, semi-axes, and rotation angle.

e = FindImageShapes[GradientFilter[imgBRIGHT, 3], "Ellipse"]
(* {GeometricTransformation[
     Circle[{456.704, 539.323}, {132.729, 92.6068}], 
      {{{0.0693787, 0.99759}, {-0.99759, 0.0693787}}, {-113.005, 957.508}}], 
     Circle[{449.805, 546.919}, {228.447, 228.122}], 
      {{{0.148538, 0.988907}, {-0.988907, 0.148538}}, {-157.86, 910.496}}]} *)

extractEllipse[GeometricTransformation[Circle[{x_, y_}, {rx_, ry_}], {m_, v_}]] := 
 {{x, y}, {rx, ry}, ArcTan @@ (m . {1, 0})}

ellipses = extractEllipse /@ e
(* {{{456.704, 539.323}, {132.729, 92.6068}, -1.50136}, 
    {{449.805, 546.919}, {228.447, 228.122}, -1.42171}} *)

To convince yourself that the result is correct, you can recreate the ellipses via Circle and RotationTransform:

 Graphics[GeometricTransformation[Circle[#[[1]], #[[2]]], 
     RotationTransform[#[[3]], #[[1]]]]] & /@ ellipses]

which gives the same result.

  • $\begingroup$ That does seem to work. Thanks! m appears to be the rotation angle relative to the horizontal axis but I'm confused about what v is supposed to be? ellipses doesn't seem to return anything for that parameter, so maybe it's not a big deal. Is this some kind of stretching? $\endgroup$
    – Drotar
    Commented Jul 21, 2023 at 22:07
  • 1
    $\begingroup$ Look at the documentation for GeometricTransform. It represents the transformation of point r to point m.r + v. In our case, m is a rotation matrix around the origin, and v is a translation vector. But this two-step transformation can be equivalently represented with a rotation around the centroid. $\endgroup$
    – Domen
    Commented Jul 21, 2023 at 22:18

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.