Array blitting (pasting one array into another)

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Array blitting (pasting one array into another)

Mikhail V
Hello all

I often need to copy one array into another array, given an offset.
This is how the "blit" function can be understood, i.e. in
every graphical lib there is such a function.
The common definition is like:
blit ( dest, src, offset ):
where dest is destination array, src is source array and offset is
coordinates in destination where the src should pe blitted.
Main feature of such function is that it never gives an error,
so if the source does not fit into the destination array, it is simply trimmed.
And respectively if there is no intersection area then nothing happens.

Hope this is clear.
So to make it work with Numpy arrays one need to calculate the
slices before copying the data.
I cannot find any Numpy or Python method to help with that so probably
it does not exist yet.
If so, my proposal is to add a Numpy method which helps with that.
Namely the proposal will be to add a method which returns
the slices for the intersection areas of two arbitrary arrays, given an offset,
so then one can "blit" the array into another with simple assignment =.

Here is a Python function I use for 2d arrays now:

def interslice ( dest, src, offset ):
    y,x = offset
    H,W = dest.shape
    h,w = src.shape

    dest_starty = max (y,0)
    dest_endy = min (y+h,H)
    dest_startx = max (x,0)
    dest_endx = min (x+w,W)

    src_starty = 0
    src_endy = h
    if y<0:     src_starty = -y
    by = y+h - H             # Y bleed
    if by>0: src_endy = h - by

    src_startx = 0
    src_endx = w
    if x<0:  src_startx = -x
    bx = x+w - W             # X bleed
    if bx>0:  src_endx = w - bx

    dest_sliceY =  slice(dest_starty,dest_endy)
    dest_sliceX =  slice(dest_startx,dest_endx)
    src_sliceY = slice(src_starty, src_endy)
    src_sliceX = slice(src_startx, src_endx)
    if dest_endy <= dest_starty:
        print "No Y intersection !"
        dest_sliceY = ( slice(0, 0) )
        src_sliceY = ( slice(0, 0) )
    if dest_endx <= dest_startx:
        print "No X intersection !"
        dest_sliceX = ( slice(0, 0) )
        src_sliceX = ( slice(0, 0) )
    dest_slice = ( dest_sliceY, dest_sliceX )
    src_slice = ( src_sliceY, src_sliceX )
    return ( dest_slice, src_slice )


------

I have intentionally made it expanded and without contractions
so that it is better understandable.
It returns the intersection area of two arrays given an offset.
First returned tuple element is the slice for DEST array and the
second element is the slice for SRC array.
If there is no intersection along one of the axis at all
it returns the corresponding slice as (0,0)

With this helper function one can blit arrays easily e.g. example code:

W = 8; H = 8
DEST = numpy.ones([H,W], dtype = "uint8")
w = 4; h = 1
SRC = numpy.zeros([h,w], dtype = "uint8")
SRC[:]=8
offset = (0,9)
ds, ss = interslice (DEST, SRC, offset )

# blit SRC into DEST
DEST[ds] = SRC[ss]

So changing the offset one can observe how the
SRC array is trimmed if it is crosses the DEST boundaries.
I think it is very useful function in general and it has
well defined behaviour. It has usage not only for graphics,
but actually any data copying-pasting between arrays.

So I am looking forward to comments on this proposal.


Mikhail
_______________________________________________
NumPy-Discussion mailing list
[hidden email]
https://mail.python.org/mailman/listinfo/numpy-discussion
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Array blitting (pasting one array into another)

Joseph Fox-Rabinovitz
This is a useful idea certainly. I would recommended extending it to an arbitrary number of axes. You could either raise an error if the ndim of the two arrays are unequal, or allow a broadcast of a lesser ndimmed src array.

- Joe 

On Jun 29, 2017 20:17, "Mikhail V" <[hidden email]> wrote:
Hello all

I often need to copy one array into another array, given an offset.
This is how the "blit" function can be understood, i.e. in
every graphical lib there is such a function.
The common definition is like:
blit ( dest, src, offset ):
where dest is destination array, src is source array and offset is
coordinates in destination where the src should pe blitted.
Main feature of such function is that it never gives an error,
so if the source does not fit into the destination array, it is simply trimmed.
And respectively if there is no intersection area then nothing happens.

Hope this is clear.
So to make it work with Numpy arrays one need to calculate the
slices before copying the data.
I cannot find any Numpy or Python method to help with that so probably
it does not exist yet.
If so, my proposal is to add a Numpy method which helps with that.
Namely the proposal will be to add a method which returns
the slices for the intersection areas of two arbitrary arrays, given an offset,
so then one can "blit" the array into another with simple assignment =.

