List Info

Thread: Comparison of PIL and GD speed for setting pixels through python




Comparison of PIL and GD speed for setting pixels through python
user name
2007-02-02 00:32:57
Hi,
	I've had a need to do some optimisation of some low level
pixel setting 
code, and have as such done some tests of different ways of
doing this 
using PIL and alternatively with gd via ctypes.

Ctypes provides a fairly easy way to interface to gd, and
allows you to 
easily use small sections of optimising C code.  A summary
of the 
results is below, but basically using ctyles/GD/c is about
20 or so 
times faster than PIL and the new Image.load, and over 200
times faster 
than using PIL's ImageDraw.point method.

Method          Time (s)        Times slower than fastest
+-----+         +-------+       +------------------------+
ctypes, c, GD   0.00181         1.0
PIL - 'load'    0.03965         21.9
ctypes, GD      0.18710         103.5
PIL - 'point'   0.45009         248.9

A full writeup of this can be found here :

http://www.lan
garson.com.au/blog/?p=10

I hope this is of use, and I look forward to comments,
particularly on 
other ways of doing this with PIL & C, which there
undoubtedly are.

Cheers,

JB.

-- 
John Barratt
www.langarson.com.au - Python, Zope, GIS, Weather.
_______________________________________________
Image-SIG maillist  -  Image-SIGpython.org
htt
p://mail.python.org/mailman/listinfo/image-sig

Re: Comparison of PIL and GD speed for setting pixels through python
user name
2007-02-02 14:30:56
John Barratt wrote:
> Hi,
> 	I've had a need to do some optimisation of some low
level pixel setting 
> code, and have as such done some tests of different
ways of doing this 
> using PIL and alternatively with gd via ctypes.

Have you tried using PIL + numpy -- you can convert a PIL
image (some 
eof them, anyway) to a numpy array, and manipulate it there.
Numpy 
provides a number if efficient ways to do such
manipulations.

In the most recent PIL, you should be able to convert
to/from PIL/numpy 
without any copying of the data, though I don't think it's
been heavily 
tested.

-Chris



-- 
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R            (206) 526-6959   voice
7600 Sand Point Way NE   (206) 526-6329   fax
Seattle, WA  98115       (206) 526-6317   main reception

Chris.Barkernoaa.gov
_______________________________________________
Image-SIG maillist  -  Image-SIGpython.org
htt
p://mail.python.org/mailman/listinfo/image-sig

Re: Comparison of PIL and GD speed for setting pixels through python
country flaguser name
Australia
2007-02-04 04:20:01
Christopher Barker wrote:
> John Barratt wrote:
>> 	I've had a need to do some optimisation of some
low level pixel setting 
>> code, and have as such done some tests of different
ways of doing this 
>> using PIL and alternatively with gd via ctypes.
> 
> Have you tried using PIL + numpy -- you can convert a
PIL image (some 
> eof them, anyway) to a numpy array, and manipulate it
there. Numpy 
> provides a number if efficient ways to do such
manipulations.
> 
> In the most recent PIL, you should be able to convert
to/from PIL/numpy 
> without any copying of the data, though I don't think
it's been heavily 
> tested.

I haven't tried it, but did originally think of adding it to
the list of 
things tested.  Given this specific example though, where
the idea is 
that a specific method or piece of code is needed to be run
for every 
pixel (not that it actually is in this abstract example), I
would think 
that unless that specific code can be called from, and done
in C, that 
it would perform similarly to the Image.load method.  This
is because I 
am assuming the cost of accessing the raw data from
Image.load to be 
similar to that of accessing an array type in numpy.  Having
said all 
that though, I'll have a look at adding it to the mix...

I think where PIL & numpy would excel is where you have
a cases of a 
number of images with calculations required that could be
easily 
represented as array operations.  The examples I am thinking
of don't 
lend themselves to this sort of solution.

It is perhaps also possible to reasonably efficiently access
the PIL raw 
data under C as a standard type (eg. a 'flattened' unsigned
char* for 
paletted images) through ctypes, in which case the result
time-wise 
would hopefully be similar, or the same as using gd all the
way.

I am also finishing a 'real world' example for this sort of
problem 
which may help further clarify further options and their
relative 
benefits & costs.

Cheers,

JB.
_______________________________________________
Image-SIG maillist  -  Image-SIGpython.org
htt
p://mail.python.org/mailman/listinfo/image-sig

Re: Comparison of PIL and GD speed for setting pixels through python
country flaguser name
Australia
2007-02-04 06:23:41
With prompting from Chris, and a little further work in gd,
I have 
updated this comparison further, adding a further gd/ctypes
test, this 
time setting pixel values using the raw pixel data, as well
as the start 
of a test for a numpy/PIL option.  Unfortunately it doesn't
fully work, 
at least with the version/s I have.  However it does, based
on what does 
work, seem to be relatively slow.  The new indicative times
look like this :

  Method          Time (s)        Times slower than fastest
