Существует ряд проблем с вашим вопросом и предположениями.
Вы не можете считать цвета с np.unique(image)
Вы не можете считать цвета на изображении с помощью np.unique(im)
. Давайте посмотрим, почему, сделав случайное изображение всего с 4 интенсивностями: 0,1,2 и 3.
import numpy as np
import cv2
# Ensure repeatable, deterministic randomness!
np.random.seed(42)
# Make a random image
im = np.random.randint(0,4,(480,640,3), dtype=np.uint8)
Это выглядит так, где каждая строка является триплетом RGB для одного пикселя:
array([[[2, 2, 3],
[3, 2, 1],
[2, 2, 0],
...,
[3, 3, 2],
[0, 0, 1],
[1, 1, 1]],
...,
[3, 3, 1],
[2, 3, 0],
[0, 1, 3]]], dtype=uint8)
Теперь, если вы попытаетесь получить уникальные цвета, подобные этим, это не сработает, потому что каждый цвет представляет собой комбинацию с 3 интенсивностями:
np.unique(im) # prints: array([0, 1, 2, 3], dtype=uint8)
Принимая во внимание, что если вы хотите количество уникальных цветов, вам нужно искать количество уникальных комбинаций трех значений RGB / BGR:
np.unique(im.reshape(-1, im.shape[2]), axis=0)
, который дает вектор уникальных RGB / BGR-триплетов на изображении - каждая строка представляет собой уникальную комбинацию цветов:
array([[0, 0, 0],
[0, 0, 1],
[0, 0, 2],
[0, 0, 3],
[0, 1, 0],
[0, 1, 1],
[0, 1, 2],
[0, 1, 3],
[0, 2, 0],
[0, 2, 1],
[0, 2, 2],
[0, 2, 3],
[0, 3, 0],
[0, 3, 1],
[0, 3, 2],
[0, 3, 3],
[1, 0, 0],
[1, 0, 1],
[1, 0, 2],
[1, 0, 3],
[1, 1, 0],
[1, 1, 1],
[1, 1, 2],
[1, 1, 3],
[1, 2, 0],
[1, 2, 1],
[1, 2, 2],
[1, 2, 3],
[1, 3, 0],
[1, 3, 1],
[1, 3, 2],
[1, 3, 3],
[2, 0, 0],
[2, 0, 1],
[2, 0, 2],
[2, 0, 3],
[2, 1, 0],
[2, 1, 1],
[2, 1, 2],
[2, 1, 3],
[2, 2, 0],
[2, 2, 1],
[2, 2, 2],
[2, 2, 3],
[2, 3, 0],
[2, 3, 1],
[2, 3, 2],
[2, 3, 3],
[3, 0, 0],
[3, 0, 1],
[3, 0, 2],
[3, 0, 3],
[3, 1, 0],
[3, 1, 1],
[3, 1, 2],
[3, 1, 3],
[3, 2, 0],
[3, 2, 1],
[3, 2, 2],
[3, 2, 3],
[3, 3, 0],
[3, 3, 1],
[3, 3, 2],
[3, 3, 3]], dtype=uint8)
Или, как простое число уникальных цветов:
len(np.unique(im.reshape(-1, im.shape[2]), axis=0)) # prints 64
Итак, для вашего изображения:
# Open image
im = cv2.imread('image.png',cv2.IMREAD_UNCHANGED)
# Count unique colours
len(np.unique(im.reshape(-1, im.shape[2]), axis=0) # prints 790
Цветов больше, чем вы ожидаете
Почему у меня больше цветов, чем я ожидаю? Две наиболее распространенные причины:
- изображение было сохранено в формате JPEG
- есть текст или нарисованные фигуры, которые были сглажены
Давайте посмотрим, как сохранение в виде JPEG портит вам жизнь!
# Load image and count colours
im = cv2.imread('image.png',cv2.IMREAD_UNCHANGED)
len(np.unique(im.reshape(-1, im.shape[2]), axis=0)) # prints 790
# Save as JPEG
cv2.imwrite('temp.jpg',im)
# Reload and recount just the same
im = cv2.imread('temp.jpg',cv2.IMREAD_UNCHANGED)
len(np.unique(im.reshape(-1, im.shape[2]), axis=0)) # prints 4666 !!!
Как я могу палитрировать изображение - (уменьшить цвета до фиксированной палитры)?
Если вы хотите создать палитру своего изображения в соответствии со своей собственной палитрой, сначала вам нужно указать свою палитру в порядке BGR (!
), чтобы соответствовать порядку OpenCV:
palette = np.array([
[0,0,0], # Black
[93,136,106], # Green
[208,224,64], # Blue
[85,124,168]], # Brown
dtype=np.uint8)
Затем прочитайте ваше изображение, отбрасывая совершенно бессмысленный альфа-канал:
test = cv2.imread("image.png",cv2.IMREAD_COLOR)
Затем вычислите расстояние до каждой записи палитры для каждого пикселя:
distance = np.linalg.norm(test[:,:,None] - palette[None,None,:], axis=3)
Затем выберите любой из цветов палитры, ближайший к каждому пикселю:
palettised = np.argmin(distance, axis=2).astype(np.uint8)
Ваше изображение теперь находится в массиве palettised
, и в каждом месте расположения пикселя хранится индекс ближайшего цвета в вашей палитре, поэтому, поскольку ваша палитра имеет 4 записи (0..3), все элементы вашего изображения 0, 1, 2 или 3.
Итак, теперь вы можете умножить на 85 с:
result = palettised * 85