Here is a Python function I use for 2d arrays now:

def interslice ( dest, src, offset ):
    y,x = offset
    H,W = dest.shape
    h,w = src.shape

    dest_starty = max (y,0)
    dest_endy = min (y+h,H)
    dest_startx = max (x,0)
    dest_endx = min (x+w,W)

    src_starty = 0
    src_endy = h
    if y<0:     src_starty = -y
    by = y+h - H             # Y bleed
    if by>0: src_endy = h - by

    src_startx = 0
    src_endx = w
    if x<0:  src_startx = -x
    bx = x+w - W             # X bleed
    if bx>0:  src_endx = w - bx

    dest_sliceY =  slice(dest_starty,dest_endy)
    dest_sliceX =  slice(dest_startx,dest_endx)
    src_sliceY = slice(src_starty, src_endy)
    src_sliceX = slice(src_startx, src_endx)
    if dest_endy <= dest_starty:
        print "No Y intersection !"
        dest_sliceY = ( slice(0, 0) )
        src_sliceY = ( slice(0, 0) )
    if dest_endx <= dest_startx:
        print "No X intersection !"
        dest_sliceX = ( slice(0, 0) )
        src_sliceX = ( slice(0, 0) )
    dest_slice = ( dest_sliceY, dest_sliceX )
    src_slice = ( src_sliceY, src_sliceX )
    return ( dest_slice, src_slice )


------

I have intentionally made it expanded and without contractions
so that it is better understandable.
It returns the intersection area of two arrays given an offset.
First returned tuple element is the slice for DEST array and the
second element is the slice for SRC array.
If there is no intersection along one of the axis at all
it returns the corresponding slice as (0,0)

With this helper function one can blit arrays easily e.g. example code:

W = 8; H = 8
DEST = numpy.ones([H,W], dtype = "uint8")
w = 4; h = 1
SRC = numpy.zeros([h,w], dtype = "uint8")
SRC[:]=8
offset = (0,9)
ds, ss = interslice (DEST, SRC, offset )

# blit SRC into DEST
DEST[ds] = SRC[ss]

So changing the offset one can observe how the
SRC array is trimmed if it is crosses the DEST boundaries.
I think it is very useful function in general and it has
well defined behaviour. It has usage not only for graphics,
but actually any data copying-pasting between arrays.

So I am looking forward to comments on this proposal.


Mikhail
_______________________________________________
NumPy-Discussion mailing list
[hidden email]
https://mail.python.org/mailman/listinfo/numpy-discussion

_______________________________________________
NumPy-Discussion mailing list
[hidden email]
https://mail.python.org/mailman/listinfo/numpy-discussion
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Array blitting (pasting one array into another)

Sebastian Berg
In reply to this post by Mikhail V
On Fri, 2017-06-30 at 02:16 +0200, Mikhail V wrote:

