Python - Fast periodic PNG modification

I wrote a python script with a unique combination of images for the OpenGL shader. The problem is that I have a large number of very large maps and it takes a long time to process. Is there a way to write this faster?

    import numpy as np

    map_data = {}
    image_data = {}
    for map_postfix in names:
    file_name = inputRoot + '-' + map_postfix + resolution + '.png'
    print 'Loading ' + file_name
    image_data[map_postfix] = Image.open(file_name, 'r')
    map_data[map_postfix] = image_data[map_postfix].load()


    color = mapData['ColorOnly']
    ambient = mapData['AmbientLight']
    shine = mapData['Shininess']

    width = imageData['ColorOnly'].size[0]
    height = imageData['ColorOnly'].size[1]

    arr = np.zeros((height, width, 4), dtype=int)

    for i in range(width):
        for j in range(height):
            ambient_mod = ambient[i,j][0] / 255.0
            arr[j, i, :] = [color[i,j][0] * ambient_mod , color[i,j][1] * ambient_mod , color[i,j][2] * ambient_mod , shine[i,j][0]]

    print 'Converting Color Map to image'
    return Image.fromarray(arr.astype(np.uint8))

      

This is just a sample of a lot of batch processes, so I'm more interested in if there is a faster way to iterate and modify an image file. Almost all of the time is spent in a nested loop against loading and saving.

+2


source to share


1 answer


Vector code example - test effect on your in timeit

orzmq.Stopwatch()

It is reported to have 22.14 seconds → 0.1624 seconds of acceleration!

While your code seems to intersect RGBA [x, y], let me show you the vectorized code syntax "that benefits from a numpy

matrix manipulation utility (forget RGB / YUV manipulation (originally based on OpenCV, not PIL). but reuse the indexed syntax approach to avoid for-loops and adapt it to work efficiently for your calculus Wrong order of operations can more than double your processing time.

And use a test / optimize / re-test loop to speed up.

For testing, use standard python timeit

if sufficient [msec]

.

Skip to rather zmq.Stopwatch()

if you need to go to [usec]

.

# Vectorised-code example, to see the syntax & principles
#                          do not mind another order of RGB->BRG layers
#                          it has been OpenCV traditional convention
#                          it has no other meaning in this demo of VECTORISED code

def get_YUV_U_Cb_Rec709_BRG_frame( brgFRAME ):  # For the Rec. 709 primaries used in gamma-corrected sRGB, fast, VECTORISED MUL/ADD CODE
    out =  numpy.zeros(            brgFRAME.shape[0:2] )
    out -= 0.09991 / 255 *         brgFRAME[:,:,1]  # // Red
    out -= 0.33601 / 255 *         brgFRAME[:,:,2]  # // Green
    out += 0.436   / 255 *         brgFRAME[:,:,0]  # // Blue
    return out
# normalise to <0.0 - 1.0> before vectorised MUL/ADD, saves [usec] ...
# on 480x640 [px] faster goes about 2.2 [msec] instead of 5.4 [msec]

      



In your case using dtype = numpy.int

, let's say it should be faster MUL

first ambient[:,:,0]

and finally DIV

for normalizationarr[:,:,:3] /= 255

# test if this goes even faster once saving the vectorised overhead on matrix DIV
arr[:,:,0] = color[:,:,0] * ambient[:,:,0] / 255  # MUL remains INT, shall precede DIV
arr[:,:,1] = color[:,:,1] * ambient[:,:,0] / 255  # 
arr[:,:,2] = color[:,:,2] * ambient[:,:,0] / 255  # 
arr[:,:,3] = shine[:,:,0]                         # STO alpha

      

So how might this look like in your algo?

No need to have Peter Jackson's impressive budget and time after it has been planned, embraced and executed with a huge crunch of 3 years in a New Zealand hangar overflowing with a herd of SGI workstations, as he was creating " The Lord of the Rings " completely digital master assembly, right behind the frame by frame, to understand that milliseconds, microseconds, and even nanoseconds in a pipeline mass production line simply matter.

So, take a deep breath and test and retest to optimize real-world imaging performance to the levels your project needs.

Hope this helps you with this:

# OPTIONAL for performance testing -------------# ||||||||||||||||||||||||||||||||
from zmq import Stopwatch                       # _MICROSECOND_ timer
#                                               # timer-resolution step ~ 21 nsec
#                                               # Yes, NANOSECOND-s
# OPTIONAL for performance testing -------------# ||||||||||||||||||||||||||||||||
arr        = np.zeros( ( height, width, 4 ), dtype = int )
aStopWatch = zmq.Stopwatch()                    # ||||||||||||||||||||||||||||||||
# /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\# <<< your original code segment          
#  aStopWatch.start()                           # |||||||||||||__.start
#  for i in range(     width  ):
#      for j in range( height ):
#          ambient_mod  = ambient[i,j][0] / 255.0
#          arr[j, i, :] = [ color[i,j][0] * ambient_mod, \
#                           color[i,j][1] * ambient_mod, \
#                           color[i,j][2] * ambient_mod, \
#                           shine[i,j][0]                \
#                           ]
#  usec_for = aStopWatch.stop()                 # |||||||||||||__.stop
#  print 'Converting Color Map to image'
#  print '           FOR processing took ', usec_for, ' [usec]'
# /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\# <<< proposed alternative
aStopWatch.start()                              # |||||||||||||__.start
# reduced numpy broadcasting one dimension less # ref. comments below
arr[:,:, 0]  = color[:,:,0] * ambient[:,:,0]    # MUL ambient[0]  * [{R}]
arr[:,:, 1]  = color[:,:,1] * ambient[:,:,0]    # MUL ambient[0]  * [{G}]
arr[:,:, 2]  = color[:,:,2] * ambient[:,:,0]    # MUL ambient[0]  * [{B}]
arr[:,:,:3] /= 255                              # DIV 255 to normalise
arr[:,:, 3]  = shine[:,:,0]                     # STO shine[  0] in [3]
usec_Vector  = aStopWatch.stop()                # |||||||||||||__.stop
print 'Converting Color Map to image'
print '           Vectorised processing took ', usec_Vector, ' [usec]'
return Image.fromarray( arr.astype( np.uint8 ) )

      

+2


source







All Articles