4

I want to add or subtract two arrays in numpy but the result has to be bounded for each element. If I restrict the typ (i.e. uint8) any exeeding sum produces an overflow (i.e. start from zero again) and any exeeding difference an underflow (i.e. start from 255 again). This is not what I want, i.e. I want to stop at 0/255 (in my example).

Is there any way to do this without accessing each element?

Thank you in advance.

Michael Hecht
  • 2,093
  • 6
  • 25
  • 37

4 Answers4

2

you can use a mask

Example: addition not exceeding 255:

import numpy as np
# create exaple data where sum exceeds 255
a = np.arange(118,130,dtype = np.uint8)
b = a.copy()
res = np.add(a,b, dtype = np.uint16);
mask = res > 255
res[mask] = 255
res = np.uint8(res)

Results are:

>>> print a
array([118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129], dtype=uint8)
>>> print b
array([118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129], dtype=uint8)
>>> print mask
array([False, False, False, False, False, False, False, False, False, False, True, True], dtype=bool)
>>> print res
array([236, 238, 240, 242, 244, 246, 248, 250, 252, 254, 255, 255], dtype=uint8)

The mask only works correct as a numpy array. Otherwise, advanced indexing will return a view, not a copy, see SciPy/NumPy documentation.

jkalden
  • 1,548
  • 4
  • 24
  • 26
  • Is this also working, if the np.type is uint8? I checked it and the answer is no. So I need to convert the arrays to a larger type (how?) prior to adding it? – Michael Hecht Oct 30 '14 at 09:27
  • See my edit. Now, `a`, `b` and result `res` are np.uint8 – jkalden Oct 30 '14 at 10:02
  • Where can I accept it? THere is no button to click on, is it? – Michael Hecht Oct 30 '14 at 13:11
  • 1
    Below the voting symbol left of the answer, there's a check mark. When you hover it with the mouse it should ask whether you want to accept it. See a description [here.](http://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work) Accepting the answer also shows other users that a solution exists for the given problem. – jkalden Oct 30 '14 at 13:21
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/63933/discussion-between-jkalden-and-michael-hecht). – jkalden Oct 30 '14 at 13:26
  • I thik that it's better using the `np.int16` data type to support also the difference case – Aelius Feb 18 '21 at 09:59
  • @Aelius: might also work, or maybe even better, but my answer is also more than 6 years old, so I just leave it as is... – jkalden Feb 18 '21 at 10:21
  • yes, I wrote a comment only for reference of further readers – Aelius Feb 18 '21 at 12:54
1

You can work with OpenCV if you have the cv2 library :

import cv2  
import numpy as np  

x=np.uint8([250])  
y=np.uint8([10])  
print cv2.add(x,y)  #250+ 10 =260=>255  

Answer :

[[255]] 
Martin Evans
  • 45,791
  • 17
  • 81
  • 97
0

As pointed out by jkalden, it's possible to use the add and subtract function of NumPy with a dtyperange wider than the uint8 data type, but instead of passing through a mask you can use the np.where function:

a = np.arange(118,130,dtype = np.uint8)
b = a.copy()
sum = np.add(a,b, dtype = np.int16)
uint8_sum = np.where(sum>255, 255, sum).astype(np.uint8)

Result:

>>> print(uint8_sum)
array([236, 238, 240, 242, 244, 246, 248, 250, 252, 254, 255, 255],
  dtype=uint8)

In the same way it's possible to perform the subtraction:

a = np.arange(118,130,dtype = np.uint8)
b = a.copy()[::-1]
diff = np.subtract(a,b, dtype = np.int16)
uint8_diff = np.where(diff<0, 0, diff).astype(np.uint8)

Result:

>>> print(uint8_diff)
array([0, 0, 0, 0, 0, 0, 1, 3, 5, 7, 9, 11],
  dtype=uint8)
Aelius
  • 1,029
  • 11
  • 22
0

simplified one-liners using np.where as suggested by Aelius, without extra variable and extra type convertions

Bounded add:

summ = np.where(np.add(a,b, dtype = np.int16)>255,255,a+b)

Bounded subtract:

subb = np.where(np.subtract(a,b, dtype = np.int16)<0,0,a-b)

Example:

import numpy as np
a = np.arange(118,135,dtype = np.uint8)
b = a.copy()

summ = np.where(np.add(a,b, dtype = np.int16)>255,255,a+b)
>>> print(summ)
[236 238 240 242 244 246 248 250 252 254 255 255 255 255 255 255 255]

subb = np.where(np.subtract(a,b[::-1], dtype = np.int16)<0,0,a-b[::-1])
>>> print(subb)
[ 0  0  0  0  0  0  0  0  0  2  4  6  8 10 12 14 16]
codenio
  • 721
  • 10
  • 17