Обнаружение порогов в цветовом пространстве HSV (из RGB) с использованием Python / PIL - PullRequest
9 голосов
/ 03 февраля 2011

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

В настоящее время я создаю новыйimage, затем создайте список новых значений пикселей, перебирая его данные, затем .putdata() этот список для формирования нового изображения.

Такое чувство, что должен быть гораздо более быстрый способ сделать это, например, с.point(), но, похоже, .point() не получает данные пиксели, а вместо этого имеет значения от 0 до 255.Есть ли .point() преобразование, но в пикселях?

Ответы [ 4 ]

21 голосов
/ 03 февраля 2011

Хорошо, это работает (исправлено несколько ошибок переполнения):

import numpy, Image
i = Image.open(fp).convert('RGB')
a = numpy.asarray(i, int)

R, G, B = a.T

m = numpy.min(a,2).T
M = numpy.max(a,2).T

C = M-m #chroma
Cmsk = C!=0

# Hue
H = numpy.zeros(R.shape, int)
mask = (M==R)&Cmsk
H[mask] = numpy.mod(60*(G-B)/C, 360)[mask]
mask = (M==G)&Cmsk
H[mask] = (60*(B-R)/C + 120)[mask]
mask = (M==B)&Cmsk
H[mask] = (60*(R-G)/C + 240)[mask]
H *= 255
H /= 360 # if you prefer, leave as 0-360, but don't convert to uint8

# Value
V = M

# Saturation
S = numpy.zeros(R.shape, int)
S[Cmsk] = ((255*C)/V)[Cmsk]

# H, S, and V are now defined as integers 0-255

Оно основано на определении HSV в Википедии.Я посмотрю это, когда у меня будет больше времени.Определенно есть ускорения и, возможно, ошибки.Пожалуйста, дайте мне знать, если найдете.ура.


Результаты:

начиная с этого цвета: enter image description here

Я получаю следующие результаты:

Оттенок:

enter image description here

Значение:

enter image description here

Насыщенность:

enter image description here

5 голосов
/ 04 февраля 2011

EDIT 2: теперь он возвращает те же результаты, что и код Пола, как и должно ...

import numpy, scipy

image = scipy.misc.imread("test.png") / 255.0

r, g, b = image[:,:,0], image[:,:,1], image[:,:,2]
m, M = numpy.min(image[:,:,:3], 2), numpy.max(image[:,:,:3], 2)
d = M - m

# Chroma and Value
c = d
v = M

# Hue
h = numpy.select([c ==0, r == M, g == M, b == M], [0, ((g - b) / c) % 6, (2 + ((b - r) / c)), (4 + ((r - g) / c))], default=0) * 60

# Saturation
s = numpy.select([c == 0, c != 0], [0, c/v])

scipy.misc.imsave("h.png", h)
scipy.misc.imsave("s.png", s)
scipy.misc.imsave("v.png", v)

, что дает оттенок от 0 до 360, насыщенность от 0 до 1 и значение от 0 до 1Я посмотрел на результаты в формате изображения, и они кажутся хорошими.

Я не был уверен, прочитав ваш вопрос, было ли это только "значение", как в V из HSV, которое вас заинтересовало. Еслиэто так, тогда вы можете обойти большую часть этого кода.

Затем вы можете выбрать пиксели на основе этих значений и установить их в 1 (или белый / черный), используя что-то вроде:

newimage = (v > 0.3) * 1
2 голосов
/ 29 июня 2013

Это решение основано на коде Пола.Я исправил ошибку DivByZero и внедрил RGB в HSL.Существует также HSL для RGB:

import numpy

