[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [pygame] surfarray.pixels3d(). I'm stumped.



On Sun, 22 Aug 2004, Pete Shinners wrote:

> Jasper Phillips wrote:
> > I'm trying to blur both RGB and alpha using surfarray.  I can get it to
> > work with surfarray.array3d() and .array_alpha(), but it's very slow as
> > I end up using Surface.set_at() to combine the results of both methods
> > together.
> 
> You'll never want to use the Surface.set_at/get_at functions when doing 
> image effects. You'll want to avoid loops like over the whole image, 
> like for x in range(width): for y in range(height): it is never going to 
> be fast enough.

Thanks for the speedy reply!

Actually, the speed isn't such a big deal, as I only blur images once, not
every frame.  It only really matters for improving testing turnaround.
Well, actually it's become academic as I've found a way to wory around
manipulating alpha, but I'm still interested in the general case.

> > exceptions.TypeError: Array can not be safely cast to required type
> 
> The "3d" arrays are always Int8 type arrays. Numeric always tries to 
> upcast your numbers into regular Int, it is very annoying. With a little 
> care or conversion you can get the right types out.

I too was down casting to Numeric.Int8...

> In my old flame example I almost have an convolution filter. Let me see 
> if I can do it here in email. This will do a single color channel, so 
> you'll apply is separately to R, G, B, and A.
> 
> def filter3x3(src, dst, matrix):
>      "src and dst must be 2d arrays of the same size"
>      w, h = src.shape[0]-2, src.shape[1]-2
>      intdst = Numeric.zeros((src.shape[0]-2, src.shape[1]-2))
>      for x,y in [(0, 0), (1, 0), (2, 0),
>                  (0, 1), (1, 1), (2, 1),
>                  (0, 2), (1, 2), (2, 2)]:
>      	intdst += src[x:x+w,y:y+w] * matrix[x,y]
>      weight = Numeric.sum(Numeric.sum(matrix))
>      intdst /= weight
>      dst[1:-1,1:-1] = intdst.astype(Numeric.Int8)
> 
> 
> This doesn't filter the border pixels, but I suppose extra work could be 
> done for those too. To call this on the separate color channels you 
> would create a pixels3d array for the source and destination, and call 
> the function like this
> 
>     filter3x3(srcarray[::0], dstarray[::0], matrix)
>     filter3x3(srcarray[::1], dstarray[::1], matrix)
>     filter3x3(srcarray[::2], dstarray[::2], matrix)
>     filter3x3(srcalphaarray, dstalphaarray, matrix)

I wasn't able to get this to work.  There was a syntax error and an indexing
error, so I tweaked it like so:

def filter3x3(src, dst, matrix):
     "src and dst must be 2d arrays of the same size"
     w, h   = src.shape[0]-2, src.shape[1]-2
     intdst = Numeric.zeros((w,h))
     for x,y in [(0, 0), (1, 0), (2, 0),
                 (0, 1), (1, 1), (2, 1),
                 (0, 2), (1, 2), (2, 2)]:
        intdst += src[x:x+w,y:y+h] * matrix[x,y]
     weight = Numeric.sum(Numeric.sum(matrix))
     intdst /= weight
     dst[1:-1,1:-1] = intdst.astype(Numeric.Int8)

def tryPixels3d( surface ):
    matrix      = Numeric.zeros( (3,3) )
    matrix[1,1] = 1
    matrix[1,0] = 1
    matrix[0,1] = 1
    matrix[2,1] = 1
    matrix[1,2] = 1
    print matrix

    srcarray = array3d(  surface )
    dstarray = pixels3d( surface )

    srcalphaarray = array_alpha(  surface )
    dstalphaarray = pixels_alpha( surface.convert_alpha() )

    filter3x3(srcarray[:,:,0], dstarray[:,:,0], matrix)
    filter3x3(srcarray[:,:,1], dstarray[:,:,1], matrix)
    filter3x3(srcarray[:,:,2], dstarray[:,:,2], matrix)
    filter3x3(srcalphaarray, dstalphaarray, matrix)

    return surface


I get the same TypeError as with my previous code, on the last line of
filter3x3()...

-Jasper