+-----+         +-------+       +------------------------+
ctypes,c,GD raw 0.00082         1.0
ctypes,c,GD     0.00177         2.2
PIL - 'load'    0.03226         39.4
ctypes, GD      0.14428         176.4
PIL, numpy *    0.26271         321.2
PIL - 'point'   0.37180         454.5

Further details are here, including updated code :

http://www.lan
garson.com.au/blog/?p=11

I also fixed a few bugs that affected the image created, but
not the 
timing, and added code to save the files out where possible
to further 
check they were actually doing what was intended.

Cheers,

JB.

-- 
John Barratt - www.langarson.com.au
          Python, Zope, GIS, Weather
_______________________________________________
Image-SIG maillist  -  Image-SIGpython.org
htt
p://mail.python.org/mailman/listinfo/image-sig

Re: Comparison of PIL and GD speed for setting pixels through python
country flaguser name
New Zealand
2007-02-04 16:43:56
hi John,

>   Method          Time (s)        Times slower than
fastest
> +-----+         +-------+      
+------------------------+
> ctypes,c,GD raw 0.00082         1.0
> ctypes,c,GD     0.00177         2.2
> PIL - 'load'    0.03226         39.4
> ctypes, GD      0.14428         176.4
> PIL, numpy *    0.26271         321.2
> PIL - 'point'   0.37180         454.5
>

You can also access raw PIL image data via C, so your top
line,
"ctypes,c,GD raw" should be just as applicable to
PIL as GD.  Or is
there some reason this is not so?  From memory, you'd pry
open the
im.im object, and use something like im->image32[y][x] to
access each
pixel.

Also, your C functions boil down to variations of memset. 
Have you
considered trying that?  Another option is PIL's
paste(colour, box)
method.  I suspect you are ignoring these two because
somewhere you
say "one pixel at a time", but as far as I can
tell your routines
don't allow for that pixel to vary, so there is actually no
difference.  im.paste(colour, (0, 0, width, height)) is
functionally
the same as your test functions; inside it probably looks
much like
your setPixelsRaw.


douglas

_______________________________________________
Image-SIG maillist  -  Image-SIGpython.org
htt
p://mail.python.org/mailman/listinfo/image-sig

Re: Comparison of PIL and GD speed for setting pixels through python
country flaguser name
Australia
2007-02-04 17:22:18
Hi Douglas,

Douglas Bagnall wrote:
>>   Method          Time (s)        Times slower than
fastest
>> +-----+         +-------+      
+------------------------+
>> ctypes,c,GD raw 0.00082         1.0
>> ctypes,c,GD     0.00177         2.2
>> PIL - 'load'    0.03226         39.4
>> ctypes, GD      0.14428         176.4
>> PIL, numpy *    0.26271         321.2
>> PIL - 'point'   0.37180         454.5
>>
> 
> You can also access raw PIL image data via C, so your
top line,
> "ctypes,c,GD raw" should be just as
applicable to PIL as GD.  Or is
> there some reason this is not so?  From memory, you'd
pry open the
> im.im object, and use something like
im->image32[y][x] to access each
> pixel.
Ahhh, that is the sort of thing I was wanting to do with
PIL, I just 
didn't know how, though hadn't dug into the source code for
PIL either. 
  I will have a look to see if I can get this to fly as
well.  I would 
hope that in this case that things should be a similar/same
speed 
between using PIL or gd as the main image object type.  The
main reason 
I did it with gd was because I could see a clear path from
the 
documentation to achieve this optimisation.

> Also, your C functions boil down to variations of
memset.  Have you
> considered trying that?  Another option is PIL's
paste(colour, box)
> method.  I suspect you are ignoring these two because
somewhere you
> say "one pixel at a time", but as far as I
can tell your routines
> don't allow for that pixel to vary, so there is
actually no
> difference.  im.paste(colour, (0, 0, width, height)) is
functionally
> the same as your test functions; inside it probably
looks much like
> your setPixelsRaw.
The code that does the pixel setting in these tests is very
simple yes, 
and deliberately so.  It could be done other ways, this was
done as a 
simple test case to get an idea of the overhead of the rest
of a system 
like this.  The idea is that each pixel requires some
relatively complex 
piece of code to calculate each value, and one that can't be
obtained by 
simple array/image operations that work on the whole image. 
I have a 
'real world' example that I will finish, and might help show
this more 
clearly.

Cheers,

JB.

-- 
John Barratt - www.langarson.com.au
          Python, Zope, GIS, Weather
_______________________________________________
Image-SIG maillist  -  Image-SIGpython.org
htt
p://mail.python.org/mailman/listinfo/image-sig

