读取 .PNG 时,如何识别颜色簇并重写图像文件,以便每个簇都有唯一的 RGB 代码?

2023-12-05

继续这个问题:如何重写一个列表列表,以使值的“孤岛”彼此唯一?

简介:您将如何解析图像,例如:

example input

通过这种方式,您可以识别不同像素的几个簇并重写文件,以便每个簇都有唯一的颜色,例如:

example output

以下是我如何在一些来源的帮助下尝试实现它,包括 stackoverflow 用户 @Rabinzel:(主代码块下方的详细推理)

    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)

我使用 PIL 加载图像:

im = Image.open(r"C:\\Users\\scoop\\Desktop\\prov_test.png")

我创建了一个数组来更轻松地(?)访问图像数组,该数组将每个像素的颜色存储为元组形式的 RGB 颜色代码。然后该方法识别相关的像素簇。

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)

然后,我创建一个唯一 RGB 代码的列表,其长度为现有像素簇的数量。

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

最后,我使用与之前的唯一簇关联的新 RGB 代码重写每个像素(并保存图像)。

#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)

不幸的是,这个脚本存在多个问题,我感觉它已经退化成了一些废话。主要问题似乎是访问 .PNG Image 类的 RGB 元组并将它们更改为整数以正确识别它们以及区分不同的簇而不仅仅是不同的颜色。到目前为止,我什至无法让脚本将图像写成除平面颜色之外的任何内容。

作为参考,我希望能够将其放大以处理如下图像:

enter image description here

并给每个小簇赋予独特的颜色。任何和所有的帮助表示赞赏。


好的,让我们看看这是否适合您。如果我正确理解了您想要实现的目标,那么这是我的(初学者)解决方案。

本质上,我在 3D 数组中获取图像,找到图片中所有唯一的颜色,并将它们替换为整数(函数:arr_to_int)。然后找到所有具有该函数的簇find_clusters。使用新颜色创建一个字典,其颜色数量与簇的数量相同(因此每个簇的每个整数都会再次替换为颜色)。 最后再次将所有 int 替换为颜色并保存图片。

这是我用来开始的图像:

enter image description here

这就是我作为输出得到的新图片:

enter image description here

如果您更改如何将它们集群应用到您想要使用的特定颜色的过程,我想我非常接近您想要实现的目标(希望如此:))

import numpy as np
import cv2
from scipy import ndimage

# array of GBR colors to single int
def arr_to_int(arr, col_mask):
    out = np.ndarray(shape=arr.shape[:2], dtype=int)
    out[:,:] = -1
    for rgb, idx in col_mask.items():
        out[(arr==rgb).all(2)] = idx
    return out

# 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
# Load image
im = cv2.imread("prov_test.png")
#im = cv2.resize(im, (2, 3)) #resize for debugging
#print('original image: \n', im, '\n')

#find all unique colors in image (cv2 presents in BGR format!!!)
unique_col_BGR = list(set(tuple(v) for m2d in im for v in m2d))
print('unique values: ', unique_col_BGR, '\n')

#create dict with GBR_colors as keys and unique integers as value
mask_GBR_int = {color:idx for idx,color in enumerate(unique_col_BGR)}
print('mask dict: ', mask_GBR_int, '\n')

#change all color values in im to a single int (mask)
im_with_ints = arr_to_int(im, mask_GBR_int)
#print('pic with mask values: \n', im_with_ints, '\n')

# due to replacing array of 3 values to a single int, new array has one dimension less
print('orig pic resized shape', im.shape)
print('Mask int pic shape', im_with_ints.shape, '\n')

clusters, cluster_count = find_clusters(im_with_ints)
print(f'Found {cluster_count} clusters', '\n')
#print(clusters)

#create dict with length equal to number of clusters and choose color of list_of_colors (random from the internet)
list_of_colors = [[192,192,192],[128,128,128],[128,0,0],[128,128,0],[0,128,0],[128,0,128],[0,128,128],[0,0,128],[255,0,0],[0,255,0],[0,0,255],[255,255,0],[0,255,255],[255,0,255]]
new_color_dict = {idx:val for idx,val in enumerate(list_of_colors[:cluster_count])}
print('new_color_dict: ', new_color_dict,'\n')

#change arr with int to colors again
res = np.array([*new_color_dict.values()])[clusters]
#print('image array with new colors: \n', res)

cv2.imwrite("prov_test_output.png", res)


Output:

unique values:  [(0, 255, 0), (255, 0, 0), (0, 0, 255), (0, 255, 255)] 

mask dict:  {(0, 255, 0): 0, (255, 0, 0): 1, (0, 0, 255): 2, (0, 255, 255): 3} 

orig pic resized shape (100, 100, 3)
Mask int pic shape (100, 100) 

Found 9 clusters 

new_color_dict:  {0: [192, 192, 192], 1: [128, 128, 128], 2: [128, 0, 0], 3: [128, 128, 0], 4: [0, 128, 0], 5: [128, 0, 128], 6: [0, 128, 128], 7: [0, 0, 128], 8: [255, 0, 0]} 


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

读取 .PNG 时,如何识别颜色簇并重写图像文件,以便每个簇都有唯一的 RGB 代码? 的相关文章

随机推荐