> Hello all
>
> I often need to copy one array into another array, given an offset.
> This is how the "blit" function can be understood, i.e. in
> every graphical lib there is such a function.
> The common definition is like:
> blit ( dest, src, offset ):
> where dest is destination array, src is source array and offset is
> coordinates in destination where the src should pe blitted.
> Main feature of such function is that it never gives an error,
> so if the source does not fit into the destination array, it is
> simply trimmed.
> And respectively if there is no intersection area then nothing
> happens.
>
> Hope this is clear.
> So to make it work with Numpy arrays one need to calculate the
> slices before copying the data.
> I cannot find any Numpy or Python method to help with that so
> probably
> it does not exist yet.
> If so, my proposal is to add a Numpy method which helps with that.
> Namely the proposal will be to add a method which returns
> the slices for the intersection areas of two arbitrary arrays, given
> an offset,
> so then one can "blit" the array into another with simple assignment
> =.
>
> Here is a Python function I use for 2d arrays now:
>
> def interslice ( dest, src, offset ):
>     y,x = offset
>     H,W = dest.shape
>     h,w = src.shape
>
>     dest_starty = max (y,0)
>     dest_endy = min (y+h,H)
>     dest_startx = max (x,0)
>     dest_endx = min (x+w,W)
>
>     src_starty = 0
>     src_endy = h
>     if y<0:     src_starty = -y
>     by = y+h - H             # Y bleed
>     if by>0: src_endy = h - by
>
>     src_startx = 0
>     src_endx = w
>     if x<0:  src_startx = -x
>     bx = x+w - W             # X bleed
>     if bx>0:  src_endx = w - bx
>
>     dest_sliceY =  slice(dest_starty,dest_endy)
>     dest_sliceX =  slice(dest_startx,dest_endx)
>     src_sliceY = slice(src_starty, src_endy)
>     src_sliceX = slice(src_startx, src_endx)
>     if dest_endy <= dest_starty:
>         print "No Y intersection !"
>         dest_sliceY = ( slice(0, 0) )
>         src_sliceY = ( slice(0, 0) )
>     if dest_endx <= dest_startx:
>         print "No X intersection !"
>         dest_sliceX = ( slice(0, 0) )
>         src_sliceX = ( slice(0, 0) )
>     dest_slice = ( dest_sliceY, dest_sliceX )
>     src_slice = ( src_sliceY, src_sliceX )
>     return ( dest_slice, src_slice )
>
>
> ------
>
> I have intentionally made it expanded and without contractions
> so that it is better understandable.
> It returns the intersection area of two arrays given an offset.
> First returned tuple element is the slice for DEST array and the
> second element is the slice for SRC array.
> If there is no intersection along one of the axis at all
> it returns the corresponding slice as (0,0)
>
> With this helper function one can blit arrays easily e.g. example
> code:
>
> W = 8; H = 8
> DEST = numpy.ones([H,W], dtype = "uint8")
> w = 4; h = 1
> SRC = numpy.zeros([h,w], dtype = "uint8")
> SRC[:]=8
> offset = (0,9)
> ds, ss = interslice (DEST, SRC, offset )
>
> # blit SRC into DEST
> DEST[ds] = SRC[ss]
>
> So changing the offset one can observe how the
> SRC array is trimmed if it is crosses the DEST boundaries.
> I think it is very useful function in general and it has
> well defined behaviour. It has usage not only for graphics,
> but actually any data copying-pasting between arrays.
>
> So I am looking forward to comments on this proposal.
>
First, the slice object provides some help:
```
In [8]: s = slice(1, 40, 2)

In [9]: s.indices(20)  # length of dimension
Out[9]: (1, 20, 2)  # and the 40 becomes 20

```

Second, there is almost no overhead of creating a view, so just create
the views first (it may well be faster). Then use the result to see how
large they actually are and index those (a second time) instead of
creating new slice objects.

- Sebastian


>
> Mikhail
> _______________________________________________
> NumPy-Discussion mailing list
> [hidden email]
> https://mail.python.org/mailman/listinfo/numpy-discussion
>
_______________________________________________
NumPy-Discussion mailing list
[hidden email]
https://mail.python.org/mailman/listinfo/numpy-discussion