Re: Comparison of PIL and GD speed for setting pixels through python
country flaguser name
Australia
2007-02-05 04:22:09
Well after some digging through the PIL source code after
the prompting 
from Douglas, and some tinkering with the python C
interface, I have 
implemented a C based version of the core pixel setting loop
using PIL 
objects.  I have also added 'reference' versions using plain
python, 
setting an integer value in the loop, and setting an integer
2D array in 
a loop.

The short of this is that a PIL implementation with C goes
faster for 
larger images (1024x1024), and faster almost overall if you
only 
consider time to actually set the pixels, and not image
creation time as 
well.

Fredrik, do you think it would be possible to have a
standard API call 
in PIL that could cleanly & reliably expose the core C
pixel data array 
for use within C (through say ctypes, or back through the
python-c api) 
for optimisations like this?

The full breakdown of results, and new source code with the
PIL/c 
implementation can be found here :

http://www.lan
garson.com.au/blog/?p=13

I think that has about exhausted the possible combinations
to test, but 
if anyone has any other suggestions, please let me know. 
Also if anyone 
has any ideas as to why the PIL/raw/c version should go so
much faster 
than the gd/raw/c version I would be interested to know, as
the core 
looping code is basically identical...

Cheers,

JB.

-- 
John Barratt - www.langarson.com.au
          Python, Zope, GIS, Weather
_______________________________________________
Image-SIG maillist  -  Image-SIGpython.org
htt
p://mail.python.org/mailman/listinfo/image-sig

Re: Comparison of PIL and GD speed for setting pixels through python
country flaguser name
United States
2007-02-05 12:28:13
John Barratt wrote:
> I haven't tried it, but did originally think of adding
it to the list of 
> things tested.  Given this specific example though,
where the idea is 
> that a specific method or piece of code is needed to be
run for every 
> pixel (not that it actually is in this abstract
example), I would think 
> that unless that specific code can be called from, and
done in C, that 
> it would perform similarly to the Image.load method. 
This is because I 
> am assuming the cost of accessing the raw data from
Image.load to be 
> similar to that of accessing an array type in numpy. 
Having said all 
> that though, I'll have a look at adding it to the
mix...

Quite true. In fact, your tests make it look like accessing
individual 
pixels in numpy is pretty darn slow. I'm guessing that
that's because 
numpy may be creating a numpy scalar object with every pixel
access.

> I think where PIL & numpy would excel is where you
have a cases of a 
> number of images with calculations required that could
be easily 
> represented as array operations.  The examples I am
thinking of don't 
> lend themselves to this sort of solution.

Also true -- but are you sure you couldn't do your
pixel-specific 
calculations as array operations?

By the way, you really want to be using numpy 1.0.1, not
numpy 0.9.8, 
numpy was undergoing a lot of flux before 1.0 came out.

Also, it looks like your code wouldn't work anyway:

data = numpy.resize(numpy.array(0),outputSize)
     for x in range(outputSize[0]):
         for y in range(outputSize[1]):
             data[x,y] = colourI

This creates a 2-d array of 32bit integers, which isn't
going to match 
an RBG array. You'd need to either use RGBA, or use an WxHx3
array of bytes:

data = numpy.zeros(outputSize[0], outputSize[1], 3,
dtype=numpy.ubyte)

However, that would only make it slower! I am a bit
surprised that it is 
as slow as that.

John Barratt wrote:
>> You can also access raw PIL image data via C, so
your top line,
>> "ctypes,c,GD raw" should be just as
applicable to PIL as GD.  Or is
>> there some reason this is not so?  From memory,
you'd pry open the
>> im.im object, and use something like
im->image32[y][x] to access each
>> pixel.
> Ahhh, that is the sort of thing I was wanting to do
with PIL, I just 
> didn't know how,

There is a movement afoot (mostly us numpy folks) to get a
basic n-d 
array object into the standard Python library. The goal is
that all 
packages that need an nd-array of data (such as PIL, etc)
could use the 
same thing, and then they'd all have the same C API for
accessing the 
data -- this looks like another good argument for that!

> The idea is that each pixel requires some relatively
complex 
> piece of code to calculate each value, and one that
can't be obtained by 
> simple array/image operations that work on the whole
image.

careful here -- if your "relatively complex" piece
of code takes 
substantially longer than the pixel setting, then all this
work is for 
naught -- though we're all learning something from it!

by the way, numpy can do more than "simple array"
operations -- so it 
still may help.

-Chris

-- 
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R            (206) 526-6959   voice
7600 Sand Point Way NE   (206) 526-6329   fax
Seattle, WA  98115       (206) 526-6317   main reception

Chris.Barkernoaa.gov
_______________________________________________
Image-SIG maillist  -  Image-SIGpython.org
htt
p://mail.python.org/mailman/listinfo/image-sig

