Ограничение минимального и максимального значений в массиве numpy
Как сделать так, чтобы при добавлении значения к красному каналу пикселя он не становился нулевым?
import numpy as np
from PIL import Image
rd = int(input())
gd = int(input())
bd = int(input())
img1 = np.copy(Image.open("./Images_processing/image.jpg"))
img = img1.copy()
img[..., 0] += rd
img[..., 1] += gd
img[..., 2] += bd
a = np.where(img <= 255, img, 255)
b = np.where(a >= 0, a, 0)
img = Image.fromarray(b)
img.save("./Images_processing/image1.jpg")
Вот тут я пытаюсь изменить цвет пикселей так, чтобы если он был больше 255, то оставался 255, а если меньше 0, то оставался 0. Но numpy меняет эти значения (если > 255 - то на 0, если < 0, то на 255). Как можно было бы это исправить?
Пример:
import numpy as np
from PIL import Image
rd = 255
gd = 0
bd = 0
img1 = np.copy(Image.open("frame.jpg"))
img = np.clip(img1, 0, 255)
print(img[-1], 'img')
img[..., 0] += rd
img[..., 1] += gd
img[..., 2] += bd
print(img[-1], 'img')
img = Image.fromarray(img)
img.save("image1.jpg")
print(b[-1], 'b')
img = Image.fromarray(b)
img.save("image1.jpg")
Вывод:
[[70 64 64]
[67 61 61]
[67 61 61]
...
[49 38 42]
[52 41 45]
[44 33 37]] img1
[[69 64 64]
[66 61 61]
[66 61 61]
...
[48 38 42]
[51 41 45]
[43 33 37]] img2
Process finished with exit code 0
Ответы (2 шт):
Воспользуйтесь методом numpy.clip():
import numpy as np
a = np.array([256, -1])
res = np.clip(a, 0, 255) # первый аргумент - массив, второй - минимальное,
# третий - максимальное значение в массиве
print(res)
[255 0]
У вас просто происходит переполнение типа данных. Изначально данные картинки имеют тип np.uint8, это целый беззнаковый байт - значения от 0 до 255. Если у вас, например, компонента имеет значение 255 и вы добавите к ней 1, то произойдёт переполнение и значение станет не 256, как вы ожидаете, а 0. И наоборот, если вы из 0 вычтете 1, то получите не -1, а 255.
# uint8 [0, 255]
255 + 1 -> 0
0 - 1 -> 255
Теперь как это исправить. Повысьте тип данных до знакового большей разрядности (это будет int16) прежде чем делать расчёты:
img = img1.copy().astype(np.int16)
^^^^^^^^^^^^^^^^^
Теперь расчёты будут идти без переполнения, так, как вы ожидаете:
#int16 [-32768, 32767]
255 + 1 -> 256
0 - 1 -> -1
Но после расчётов нужно будет вернуть тип данных обратно, чтобы сохранить картинку. Данные в этот момент у вас уже приведены в диапазон типа uint8 0-255, поэтому можно спокойно преобразовывать, данные не "испортятся" при преобразовании в более узкий тип:
img2 = Image.fromarray(b.astype(np.uint8))
^^^^^^^^^^^^^^^^^