patternpythonMinor
Writing image pixel data to printer code
Viewed 0 times
imagepixelwritingprintercodedata
Problem
I've been trying to take image pixel data and write it out into printer code and my results are rather slow.
Here is a simplified version of what I have so far (image is a PIL Image object of 1200 x 1800 pixels):
I know the loop can be optimized way better, but how?
My code is running on a beaglebone so speed is slower than you'd expect, but composing the complex images takes about 5 seconds. I wouldn't expect my printer code function (which just reorders the data) to take much longer than about 2 or 3 seconds. My first attempt (with
For comparison, just so we can all see where the hold up is, this code runs in 0.1 secs (but, of course, is lacking the important data):
I guess a simplified version of this problem is to rewrite something like the following:
into
but as a string
Here is a simplified version of what I have so far (image is a PIL Image object of 1200 x 1800 pixels):
# ~36 seconds on beaglebone
f.write(pclhead)
pix = image.getdata()
for y in xrange(1800):
row = '\xff'*72
### vvv slow code vvv ###
for x in xrange(1200):
(r,g,b) = pix[y*1200+x]
row += chr(g)+chr(b)+chr(r)
### ^^^ slow code ^^^ ###
row += '\xff'*72
f.write(row)
f.write(pclfoot)I know the loop can be optimized way better, but how?
My code is running on a beaglebone so speed is slower than you'd expect, but composing the complex images takes about 5 seconds. I wouldn't expect my printer code function (which just reorders the data) to take much longer than about 2 or 3 seconds. My first attempt (with
getpixel) took 90 seconds. Now I have it down to 36 seconds. Surely I can make this quite a bit faster yet.For comparison, just so we can all see where the hold up is, this code runs in 0.1 secs (but, of course, is lacking the important data):
# ~0.1 seconds on beaglebone
f.write(pclhead)
pix = image.getdata()
for y in xrange(1800):
row = '\xff'*72
### vvv substituted vvv ###
row += '\xff'*3600
### ^^^ substituted ^^^ ###
row += '\xff'*72
f.write(row)
f.write(pclfoot)I guess a simplified version of this problem is to rewrite something like the following:
[ (1,2,3), (1,2,3) ... 1200 times ]into
[ 2, 3, 1, 2, 3, 1, etc... ]but as a string
"\x02\x03\x01\x02\x03\x01 ... "Solution
Start with storing the
Next, use a list to collect all strings, then join at the end; this is cheaper than constant string concatenation.
Last, avoid attribute lookups in critical sections; assign any attribute lookups done more than once to a local name:
You can experiment with joining the whole row (including
'\xff' * 72 string as a constant; Python strings are immutable, recreating that string each time is not necessary.Next, use a list to collect all strings, then join at the end; this is cheaper than constant string concatenation.
Last, avoid attribute lookups in critical sections; assign any attribute lookups done more than once to a local name:
from operator import itemgetter
bgr = itemgetter(1,2,0)
pix = image.getdata()
rowstart = '\xff' * 72
f_write = f.write
empty_join = ''.join
for y in xrange(1800):
row = [rowstart]
r_extend = row.extend
for x in xrange(1200):
r_extend(map(chr, bgr(pix[y*1200+x])))
r.append(rowstart)
f_write(empty_join(row))You can experiment with joining the whole row (including
rowstart) or writing out rowstart values separately; the following version might be faster still depending on write speed versus list concatenation speed:for y in xrange(1800):
f_write(rowstart)
row = []
r_extend = row.extend
for x in xrange(1200):
r_extend(map(chr, bgr(pix[y*1200+x])))
f_write(empty_join(row))
f_write(rowstart)Code Snippets
from operator import itemgetter
bgr = itemgetter(1,2,0)
pix = image.getdata()
rowstart = '\xff' * 72
f_write = f.write
empty_join = ''.join
for y in xrange(1800):
row = [rowstart]
r_extend = row.extend
for x in xrange(1200):
r_extend(map(chr, bgr(pix[y*1200+x])))
r.append(rowstart)
f_write(empty_join(row))for y in xrange(1800):
f_write(rowstart)
row = []
r_extend = row.extend
for x in xrange(1200):
r_extend(map(chr, bgr(pix[y*1200+x])))
f_write(empty_join(row))
f_write(rowstart)Context
StackExchange Code Review Q#31545, answer score: 6
Revisions (0)
No revisions yet.