# Request for help with Image color space conversion

Discussion in 'Python' started by ttest, Jan 4, 2008.

1. ### ttestGuest

Hello,

I'm working on an image processing project using the Python Imaging
Library along with numpy. Right now, I'm trying to build a speedy
script for converting whole images between the RGB and the HSV (a.k.a.
HSB) color spaces. Unfortunately, the code I've made so far runs
dreadfully slow with even moderate-sized images.

I'm under the impression that the crux of the problem is the fact that
PIL's point method operates on only one band at a time, and to do a
proper color space conversion, you need information about all three
bands in a particular problem. This has forced me to do an awkward
work-around where the image data is loaded into a numpy array
(1600x1200x3), and a dinky for-loop run runs through the array picking
up RGB values, converting to HSV, and dumping the results back into
another array.

How can I make this more efficient?

--------

from PIL import Image
from PIL import TiffImagePlugin
from scipy.misc import pilutil
import numpy
import colorsys

def myrgbtohsv(r,g,b):
'''A wrapper for the colorsys function rgb_to_hsv
that takes r,g,b values between 0 and 255
(standard pixel value range in most of my single-band imaging
operations)
and returns the corresponding 255-scaled h,s,v values'''
tr = r/255.0
tg = g/255.0
tb = b/255.0
ur,ug,ub = colorsys.rgb_to_hsv(tr,tg,tb)
pr = int(round(ur,0))*255
pg = int(round(ug,0))*255
pb = int(round(ub,0))*255
return pr,pg,pb

def rgbarrtohsvarr(pilarray):
'''Takes an 3d numpy ndarray loaded with a RGB PIL image and
converts
a copy of the contents to 255-scaled HSV array.

Returns the converted copy of the array.
'''
arrt = pilarray.copy()
r,c,d = arrt.shape
hsvarray = numpy.zeros((r,c,d))

print out
for i in range(0,r):
for j in range(0,c):
localrgb = (arrt[i,j,0],arrt[i,j,1],arrt[i,j,2])
(lh,ls,lv) = rgbtohsv(localrgb)
hsvarray[i,j,0],hsvarray[i,j,1],hsvarray[i,j,2]= lh,ls,lv

return hsvarray

im = Image.open(r'C:\test.tif')
arr = pilutil.fromimage(im)
out = rgbarrtohsvarr(arr)

--------

ttest, Jan 4, 2008

2. ### Robert KernGuest

ttest wrote:
> Hello,
>
> I'm working on an image processing project using the Python Imaging
> Library along with numpy. Right now, I'm trying to build a speedy
> script for converting whole images between the RGB and the HSV (a.k.a.
> HSB) color spaces. Unfortunately, the code I've made so far runs
> dreadfully slow with even moderate-sized images.
>
> I'm under the impression that the crux of the problem is the fact that
> PIL's point method operates on only one band at a time, and to do a
> proper color space conversion, you need information about all three
> bands in a particular problem. This has forced me to do an awkward
> work-around where the image data is loaded into a numpy array
> (1600x1200x3), and a dinky for-loop run runs through the array picking
> up RGB values, converting to HSV, and dumping the results back into
> another array.
>
> How can I make this more efficient?

Reimplement colorsys.rgb_to_hsv() such that it operates on arrays instead of
scalars. Only minor modifications are necessary.

--
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless enigma
that is made terrible by our own mad attempt to interpret it as though it had
an underlying truth."
-- Umberto Eco

Robert Kern, Jan 4, 2008

3. ### ttestGuest

> Reimplement colorsys.rgb_to_hsv() such that it operates on arrays instead of
> scalars. Only minor modifications are necessary.
>
> --
> Robert Kern

Thanks! I'll try and see if a newcomer like me can get his head
around the array-centric modifications to colorsys.

ttest, Jan 5, 2008
4. ### Robert KernGuest

ttest wrote:
>> Reimplement colorsys.rgb_to_hsv() such that it operates on arrays instead of
>> scalars. Only minor modifications are necessary.
>>
>> --
>> Robert Kern

>
> Thanks! I'll try and see if a newcomer like me can get his head
> around the array-centric modifications to colorsys.

If you hit any roadblocks, drop in on numpy-discussion, and we'll help you out.

http://www.scipy.org/Mailing_Lists

--
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless enigma
that is made terrible by our own mad attempt to interpret it as though it had
an underlying truth."
-- Umberto Eco

Robert Kern, Jan 6, 2008
5. ### Guest

>
> ...where the image data is loaded into a numpy array
> (1600x1200x3)...

One comment: that is a big array, too big for the cache memory. I know
that in these cases it makes a difference how many times the slices of
the array are loaded and unloaded from RAM onto cache. One issue is
that a 2D array l[i,j] is actually a 1D array:
either
l[i,j]=l[i*N+j]
or
l[i,j]=l[j*N+i]
I don't know which in python/numpy. In the first case, when you fix i
and change j, you get consecutive positions in the underlying 1D
array, and they all belong to the same slice, which is loaded onto
cache very fast as a block. If you do the opposite, you are making
jumps to distant positions in the array (not a slice), and performance
suffers.

In gimp, for example, the underlying array is split into 'tiles',
which are 64x64 pixel regions that can be loaded/unloaded as a block.
And that's about all I know on the issue.

So it ma

, Jan 6, 2008