Выбор цвета Python Pillow HSV; сделать его более конкретным

Я работаю над веб-приложением, которое позволит вам редактировать изображения с использованием цветов, например, раскрашивая черно-белое изображение или переключая цвет автомобиля на цветное изображение.

Мой первый подход к выбору цвета заключался в том, чтобы сэмплировать цвет в rgb, а затем работать с ним. Проблема с rgb заключается в том, что цветовая вариация настолько велика, что, выбирая похожие оттенки фиолетового на изображении, вы можете в конечном итоге повторно выбрать несколько раз и все еще иметь маленькие квадратики, где вы еще не пробовали их. Например, вот исходное изображение:

Выбор цвета Python Pillow HSV; сделать его более конкретным

Используя веб-приложение, я выбираю небольшую область между изображением для выборки цветов, а затем показываю, где цвета совпадают ниже.

Выбор цвета Python Pillow HSV; сделать его более конкретным

вы можете сказать, что у него есть небольшая область прямоугольника и маленькие пятна снаружи, где совпадает цвет.

Я провел некоторое исследование и обнаружил, что HSV, который представляет собой оттенок, насыщенность и значение, является более простым способом выбора оттенков цветов.

Таким образом, используя тот же метод, веб-приложение предоставляет интересующую область, я, как обычно, получаю интересующую область, а затем, если использую hsv, получаю значение оттенка интересующей области и использую его для проверки изображения, все пиксели с одинаковыми значение hue, и оно возвращается как новая область выбора и затем используется для выборки всех этих новых пикселей для цветов.

Это код ниже

def get_hsv_positions(image, positions):
    #hsv comes in hue (color of image), saturation and value that's supposed to be how light or dark the color is
    hsv_image = image.convert('HSV')

    values = []

    for pixel in positions:
        values.append(hsv_image.getpixel(tuple(pixel)))

    hues = set([x[0] for x in values])
    hue_matches = []

    width, height = image.size

    img_width, img_height = 0,0

    for _ in range(width * height):
        if img_width == width:
            img_height += 1
            img_width = 0

        pixel = hsv_image.getpixel((img_width, img_height))
        if pixel[0] in hues:
            hue_matches.append((img_width, img_height))

        img_width += 1

    return hue_matches

def get_color_range(request):
    ...

    #this gets the x,y position on the image of interest to sample colors
    cells = []
    for item in selection:
        pos = get_position(item['position']['left'], item['position']['top'], image.width, image.height, width, height)
        item['position']['top'] = pos[1]
        item['position']['left'] = pos[0]

        scale_grid(item, width, height, image.width, image.height)
        cells.extend(get_cells(item))

    image = PILImage.open(image_url)

    if hsv:
        cells = get_hsv_positions(image, cells)

и вот как он теперь сэмплирует изображение

Выбор цвета Python Pillow HSV; сделать его более конкретным

это лучше, но не идеально, как вы можете сказать здесь

Выборка исходного изображения телесного цвета

Выбор цвета Python Pillow HSV; сделать его более конкретным

Выборка с использованием HSV

Выбор цвета Python Pillow HSV; сделать его более конкретным

Выборка без использования HSV

Выбор цвета Python Pillow HSV; сделать его более конкретным

Как вы можете сказать, HSV получает больше тех маленьких тонов, которые появляются в виде маленьких фигур на изображении, но не получают их все.

Я надеюсь, что кто-то, кто играл с манипулированием изображениями, будь то для науки о данных или чего-то еще, может помочь.

Кроме того, это проект с открытым исходным кодом, который я создал и над которым работаю в свободное время, поэтому, если вам интересно, вы можете проверить исходный код, вот видео краткое введение о том, как это работает. Так что, если вы хотите внести свой вклад, вы знаете каналы :) или используйте его бесплатно, как вам удобно.

Некоторые направления, чтобы попробовать (но не полный ответ): со вторым изображением (или для вашей идеи «автомобиля») похоже, что сегментация может помочь. Вы смотрели на «водораздел» opencv? Кроме того, участки, которые вы пропустили, имеют квадратную форму, что заставляет меня думать, что они могут быть связаны со сжатием JPEG, и может помочь фильтр Гаусса с учетом границ.

Pam 02.04.2019 15:58

Что-либо в цветовом пространстве HSV часто становится безумным и блочным после сжатия JPEG - я думаю, что это может иметь какое-то отношение к понижению дискретизации цветности, но никогда не исследовал это.

Mark Setchell 02.04.2019 22:31
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
2
1 177
1

Ответы 1

Решение, которое приходит на ум, состоит в том, чтобы размыть канал оттенка вашего изображения при выборе пикселей в диапазоне. Это должно сгладить резкие изменения оттенка (например, квадратные артефакты на портрете).

Один из способов сделать это — преобразовать канал оттенка в пустой массив, применить фильтр Гаусса, а затем использовать его для создания маски. Это грубая переработка вашей функции get_hsv_positions, которая использует numpy и scipy вместо циклов.

