7
$\begingroup$

I'm new to Mathematica. I'm very impressed about it's abilities. It's very easy to achieve complex tasks. But I fail the simple ones.

How can I get coordinates in image processing?

I'd like to detect one of the following things

  • absolute vertical center of the rectangle surrounding all white parts
  • gravity center of all white parts

e.g.: for this picture

https://i.stack.imgur.com/0GFCv.png

I want to find the green point (center of outbound box).

https://i.stack.imgur.com/AcMp5.png

$\endgroup$
3
  • $\begingroup$ So the center of outbound box (the green point in your example) is generally NOT the gravity center of all white parts, then which is the one you really want? $\endgroup$
    – Silvia
    Apr 22, 2013 at 11:42
  • $\begingroup$ The question is more general: "How to find and handle positions/coordinates in images". I do not care, which aspect of the precise question is going to be answered ;-) $\endgroup$
    – schmijos
    Apr 22, 2013 at 12:53
  • 1
    $\begingroup$ Then that will be a HUGE topic, with various methods for various problems. It's usually not the positions of points, but the special properties of those points, which distinguish them from points you want to drop, are essential for image processing. $\endgroup$
    – Silvia
    Apr 22, 2013 at 14:35

5 Answers 5

8
$\begingroup$

ImageValuePositions, new in 9, can return a list of white pixel positions.

i = Import@"https://i.stack.imgur.com/opzqB.png";
p = ImageValuePositions[i, White] // Mean
(* {298.896, 21.3231} *)

HighlightImage[i, {p},
 Method -> {"CrossMarkers", 5}]

Update: Surrounding rectangle

Get the min/max of white pixel coordinates.

whites = ImageValuePositions[i, White];
corners = Transpose[{
   Through[{Min, Max}[First /@ whites]],
   Through[{Min, Max}[Last /@ whites]]}]
(* {{218.5, 0.5}, {373.5, 50.5}} *)

Make a rectangle boundary and highlight that region on the image.

rect = corners /. {{x1_, y1_}, {x2_, y2_}} :>
    With[{dx = 2}, Join[
      Table[{x1, y1} + {0, y}, {y, 0, y2 - y1, dx}],
      Table[{x1, y2} + {x, 0}, {x, 0, x2 - x1, dx}],
      Table[{x2, y2} - {0, y}, {y, 0, y2 - y1, dx}],
      Table[{x2, y1} - {x, 0}, {x, 0, x2 - x1, dx}]]];

HighlightImage[i, rect,
 Method -> {"DiskMarkers", 1}]
$\endgroup$
3
  • $\begingroup$ @Mr.Wizard But he is looking for "gravity center of all white parts." $\endgroup$
    – BoLe
    Apr 22, 2013 at 11:13
  • $\begingroup$ @belisarius Okay, I've been put in my place. :-o (+1 to BoLe) $\endgroup$
    – Mr.Wizard
    Apr 22, 2013 at 11:16
  • $\begingroup$ +1. Didn't notice the "gravity center" phrase in OP's question. $\endgroup$
    – Silvia
    Apr 22, 2013 at 11:43
7
$\begingroup$

For another approach, there's always the ComponentMeasurements way:

cm = ComponentMeasurements[Dilation[i, BoxMatrix[5]] , "Centroid"]

{1 -> {297.633, 23.7345}}

mean = Mean@cm[[All, 2]] (* not needed if only one component found*)

HighlightImage[i, 
 List@mean, 
 Method -> {"DiskMarkers", 3}, 
 HighlightColor -> Green]

pic

I'm not happy with the Dilation approach, though, which is a bit sloppy.

