Continued from this question: How could you rewrite a list of lists so that "islands" of values are unique from one another?
Brief: How would you parse an image, for example:
in such a way that you identify the several clusters of distinct pixels and rewrite the file so that each cluster has a unique color, for example:
Here's how I have tried to implement it with assistance from a few sources, including stackoverflow user @Rabinzel: (detailed reasoning below main code block)
from scipy import ndimage
import numpy as np
from PIL import Image
#set the file path to wherever your provinces.png is located
im = Image.open(r"C:\\Users\\scoop\\Desktop\\prov_test.png")
print('-------------------------------------------')
#DEBUGGING: simply prints the format, size, and mode of your file
print(im.format, im.size, im.mode)
#saves the width and depth of the file
im_xsize = im.size[0]
im_ysize = im.size[1]
#DEBUGGING: prints it
print(im_xsize, im_ysize)
#DEBUGGNG: prints data bands, should be R, G, B
print(im.getbands())
#DEBUGGING: prints RGB value of pixel of choice
print(im.getpixel((0,0)))
print('-------------------------------------------')
#creates array for pixel RGBs
rgb_array = [[None] * im_ysize for length in range(0,im_xsize)]
#fills pixel RGB array
for x in range(0,im_xsize):
for y in range(0,im_ysize):
rgb_array[x][y] = im.getpixel((x,y))
#find unique clusters of identical RGB codes
def find_clusters(array):
clustered = np.empty_like(array)
unique_vals = np.unique(array)
cluster_count = 0
for val in unique_vals:
labelling, label_count = ndimage.label(array == val)
for k in range(1, label_count + 1):
clustered[labelling == k] = cluster_count
cluster_count += 1
return clustered, cluster_count
clusters, cluster_count = find_clusters(rgb_array)
print("Found {} clusters:".format(cluster_count))
#print(clusters)
#defining a list of unique colors
province_color_list = [[0] * 3 for length in range(0,cluster_count)]
#DEBUGGING
print('province count...', cluster_count)
#variables
r = 255
g = 0
b = 0
count = 0
#generating colors
for length in range(0,cluster_count):
province_color_list[length][0] = r
province_color_list[length][1] = g
province_color_list[length][2] = b
g += 25
b += 25
count += 1
if count >= 11:
r -= 1
g = 0
b = 0
count = 0
#DEBUGGING
print('# of colors... ', len(province_color_list))
print(province_color_list)
print('-------------------------------------------')
#writing colors to pixels
for x in range(0,im_xsize):
for y in range(0,im_ysize):
#places province color based on which province current pixel is assigned to
im.putpixel((x,y), (province_color_list[0][0], province_color_list[0][1], province_color_list[0][2]))
#im.save(r"C:\\Users\\scoop\\Desktop\\prov_test.png", im.format)
I load the image using PIL:
im = Image.open(r"C:\\Users\\scoop\\Desktop\\prov_test.png")
I create an array to more easily(?) access the image array, which stores each pixel's color as an RGB color code in tuple form. Then this method identifies the relevant pixel clusters.
rgb_array = [[None] * im_ysize for length in range(0,im_xsize)]
#fills pixel RGB array
for x in range(0,im_xsize):
for y in range(0,im_ysize):
rgb_array[x][y] = im.getpixel((x,y))
#find unique clusters of identical RGB codes
def find_clusters(array):
clustered = np.empty_like(array)
unique_vals = np.unique(array)
cluster_count = 0
for val in unique_vals:
labelling, label_count = ndimage.label(array == val)
for k in range(1, label_count + 1):
clustered[labelling == k] = cluster_count
cluster_count += 1
return clustered, cluster_count
clusters, cluster_count = find_clusters(rgb_array)
Then I create a list of unique RGB codes the length of the # of pixel clustes that exist.
province_color_list = [[0] * 3 for length in range(0,cluster_count)]
#DEBUGGING
print('province count...', cluster_count)
#variables
r = 255
g = 0
b = 0
count = 0
#generating colors
for length in range(0,cluster_count):
province_color_list[length][0] = r
province_color_list[length][1] = g
province_color_list[length][2] = b
g += 25
b += 25
count += 1
if count >= 11:
r -= 1
g = 0
b = 0
count = 0
and finally, I rewrite each pixel with the new RGB code associated with the unique cluster from earlier (and save the image).
#writing colors to pixels
for x in range(0,im_xsize):
for y in range(0,im_ysize):
#places province color based on which province current pixel is assigned to
im.putpixel((x,y), (province_color_list[clusters[x][y]][0], province_color_list[clusters[x][y]][1], province_color_list[clusters[x][y]][2]))
#im.save(r"C:\\Users\\scoop\\Desktop\\prov_test.png", im.format)
Unfortunately there's multiple issues with this script and I get the feeling its degenerated into a bit of nonsense. The chief issues seem to be accessing the RGB tuples of the .PNG Image class and changing them to integers to identify them properly as well as differentiating between distinct clusters not just distinct colors. I haven't even been able to get the script to write the image as anything but a flat color so far.
For reference, I hope to be able to scale this up to handle an image like this:
and give each of those little clusters a unique color. Any and all help appreciated.




