2

I have an Image (or several hundreds of them) that need to be analyzed. The goal is to find all black spots close to each other.

For example all black spots with a Horizontal distance of 160 pixel and vertical 40 pixel.

Just a small part of an image

For now I just look at each Pixel and if there is a black pixel I call a recursive Method to find its neighbours (i can post the code too if you want to)

It works, but its very slow. At the moment the script runs about 3-4 minutes depending on image size.

Is there some easy/fast way to accomplish this (best would be a scikit-image method to help out here) I'm using Python.

edit: I tried to use scikit.measure.find_contours, now i have an array with arrays containing the contours of the black spots. Now I only need to find the contours in the neighbourhood of these contours.

Ulf Gjerdingen
  • 1,414
  • 3
  • 16
  • 20
Kuchen
  • 108
  • 7

3 Answers3

2

When you get the coordinates of the different black spots, rather than computing all distances between all pairs of black pixels, you can use a cKDTree (in scipy.spatial, http://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.cKDTree.html#scipy.spatial.cKDTree). The exact method of cKDTree to use depends on your exact criterion (you can for example use cKDTree.query_ball_tree to know whether there exists a pair of points belonging to two different labels, with a maximal distance that you give).

KDTrees are a great method to reduce the complexity of problems based on neighboring points. If you want to use KDTrees, you'll need to rescale the coordinates so that you can use one of the classical norms to compute the distance between points.

  • This is pretty nice to get the distance of the different regions and also really fast compared to my own method. The only problem is, I only get the distance in a radius. but the distance is need is different horizontically and vertically. For Example 100px in x-Axis and 40 px in y-Axis. Do you know a way to find the distance in one direction this fast? – Kuchen Aug 11 '16 at 10:40
1

Disclaimer: I'm not proficient with the scikit image library at all, but I've tackled similar problems using MATLAB so I've searched for the equivalent methods in scikit, and I hope my findings below help you.

First you can use skimage.measure.label which returns label_image, i.e. an image where all connected regions are labelled with the same number. I believe you should call this function with background=255 because from your description it seems that the background in your images is the while region (hence the value 255).

This is essentially an image where the background pixels are assigned the value 0 and the pixels that make up each (connected) spot are assigned the value of an integer label, so all the pixels of one spot will be labelled with the value 1, the pixels of another spot will be labelled with the value 2, and so on. Below I'll refer to "spots" and "labelled regions" interchangeably.

You can then call skimage.measure.regionprops, that takes as input the label_image obtained in the previous step. This function returns a list of RegionProperties (one for each labelled region), which is a summary of properties of a labelled region.

Depending on your definition of

The goal is to find all black spots close to each other.

there are different fields of the RegionProperties that you can use to help solve your problem:

  • bbox gives you the set of coordinates of the bounding box that contains that labelled region,
  • centroid gives you the coordinates of the centroid pixel of that labelled region,
  • local_centroid gives you the centroid relative to the bounding box bbox

(Note there are also area and bbox_area properties which you can use to decide whether to throw away very small spots that you might not be interested in, thus reducing computation time when it comes to comparing proximity of each pair of spots)

If you're looking for a coarse comparison, then comparing the centroid or local_centroid between each pair of labelled regions might be enough.

Otherwise you can use the bbox coordinates to measure the exact distance between the outer bounds of any two regions.

If you want to base the decision on the precise distance between the pixel(s) of each pair of regions that are closest to each other, then you'll likely have to use the coords property.

etsetnj
  • 38
  • 1
  • 6
  • Thank you for your answer. The coords property es exactly what i needed. Now i Just need to get the vertikal/horizontal distance between each pixel. But I think that shouldnt be a problem. – Kuchen Aug 10 '16 at 11:20
1

If your input image is binary, you could separate your regions of interest as follows:

  1. "grow" all the regions by the expected distance (actually half of it, as you grow from "both sides of the gap") with binary_dilation, where the structure is a kernel (e.g. rectangular: http://scikit-image.org/docs/dev/api/skimage.morphology.html#skimage.morphology.rectangle) of, let's say, 20x80pixels;
  2. use the resulting mask as an input to skimage.measure.label to assign different values for different regions' pixels;
  3. multiply your input image by the mask created above to zero dilated pixels.

Here are the results of proposed method on your image and kernel = rectange(5,5):

Dilated binary image (output of step 1):

enter image description here

Labeled version of the above (output of step 2):

enter image description here

Multiplication results (output of step 3):

enter image description here

soupault
  • 6,089
  • 4
  • 24
  • 35