import numpy as np
from scipy.ndimage import gaussian_filter

def get_hsv_positions_smooth(image, positions):
    #hsv comes in hue (color of image), saturation and value that's supposed to be how light or dark the color is
    hsv_image = image.convert('HSV')

    # convert to numpy array
    hsv_image = np.array(hsv_image)
    hue_channel = hsv_image[0, :, :]  # indexed (channel, row, column)

    # get the matching hues
    matching_hues = set()
    for x,y in positions:
        matching_hues.add(hue_channel[x, y])

    # blur hue channel
    SIGMA = 2
    blurred_hue = gaussian_filter(hue_channel, SIGMA)

    # mask the matching values
    mask = np.isin(blurred_hue, matching_hues)

    # get a list of [(x, y), ...] true values in the mask
    xs, ys = np.nonzero(mask)
    return zip(xs, ys)

Стоит отметить, что вы можете исследовать другие виды размытия, которые имеют другие свойства.

Редактировать: Я переместил предыдущее решение вниз, потому что думаю, что размытие, вероятно, даст вам лучшие результаты.

Одним из решений может быть искусственное сглаживание/расширение hues списка разрешенных оттенков. В данной области интереса выбранные вами оттенки могут не быть непрерывными (например, темно-синий и голубой, но не синие между ними) и могут прерываться на неестественном пороге.

Я бы предложил превратить hues в np.array, чтобы было немного проще выполнять такие манипуляции. Если бы ваш массив hues выглядел примерно как [30, 31, ..., 40, 230, 231, ..., 240], вы могли бы сгладить его с помощью

import numpy as np

hues = np.array(hues)  # numpy it
blended_hues = np.concatenate([
    hues + 1, hues + 2, ...  # as many points out as you want
    hues - 1, hues - 2, ...
])
all_hues = list(np.unique(np.concatenate([hues, blended_hues])))

И тогда у all_hues будут ваши оригинальные оттенки с некоторыми дополнениями.

Другим решением может быть просмотр цветовых пространств МКО. В них обычно X и Y оттенки расширены в двух измерениях, так что вы можете сделать более сложное смешивание цветов.

Я понимаю, что вы имеете в виду, я попробую и посмотрю, как это работает

Sam B. 02.04.2019 15:58

Также эта реализация hues = set([x[0] for x in values]) hues = np.array(hues) # numpy it blended_hues = np.concatenate([ hues + 1, hues + 2, hues - 1, hues - 2, ]) all_hues = list(np.unique(np.concatenate([hues, blended_hues]))) выдает эту ошибку File "/home/sam/code/pixelart/pixelart/views.py", line 430, in get_hsv_positions hues + 1, hues + 2, TypeError: unsupported operand type(s) for +: 'set' and 'int'

Sam B. 02.04.2019 16:08

Вам нужно будет изменить строку с hues = np.array(hues) на hues = np.array(list(hues)). Массивы Numpy упорядочены и не поддерживают приведение напрямую из set объектов. В качестве альтернативы просто удалите часть set(...) в начале — значения в любом случае будут сделаны уникальными с помощью np.unique(...).

Andrew F 02.04.2019 16:40

это работает, но немного перебарщивает и пробует цвета, такие как цвет ее помады, который намного меньше похож на цвет кожи.

Sam B. 02.04.2019 19:20

Я добавил еще одно решение, которое включает сглаживание канала оттенка. Это также должно сделать совпадающие области немного более гладкими.

Andrew F 03.04.2019 13:24

Получение этой ошибки с вашей реализацией matching_hues.add(hue_channel[x, y]) IndexError: only integers, slices (:), ellipsis (...), numpy.newaxis (None) and integer or boolean arrays are valid indices

Sam B. 06.04.2019 16:27

Я только что получил шанс проверить это. Я перепутал индексы на hue_channel = hsv_image[...]. Нарезка [:, :, 0] испортила x, y координаты, что привело к ошибке вашего индекса. Правильный порядок нарезки массивов numpy — [channel, row, column], поэтому я изменил строку на hue_channel = hsv_image[0, :, :]. Извини за это! Здесь — полезная статья о нарезке Numpy!

Andrew F 08.04.2019 11:04

Он по-прежнему возвращает ту же ошибку File "/home/sam/code/pixelart/pixelart/views.py", line 493, in get_color_range cells = get_hsv_positions_smooth(image, cells) File "/home/sam/code/pixelart/pixelart/views.py", line 458, in get_hsv_positions_smooth matching_hues.add(hue_channel[x, y]) IndexError: only integers, slices (:), ellipsis (...), numpy.newaxis (None) and integer or boolean arrays are valid indices [09/Apr/2019 06:51:13] "POST /color-range HTTP/1.1" 500 16846

Sam B. 09.04.2019 08:52

Другие вопросы по теме