I need to divide an image to regions of pixels whose RGB value pass a certain test.
I'm OK with scanning the image and checking each pixel's value however the part of clustering them into regions and then getting those regions coordinates (x, y, width, height) leaves me in total dark :)
here's the code I have so far
from PIL import Image
def detectRedRegions(PILImage):
image = PILImage.load()
width, height = PILImage.size
reds = []
h = 0
while h < height:
w = 0
while w < width:
px = image[w, h]
if is_red(px):
reds.append([w, h])
# Here's where I'm being clueless
w +=1
h +=1
I read tons about clustering but just can't wrap my head around this subject any code example s that will fit my needs will be great (and hopefully enlightening
Thanks!
What you want is called area labeling or connected component detection in image processing. There is an implementation provided in the scipy.ndimage package. So the following should work provided you have numpy + scipy installed
[EDIT]
While the solution below works, it can be made better. Here is a version with better names and better performance:
Unlike
disjoint_areas()
below,closed_regions()
returns sets of pixel coordinates instead of their bounding boxes.Also, if we use flooding instead of the connected components algorithm, we can make it even simpler and about twice as fast:
It was inspired by Eric S. Raymond's version of floodfill.
[/EDIT]
One could probably use floodfill, but I like this:
Here, pairs of neighboring pixels that both satisfy
is_black_enough()
are interpreted as edges in a graph. Also, every pixel is viewed as its own neighbor. Due to this re-interpretation we can use the connected component algorithm for graphs which is quite easy to implement. The result is the sequence of the bounding boxes of all areas who's pixels satisfyis_black_enough()
.