def rgb_to_hsl_hsv(a, isHSV=True):
    """
    Converts RGB image data to HSV or HSL.
    :param a: 3D array. Retval of numpy.asarray(Image.open(...), int)
    :param isHSV: True = HSV, False = HSL
    :return: H,S,L or H,S,V array
    """
    R, G, B = a.T

    m = numpy.min(a, 2).T
    M = numpy.max(a, 2).T

    C = M - m #chroma
    Cmsk = C != 0

    # Hue
    H = numpy.zeros(R.shape, int)
    mask = (M == R) & Cmsk
    H[mask] = numpy.mod(60 * (G[mask] - B[mask]) / C[mask], 360)
    mask = (M == G) & Cmsk
    H[mask] = (60 * (B[mask] - R[mask]) / C[mask] + 120)
    mask = (M == B) & Cmsk
    H[mask] = (60 * (R[mask] - G[mask]) / C[mask] + 240)
    H *= 255
    H /= 360 # if you prefer, leave as 0-360, but don't convert to uint8


    # Saturation
    S = numpy.zeros(R.shape, int)

    if isHSV:
        # This code is for HSV:
        # Value
        V = M

        # Saturation
        S[Cmsk] = ((255 * C[Cmsk]) / V[Cmsk])
        # H, S, and V are now defined as integers 0-255
        return H.swapaxes(0, 1), S.swapaxes(0, 1), V.swapaxes(0, 1)
    else:
        # This code is for HSL:
        # Value
        L = 0.5 * (M + m)

        # Saturation
        S[Cmsk] = ((C[Cmsk]) / (1 - numpy.absolute(2 * L[Cmsk]/255.0 - 1)))
        # H, S, and L are now defined as integers 0-255
        return H.swapaxes(0, 1), S.swapaxes(0, 1), L.swapaxes(0, 1)


def rgb_to_hsv(a):
    return rgb_to_hsl_hsv(a, True)


def rgb_to_hsl(a):
    return rgb_to_hsl_hsv(a, False)


def hsl_to_rgb(H, S, L):
    """
    Converts HSL color array to RGB array

    H = [0..360]
    S = [0..1]
    l = [0..1]

    http://en.wikipedia.org/wiki/HSL_and_HSV#From_HSL

    Returns R,G,B in [0..255]
    """

    C = (1 - numpy.absolute(2 * L - 1)) * S

    Hp = H / 60.0
    X = C * (1 - numpy.absolute(numpy.mod(Hp, 2) - 1))

    # initilize with zero
    R = numpy.zeros(H.shape, float)
    G = numpy.zeros(H.shape, float)
    B = numpy.zeros(H.shape, float)

    # handle each case:

    mask = (Hp >= 0) == ( Hp < 1)
    R[mask] = C[mask]
    G[mask] = X[mask]

    mask = (Hp >= 1) == ( Hp < 2)
    R[mask] = X[mask]
    G[mask] = C[mask]

    mask = (Hp >= 2) == ( Hp < 3)
    G[mask] = C[mask]
    B[mask] = X[mask]

    mask = (Hp >= 3) == ( Hp < 4)
    G[mask] = X[mask]
    B[mask] = C[mask]

    mask = (Hp >= 4) == ( Hp < 5)
    R[mask] = X[mask]
    B[mask] = C[mask]

    mask = (Hp >= 5) == ( Hp < 6)
    R[mask] = C[mask]
    B[mask] = X[mask]

    m = L - 0.5*C
    R += m
    G += m
    B += m

    R *=255.0
    G *=255.0
    B *=255.0

    return R.astype(int),G.astype(int),B.astype(int)

def combineRGB(r,g,b):
    """
    Combines separated R G B arrays into one array = image.
    scipy.misc.imsave("rgb.png", combineRGB(R,G,B))
    """
    rgb = numpy.zeros((r.shape[0],r.shape[1],3), 'uint8')
    rgb[..., 0] = r
    rgb[..., 1] = g
    rgb[..., 2] = b
    return rgb
1 голос
/ 03 февраля 2011

Я думаю, что самый быстрый результат будет через NumPy.Функция будет выглядеть примерно так ( updated , добавлено более подробное описание в качестве примера):

limg = im.convert("L", ( 0.5, 0.5, 0.5, 0.5 ) )
na = numpy.array ( limg.getdata() )
na = numpy.piecewise(na, [ na > 128 ], [255, 0])
limg.pytdata(na)
limg.save("new.png")

В идеале, вы можете использовать кусочную функцию без предварительного преобразования в черно-белое изображение, которое будетбольше похоже на оригинальный пример.Синтаксис будет выглядеть примерно так:

na = numpy.piecewise(na, [ na[0] > 128 ], [255, 0])

Но вы должны быть осторожны, поскольку RGB-изображение - это кортеж с возвращаемым значением 3 или 4.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...