Re: Comparison of PIL and GD speed for setting pixels through python
country flaguser name
New Zealand
2007-02-05 17:59:48
John Barratt wrote:

> I think that has about exhausted the possible
combinations to test, but 
> if anyone has any other suggestions, please let me
know.  Also if anyone 
> has any ideas as to why the PIL/raw/c version should go
so much faster 
> than the gd/raw/c version I would be interested to
know, as the core 
> looping code is basically identical...
> 

um.. cache locality?  With GD you have

  for (u=0; u<x; u++) {
    for (v=0; v<y; v++) {
      d[v][u] = colour;
    }
  }

which goes through every row for each column, jumping back
and forth in
memory.  You need to switch the order of the loops, like you
have in the
PIL example:

  for (u=0; u<xSize; u++) {
    for (v=0; v<xSize; v++) {
      data[u][v] = colour;
    }
  }

...which, BTW, as written, would not be so successful on
non-square images.

However, this shows how far the benchmark has got from real
world usage.
 As Chris Barker pointed out, if you are doing any kind of
work to find
your pixels, these effects would become negligible.

Have you looked at PyGame? it seems to have drawing commands
too.


Douglas Bagnall



_______________________________________________
Image-SIG maillist  -  Image-SIGpython.org
htt
p://mail.python.org/mailman/listinfo/image-sig

Re: Comparison of PIL and GD speed for setting pixels through python
country flaguser name
Australia
2007-02-05 19:13:42
Hi Chris,

Christopher Barker wrote:
>> I think where PIL & numpy would excel is where
you have a cases of a 
>> number of images with calculations required that
could be easily 
>> represented as array operations.  The examples I am
thinking of don't 
>> lend themselves to this sort of solution.
> 
> Also true -- but are you sure you couldn't do your
pixel-specific 
> calculations as array operations?
Well, certainly not simple array operations, I have an
example I will 
finish (hill shading) that perhaps could be done with array
operations, 
but would I think still require a large number of them,
making it still 
inefficient.

> By the way, you really want to be using numpy 1.0.1,
not numpy 0.9.8, 
> numpy was undergoing a lot of flux before 1.0 came
out.
OK, I will update my version.

> Also, it looks like your code wouldn't work anyway:
> 
> data = numpy.resize(numpy.array(0),outputSize)
>     for x in range(outputSize[0]):
>         for y in range(outputSize[1]):
>             data[x,y] = colourI
> 
> This creates a 2-d array of 32bit integers, which isn't
going to match 
> an RBG array. You'd need to either use RGBA, or use an
WxHx3 array of 
> bytes:
> 
> data = numpy.zeros(outputSize[0], outputSize[1], 3,
dtype=numpy.ubyte)
> 
> However, that would only make it slower! I am a bit
surprised that it is 
> as slow as that.
OK, thanks.  I was perhaps guessing at what was required
here, and since 
I couldn't get the output to work I couldn't tell it was
actually 
broken.  I'll revisit this when I can get numpy working with
PIL, 
perhaps the newer version will help.

> There is a movement afoot (mostly us numpy folks) to
get a basic n-d 
> array object into the standard Python library. The goal
is that all 
> packages that need an nd-array of data (such as PIL,
etc) could use the 
> same thing, and then they'd all have the same C API for
accessing the 
> data -- this looks like another good argument for
that!
mmm that would be nice.  Would be nice to be able to combine
python with 
the efficiency of C more easily for tasks like this!

>> The idea is that each pixel requires some
relatively complex piece of 
>> code to calculate each value, and one that can't be
obtained by simple 
>> array/image operations that work on the whole
image.
> 
> careful here -- if your "relatively complex"
piece of code takes 
> substantially longer than the pixel setting, then all
this work is for 
> naught -- though we're all learning something from it!
Yes, true. It could be a relatively minor cost at the end of
the day if 
the per-pixel operation is too costly.  But there are
actually two 
motivations here :

- If the per-pixel operation isn't too costly, then you get
a real 
noticeable benefit of lower pixel-access overhead.

- Even if the per-pixel operation is relatively costly, with
this method 
you can easily implement that per-pixel operation in C
because the core 
pixel access loop is in C (with PIL or gd at the python
level).  This in 
turn should make it run significantly faster than it's pure
python 
counterpart.  This perhaps works only with the assumption
that it isn't 
too much effort to write/rewrite that particular operation
in C.

> by the way, numpy can do more than "simple
array" operations -- so it 
> still may help.
OK.  It may indeed be able to do something more effectively
with the 
next example.

Thanks for the comments,

JB.

-- 
John Barratt - www.langarson.com.au
          Python, Zope, GIS, Weather
_______________________________________________
Image-SIG maillist  -  Image-SIGpython.org
htt
p://mail.python.org/mailman/listinfo/image-sig

[1-10] [11]

about | contact  Other archives ( Real Estate discussion Medical topics )