开发者

convert RGB values to equivalent HSV values using python

I want to convert 开发者_开发百科RGB values to HSV using python. I got some code samples, which gave the result with the S and V values greater than 100. (example : http://code.activestate.com/recipes/576554-covert-color-space-from-hsv-to-rgb-and-rgb-to-hsv/ ) . anybody got a better code which convert RGB to HSV and vice versa

thanks


Did you try using the colorsys library?

The colorsys module defines bidirectional conversions of color values between colors expressed in the RGB (Red Green Blue) color space used in computer monitors and three other coordinate systems: YIQ, HLS (Hue Lightness Saturation) and HSV (Hue Saturation Value)

Example (taken from the above link):

>>> import colorsys
>>> colorsys.rgb_to_hsv(.3, .4, .2)
(0.25, 0.5, 0.4)
>>> colorsys.hsv_to_rgb(0.25, 0.5, 0.4)
(0.3, 0.4, 0.2)


If using PIL, with a recent copy of Pillow, one should probably use

def rgb2hsv(image):
    return image.convert('HSV')


Based on array indexing and slicing in numpy, this is my approach for the forward:

import numpy as np

def rgb2hsv(rgb):
    """ convert RGB to HSV color space

    :param rgb: np.ndarray
    :return: np.ndarray
    """

    rgb = rgb.astype('float')
    maxv = np.amax(rgb, axis=2)
    maxc = np.argmax(rgb, axis=2)
    minv = np.amin(rgb, axis=2)
    minc = np.argmin(rgb, axis=2)

    hsv = np.zeros(rgb.shape, dtype='float')
    hsv[maxc == minc, 0] = np.zeros(hsv[maxc == minc, 0].shape)
    hsv[maxc == 0, 0] = (((rgb[..., 1] - rgb[..., 2]) * 60.0 / (maxv - minv + np.spacing(1))) % 360.0)[maxc == 0]
    hsv[maxc == 1, 0] = (((rgb[..., 2] - rgb[..., 0]) * 60.0 / (maxv - minv + np.spacing(1))) + 120.0)[maxc == 1]
    hsv[maxc == 2, 0] = (((rgb[..., 0] - rgb[..., 1]) * 60.0 / (maxv - minv + np.spacing(1))) + 240.0)[maxc == 2]
    hsv[maxv == 0, 1] = np.zeros(hsv[maxv == 0, 1].shape)
    hsv[maxv != 0, 1] = (1 - minv / (maxv + np.spacing(1)))[maxv != 0]
    hsv[..., 2] = maxv

    return hsv

and backward color space conversion:

def hsv2rgb(hsv):
    """ convert HSV to RGB color space

    :param hsv: np.ndarray
    :return: np.ndarray
    """

    hi = np.floor(hsv[..., 0] / 60.0) % 6
    hi = hi.astype('uint8')
    v = hsv[..., 2].astype('float')
    f = (hsv[..., 0] / 60.0) - np.floor(hsv[..., 0] / 60.0)
    p = v * (1.0 - hsv[..., 1])
    q = v * (1.0 - (f * hsv[..., 1]))
    t = v * (1.0 - ((1.0 - f) * hsv[..., 1]))

    rgb = np.zeros(hsv.shape)
    rgb[hi == 0, :] = np.dstack((v, t, p))[hi == 0, :]
    rgb[hi == 1, :] = np.dstack((q, v, p))[hi == 1, :]
    rgb[hi == 2, :] = np.dstack((p, v, t))[hi == 2, :]
    rgb[hi == 3, :] = np.dstack((p, q, v))[hi == 3, :]
    rgb[hi == 4, :] = np.dstack((t, p, v))[hi == 4, :]
    rgb[hi == 5, :] = np.dstack((v, p, q))[hi == 5, :]

    return rgb

I was motivated to write these lines as I wasn't convinced by a pixel-wise conversion due to the computational overload and also did not want to rely on another library such as OpenCV.

Feel free to suggest a modification to make this solution more elegant and generic.


I suggest to work with OpenCV

import cv2

# Read the image - Notice that OpenCV reads the images as BRG instead of RGB
img = cv2.imread('myimage.jpg')

# Convert the BRG image to RGB
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

# Convert the RGB image to HSV
img = cv2.cvtColor(img, cv2.COLOR_RGB2HSV)


If you need to convert an image that is saved as numpy, you should either use:

  1. opencv see answer by George Pipis
  2. skimage:
from skimage.color import rgb2hsv
hsv_img = rgb2hsv(rgb_img)


1.) This is a complete script. It convert RGB(40, 32, 28) to HSV(20, 30, 26)