$\endgroup$
3
  • $\begingroup$ I thought of Dilation at first, but afraid it may change the center position given that the image pattern is not symmetric. $\endgroup$
    – Silvia
    Apr 22, 2013 at 10:59
  • $\begingroup$ @Silvia I couldn't think of any dilation-towards-the-center commands. MorphologicalTransform doesn't do it either... :( I was close, anyway! $\endgroup$
    – cormullion
    Apr 22, 2013 at 11:07
  • 2
    $\begingroup$ +1. Instead of Dilation, you can use the ComponentMeasurements overload that takes a label matrix instead of an image: ComponentMeasurements[ImageData[Binarize[i]], "Centroid"]. That way, you'll always get a single component, because the label matrix only contains 0 and 1. $\endgroup$ Apr 22, 2013 at 11:32
7
$\begingroup$

Suppose your original image is img.

First we Binarize it:

imgBinarized = img // Binarize;

Then crop all the black boarders:

imgConcerned = ImageCrop[imgBinarized]

imgConcerned

So now, using the HitMissTransform (also wiki page), we can easily get its center position:

centerPos = HitMissTransform[imgBinarized, ImageData[imgConcerned]]

enter image description here

To achieve the appearance of your last picture, we construct a diamond marker first:

markerMatrix = Graphics[{EdgeForm[{White, Thick}], FaceForm[],
       Rotate[Rectangle[], π/4]},
      Background -> Black,
      ImageSize -> {15, 15}] // Rasterize //
    ColorConvert[#, "Grayscale"] & // ImageData;

Then convolve it with the centerPos image:

imgCenter = ImageConvolve[centerPos, markerMatrix];

Colorize it:

imgCenterColored = Image[
  # ImageData[imgCenter] & /@ {0, 3/4, 0, 1},
  "Real", ColorSpace -> "RGB", Interleaving -> False];

Compose it with the original image img:

ImageCompose[img, imgCenterColored]

enter image description here

You can explore the image processing functions in Mathematica and find yourself how to add the red boundary box.

Edit

As cormullion suggested, in case you want the coordinate of the center point, you can extract it from the mask image centerPos straightway:

Position[Transpose[ImageData[centerPos, DataReversed -> True]], 1]

{{297, 26}}

$\endgroup$
4
  • $\begingroup$ I like your HitMissTransform. If the OP wants the coordinates of the point, can they get that from centerPos? $\endgroup$
    – cormullion
    Apr 22, 2013 at 10:36
  • $\begingroup$ @cormullion I think ImageData then using Cases or ArrayRule etc to extract it would be viable. $\endgroup$
    – Silvia
    Apr 22, 2013 at 10:38
  • $\begingroup$ If he's new, he might want to see that...! (or Position[Transpose[ImageData[centerPos, DataReversed -> True]], 1] might work...) $\endgroup$
    – cormullion
    Apr 22, 2013 at 10:40
  • $\begingroup$ @cormullion Thanks for suggestion. Have added it :) $\endgroup$
    – Silvia
    Apr 22, 2013 at 10:57
5
$\begingroup$

A variation of BoLe's center-of-gravity method for version 7:

img = Import["https://i.stack.imgur.com/opzqB.png"]

SparseArray[ImageData@Binarize@img]["NonzeroPositions"] // Mean // N
{30.1769, 299.396}

Output in (y,x) order.

SparseArray is much faster than Position:

dat = ImageData@Binarize@img;

Do[SparseArray[dat]["NonzeroPositions"], {1500}] // Timing // First

Do[Position[dat, 1], {1500}] // Timing // First

0.14

2.465

Links to other uses of SparseArray Properties here.

$\endgroup$
3
  • $\begingroup$ Thank you for this very general answer! +1 for legacy support. Why is the resulting vector the wrong way arround: {y,x} instead of {x,y} ? $\endgroup$
    – schmijos
    Apr 23, 2013 at 13:11
  • $\begingroup$ @Josua You're welcome. It's just an artifact of the way array elements are indexed in Mathematica: row, then column. $\endgroup$
    – Mr.Wizard
    Apr 23, 2013 at 13:24
  • $\begingroup$ @Josua By the way I just revised the timings to better emphasize the superiority of SparseArray over Position. $\endgroup$
    – Mr.Wizard
    Apr 23, 2013 at 13:27
4
$\begingroup$

Here's one way that exploits the fact that you have a constant black background. If your image is called img, then

small = ImageCrop[img]

crops it and leaves just the central rectangle.

enter image description here

Now you want the center of the cropped image, which can be found

cen = ImageDimensions[ImageCrop[img]]/2

To display the small image and the centerpoint:

Show[small, Graphics[{Thick, Orange, Point[{{cen, cen}}]}]]

This gives you a little orange dot at the center.

enter image description here

You can of course, change the orange dot to whatever you like.

$\endgroup$
2
  • $\begingroup$ +1. In this case ImageCrop works but in more complicated cases it can do wrong cropping: "Precise cropping with ImageCrop." The reliable way to crop is ImagePad[img, -BorderDimensions[img, 0]]. $\endgroup$ Apr 22, 2013 at 13:47
  • 1
    $\begingroup$ Sure, that's why I prefaced my answer with "Here's one way that exploits the fact that you have a constant black background." In general you might want to binarize the image, and perhaps then apply some kind of erosion in order to make the background uniform. But in the present case the image was already binary and already noise-free. $\endgroup$
    – bill s
    Apr 23, 2013 at 6:55

Your Answer

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

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