signature.asc (817 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Array blitting (pasting one array into another)

Mikhail V
In reply to this post by Joseph Fox-Rabinovitz
On 30 June 2017 at 03:34, Joseph Fox-Rabinovitz
<[hidden email]> wrote:
> This is a useful idea certainly. I would recommended extending it to an
> arbitrary number of axes. You could either raise an error if the ndim of the
> two arrays are unequal, or allow a broadcast of a lesser ndimmed src array.
>


Now I am thinking that there is probably an even better, more generalised
way to provide this functionality.
Say if we had a function "intersect" which would be defined as follows:

intersect(A, B, offset)

where A, B are vector endpoints, and the offset is the distance
between their origins.
So to find a needed slice I could simply pass the shapes:

intersect (DEST.shape, SRC.shape, offset)

Hmm. there is something to think about. Could be a
better idea to propose this, since it could be used in many
other sitiations, not only for finding slice intersection.

Although I'll need some time to think out more examples and use cases.

Mikhail

>
> On Jun 29, 2017 20:17, "Mikhail V" <[hidden email]> wrote:
>>
>> Hello all
>>
>> I often need to copy one array into another array, given an offset.
>> This is how the "blit" function can be understood, i.e. in
>> every graphical lib there is such a function.
>> The common definition is like:
>> blit ( dest, src, offset ):
>> where dest is destination array, src is source array and offset is
>> coordinates in destination where the src should pe blitted.
>> Main feature of such function is that it never gives an error,
>> so if the source does not fit into the destination array, it is simply
>> trimmed.
>> And respectively if there is no intersection area then nothing happens.
>>
>> Hope this is clear.
>> So to make it work with Numpy arrays one need to calculate the
>> slices before copying the data.
>> I cannot find any Numpy or Python method to help with that so probably
>> it does not exist yet.
>> If so, my proposal is to add a Numpy method which helps with that.
>> Namely the proposal will be to add a method which returns
>> the slices for the intersection areas of two arbitrary arrays, given an
>> offset,
>> so then one can "blit" the array into another with simple assignment =.
>>
>> Here is a Python function I use for 2d arrays now:
>>
>> def interslice ( dest, src, offset ):
>>     y,x = offset
>>     H,W = dest.shape
>>     h,w = src.shape
>>
>>     dest_starty = max (y,0)
>>     dest_endy = min (y+h,H)
>>     dest_startx = max (x,0)
>>     dest_endx = min (x+w,W)
>>
>>     src_starty = 0
>>     src_endy = h
>>     if y<0:     src_starty = -y
>>     by = y+h - H             # Y bleed
>>     if by>0: src_endy = h - by
>>
>>     src_startx = 0
>>     src_endx = w
>>     if x<0:  src_startx = -x
>>     bx = x+w - W             # X bleed
>>     if bx>0:  src_endx = w - bx
>>
>>     dest_sliceY =  slice(dest_starty,dest_endy)
>>     dest_sliceX =  slice(dest_startx,dest_endx)
>>     src_sliceY = slice(src_starty, src_endy)
>>     src_sliceX = slice(src_startx, src_endx)
>>     if dest_endy <= dest_starty:
>>         print "No Y intersection !"
>>         dest_sliceY = ( slice(0, 0) )
>>         src_sliceY = ( slice(0, 0) )
>>     if dest_endx <= dest_startx:
>>         print "No X intersection !"
>>         dest_sliceX = ( slice(0, 0) )
>>         src_sliceX = ( slice(0, 0) )
>>     dest_slice = ( dest_sliceY, dest_sliceX )
>>     src_slice = ( src_sliceY, src_sliceX )
>>     return ( dest_slice, src_slice )
>>
>>
>> ------
>>
>> I have intentionally made it expanded and without contractions
>> so that it is better understandable.
>> It returns the intersection area of two arrays given an offset.
>> First returned tuple element is the slice for DEST array and the
>> second element is the slice for SRC array.
>> If there is no intersection along one of the axis at all
>> it returns the corresponding slice as (0,0)
>>
>> With this helper function one can blit arrays easily e.g. example code:
>>
>> W = 8; H = 8
>> DEST = numpy.ones([H,W], dtype = "uint8")
>> w = 4; h = 1
>> SRC = numpy.zeros([h,w], dtype = "uint8")
>> SRC[:]=8
>> offset = (0,9)
>> ds, ss = interslice (DEST, SRC, offset )
>>
>> # blit SRC into DEST
>> DEST[ds] = SRC[ss]
>>
>> So changing the offset one can observe how the
>> SRC array is trimmed if it is crosses the DEST boundaries.
>> I think it is very useful function in general and it has
>> well defined behaviour. It has usage not only for graphics,
>> but actually any data copying-pasting between arrays.
>>
>> So I am looking forward to comments on this proposal.
>>
>>
>> Mikhail
>> _______________________________________________
>> NumPy-Discussion mailing list
>> [hidden email]
>> https://mail.python.org/mailman/listinfo/numpy-discussion
>
>
> _______________________________________________
> NumPy-Discussion mailing list
> [hidden email]
> https://mail.python.org/mailman/listinfo/numpy-discussion
>
_______________________________________________
NumPy-Discussion mailing list
[hidden email]
https://mail.python.org/mailman/listinfo/numpy-discussion
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Array blitting (pasting one array into another)

Joseph Fox-Rabinovitz
If you are serious about adding this to numpy, an even better option might be to create a pull request with the implementation and solicit comments on that. The problem lends itself to an easy solution in pure Python, so this should not be too hard to do.

    -Joe


On Fri, Jun 30, 2017 at 4:08 PM, Mikhail V <[hidden email]> wrote:
On 30 June 2017 at 03:34, Joseph Fox-Rabinovitz
<[hidden email]> wrote:
> This is a useful idea certainly. I would recommended extending it to an
> arbitrary number of axes. You could either raise an error if the ndim of the
> two arrays are unequal, or allow a broadcast of a lesser ndimmed src array.
>


Now I am thinking that there is probably an even better, more generalised
way to provide this functionality.
Say if we had a function "intersect" which would be defined as follows:

intersect(A, B, offset)

where A, B are vector endpoints, and the offset is the distance
between their origins.
So to find a needed slice I could simply pass the shapes:

intersect (DEST.shape, SRC.shape, offset)

Hmm. there is something to think about. Could be a
better idea to propose this, since it could be used in many
other sitiations, not only for finding slice intersection.

Although I'll need some time to think out more examples and use cases.

Mikhail

>
> On Jun 29, 2017 20:17, "Mikhail V" <[hidden email]> wrote:
>>
>> Hello all
>>
>> I often need to copy one array into another array, given an offset.
>> This is how the "blit" function can be understood, i.e. in
>> every graphical lib there is such a function.
>> The common definition is like:
>> blit ( dest, src, offset ):
>> where dest is destination array, src is source array and offset is
>> coordinates in destination where the src should pe blitted.
>> Main feature of such function is that it never gives an error,
>> so if the source does not fit into the destination array, it is simply
>> trimmed.
>> And respectively if there is no intersection area then nothing happens.
>>
>> Hope this is clear.
>> So to make it work with Numpy arrays one need to calculate the
>> slices before copying the data.
>> I cannot find any Numpy or Python method to help with that so probably
>> it does not exist yet.
>> If so, my proposal is to add a Numpy method which helps with that.
>> Namely the proposal will be to add a method which returns
>> the slices for the intersection areas of two arbitrary arrays, given an
>> offset,
>> so then one can "blit" the array into another with simple assignment =.
>>
>> Here is a Python function I use for 2d arrays now:
>>
>> def interslice ( dest, src, offset ):
>>     y,x = offset
>>     H,W = dest.shape
>>     h,w = src.shape
>>
>>     dest_starty = max (y,0)
>>     dest_endy = min (y+h,H)
>>     dest_startx = max (x,0)
>>     dest_endx = min (x+w,W)
>>
>>     src_starty = 0
>>     src_endy = h
>>     if y<0:     src_starty = -y
>>     by = y+h - H             # Y bleed
>>     if by>0: src_endy = h - by
>>
>>     src_startx = 0
>>     src_endx = w
>>     if x<0:  src_startx = -x
>>     bx = x+w - W             # X bleed
>>     if bx>0:  src_endx = w - bx
>>
>>     dest_sliceY =  slice(dest_starty,dest_endy)
>>     dest_sliceX =  slice(dest_startx,dest_endx)
>>     src_sliceY = slice(src_starty, src_endy)
>>     src_sliceX = slice(src_startx, src_endx)
>>     if dest_endy <= dest_starty:
>>         print "No Y intersection !"
>>         dest_sliceY = ( slice(0, 0) )
>>         src_sliceY = ( slice(0, 0) )
>>     if dest_endx <= dest_startx:
>>         print "No X intersection !"
>>         dest_sliceX = ( slice(0, 0) )
>>         src_sliceX = ( slice(0, 0) )
>>     dest_slice = ( dest_sliceY, dest_sliceX )
>>     src_slice = ( src_sliceY, src_sliceX )
>>     return ( dest_slice, src_slice )
>>
>>
>> ------
>>
>> I have intentionally made it expanded and without contractions
>> so that it is better understandable.
>> It returns the intersection area of two arrays given an offset.
>> First returned tuple element is the slice for DEST array and the
>> second element is the slice for SRC array.
>> If there is no intersection along one of the axis at all
>> it returns the corresponding slice as (0,0)
>>
>> With this helper function one can blit arrays easily e.g. example code:
>>
>> W = 8; H = 8
>> DEST = numpy.ones([H,W], dtype = "uint8")
>> w = 4; h = 1
>> SRC = numpy.zeros([h,w], dtype = "uint8")
>> SRC[:]=8
>> offset = (0,9)
>> ds, ss = interslice (DEST, SRC, offset )
>>
>> # blit SRC into DEST
>> DEST[ds] = SRC[ss]
>>
>> So changing the offset one can observe how the
>> SRC array is trimmed if it is crosses the DEST boundaries.
>> I think it is very useful function in general and it has
>> well defined behaviour. It has usage not only for graphics,
>> but actually any data copying-pasting between arrays.
>>
>> So I am looking forward to comments on this proposal.
>>
>>
>> Mikhail
>> _______________________________________________
>> NumPy-Discussion mailing list
>> [hidden email]
>> https://mail.python.org/mailman/listinfo/numpy-discussion
>
>
> _______________________________________________
> NumPy-Discussion mailing list
> [hidden email]
> https://mail.python.org/mailman/listinfo/numpy-discussion
>
_______________________________________________
NumPy-Discussion mailing list
[hidden email]
https://mail.python.org/mailman/listinfo/numpy-discussion


_______________________________________________
NumPy-Discussion mailing list
[hidden email]
https://mail.python.org/mailman/listinfo/numpy-discussion
Loading...