2.) Usage.

Run this script, in particular the function convert_rgb_to_hsv()

You can edit the variable red, green, blue.

import colorsys

#usage.
#run this script, in particular the function convert_rgb_to_hsv()
#edit red, green, blue



def convert_rgb_to_hsv():
    #rgb normal: range (0-255, 0-255, 0.255)
    red=40
    green=32
    blue=28

    
    
    #get rgb percentage: range (0-1, 0-1, 0-1 )
    red_percentage= red / float(255)
    green_percentage= green/ float(255)
    blue_percentage=blue / float(255)

    
    #get hsv percentage: range (0-1, 0-1, 0-1)
    color_hsv_percentage=colorsys.rgb_to_hsv(red_percentage, green_percentage, blue_percentage) 
    print('color_hsv_percentage: ', color_hsv_percentage)

    
    
    #get normal hsv: range (0-360, 0-255, 0-255)
    color_h=round(360*color_hsv_percentage[0])
    color_s=round(255*color_hsv_percentage[1])
    color_v=round(255*color_hsv_percentage[2])
    color_hsv=(color_h, color_s, color_h)

    print('color_hsv: ', color_hsv)



#INVOCATE MAIN FUNCTION
convert_rgb_to_hsv()


What values of R, G, and B did you put in, and what values of H, S, and V that look erroneous did you get out?

The code you link to, like colorsys, expects float values between 0.0 and 1.0. If you call it with integer values in the 0-to-255 range, you'll get bogus results. It should work fine if you give it the input values it expects.

(It is a distinct failure of that code sample that it does not actually document what sorts of inputs it expects.)


I've looked at the various libraries from opencv, colorsys and PIL.

colorsys is not very accurate but gets within 15 degrees. Most of the time within 3 degress. FOr the others there seems to be minor dependencies over a few degrees, but who is more correct? I don't know. But here is my numpyfied rgb to hsv code. I think it's pretty good but I am sure it could be better optimized somehow. The most obvious would be to combine the H, s, and v. Yes that is there also. Mine's more accurate then colorsys for sure, but you definitely see some small rounding errors. But hey it does the whole array in several steps at least. Sorry no invert code. Maybe another day I will write it. Ok so last thing is I don't assume scale. You have to add your own post scaling for the separate hue, sat, and val. the optional s argument is input scaling to 1, the dhue, dsat and dval are out scaling. And yes this is for 2dim arrays. it shouldn't be hard to fix it to work on while, or just reshape your stuff to 2dim and then back again.

def rgb_hue(rgb, s=1):
  nrgb = rgb.astype(np.float64) / float(s)
  nmax = np.max(nrgb,1)
  ndelta = nmax - np.min(nrgb,1)
  return (np.where(ndelta == 0, 0
      , np.where(nmax == nrgb[:,0], nrgb[:,1]-nrgb[:,2]
      , np.where(nmax == nrgb[:,1], (nrgb[:,2]-nrgb[:,0])+2
      , (nrgb[:,0]-nrgb[:,1])+4))) / 6.) % 1.

def rgb_saturation(rgb, s=1):
  nrgb = rgb.astype(np.float64) / float(s)
  nmax = np.max(nrgb,1)
  ndelta = nmax - np.min(nrgb,1)
  return np.where(nmax == 0, 0, ndelta / nmax)

def rgb_value(rgb, s=1):
  nrgb = rgb.astype(np.float64) / float(s)
  nmax = np.max(nrgb,1)
  return nmax

def rgb_hsv(rgb, s=1, dhue=1, dsat=1, dval=1):
  nrgb = rgb.astype(np.float64) / float(s)
  nmax = np.max(nrgb,1)
  ndelta = nmax - np.min(nrgb,1)
  hue = (np.where(ndelta == 0, 0
      , np.where(nmax == nrgb[:,0], nrgb[:,1]-nrgb[:,2]
      , np.where(nmax == nrgb[:,1], (nrgb[:,2]-nrgb[:,0])+2
      , (nrgb[:,0]-nrgb[:,1])+4))) / 6.) % 1.
  sat = np.where(nmax == 0, 0, ndelta / nmax)
  val = nmax
  return np.column_stack((hue*dhue, sat*dsat, val*dval))
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