【问题标题】:Accurate color quantization of image to minimize color palette图像的准确颜色量化以最小化调色板
【发布时间】:2021-11-11 18:37:08
【问题描述】:

我正在尝试量化图像,以保留所有原色并删除所有次要颜色,例如“抗锯齿”边框。 例如。下面的图像最终应该被量化为 3 种颜色,而原始图像中的实际颜色数量超过 30 种。所有“抗锯齿”边框颜色都应该被视为次要颜色,并在量化以及“jpeg 伪影”时消除,这由于过度优化,为图像添加更多颜色。 注意:源图像可以是 png 或 jpeg。

对于量化本身,我使用 PIL.quantize(...) 和 K 作为要离开的颜色数。而且它的效果相当好,并且使调色板与原始调色板完美匹配。

def color_quantize(path, K):
    image = cv2.imread(path, cv2.IMREAD_UNCHANGED)
    img = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    im_pil = Image.fromarray(np.uint8(img))
    im_pil = im_pil.quantize(K, None, 0, None)
    return cv2.cvtColor(np.array(im_pil.convert("RGB")), cv2.COLOR_RGB2BGR) 

因此,如果我提前知道“K”(原色的数量),那么我会将它用于im_pil.quantize(...)。基本上,我需要一种方法来获得那个“K”数字。 有什么方法可以确定原色的个数吗?

顺便说一句,关于“jpeg artifacts”的删除,我目前正在使用img = cv2.bilateralFilter(img, 9, 75, 75),效果很好。

【问题讨论】:

  • 量化基本上是一种聚类技术。有些聚类方法不需要参数k,它们会找到一组“自然”的聚类。例如 DBSCAN:en.wikipedia.org/wiki/DBSCAN

标签: python image image-processing colors quantization


【解决方案1】:

您可能想尝试分析 RGB 通道的直方图以找出它们有多少个峰值,希望您会有一些大峰值和一些非常小的峰值,那么大峰值的数量应该是您的 K .

【讨论】:

    【解决方案2】:

    我最终得到了以下函数来确定主色的数量:

    def get_dominant_color_number(img, threshold):
        # remove significant artifacts
        img = cv2.bilateralFilter(img, 9, 75, 75) 
    
        # resize image to make the process more efficient on 250x250 (without antialiasing to reduce color space)
        thumbnail = cv2.resize(img, (250, 250), None)
    
        # convert to HSV color space 
        imghsv = cv2.cvtColor(thumbnail, cv2.COLOR_BGR2HSV).astype("float32")
        (h, s, v) = cv2.split(imghsv)
    
        # quantize saturation and value to merge close colors
        v = (v // 30) * 30
        s = (s // 30) * 30
    
        imghsv = cv2.merge([h,s,v])
        thumbnail = cv2.cvtColor(imghsv.astype("uint8"), cv2.COLOR_HSV2BGR)
    
        (unique, counts) = np.unique(thumbnail.reshape(-1, thumbnail.shape[2]), return_counts=True, axis = 0)
    
        # calculate frequence of each color and sort them 
        freq = counts.astype("float")
        freq /= freq.sum()
        count_sort_ind = np.argsort(-counts)
        
        # get frequent colors above the specified threshold
        n = 0
        dominant_colors = []
        
        for (c) in count_sort_ind:
            n += 1;
            dominant_colors.append(unique[c])
            if (freq[c] <= threshold):
               break
    
        return (dominant_colors, n)
    
    # -----------------------------------------------------------
    
    img = cv2.imread("File.png", cv2.IMREAD_UNCHANGED)
    channels = img.shape[2]
    if channels == 4:
       trans_mask = img[:,:,3] == 0
       img[trans_mask] = [254, 253, 254, 255]
       img = cv2.cvtColor(img, cv2.COLOR_BGRA2BGR)
    
    (dom_colors, dom_color_num) = get_dominant_color_number(img, .0045)
    
    

    对于阈值“.0045”,它给出了可接受的结果。然而,它看起来还是有点“人造”。

    【讨论】:

      猜你喜欢
      • 2011-02-12
      • 2011-09-06
      • 2012-11-29
      • 2019-05-27
      • 2016-04-06
      • 1970-01-01
      • 2021-01-10
      • 1970-01-01
      • 2023-03-18
      相关资源
      最近更新 更多