图像的准确颜色量化以最小化调色板
Posted
技术标签:
【中文标题】图像的准确颜色量化以最小化调色板【英文标题】: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 【参考方案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”,它给出了可接受的结果。然而,它看起来还是有点“人造”。
【讨论】:
以上是关于图像的准确颜色量化以最小化调色板的主要内容,如果未能解决你的问题,请参考以下文章