Массив плавающих изображений numpy, значение int 0..255

Я получил 3 массива данных NumPy r,g,b, представленных в виде 2D-массива float64 (720x1024)
По сути, для каждой строки каждый канал представляет собой набор поплавков:

[[0.94984896 0.96076077 0.9599071  ... 0.80338298 0.80253267 0.80560301], 
 [0.94958899 0.95265769 0.95964721 ... 0.80312296 0.80619422 0.80534302], 
 [0.94932439 0.95239315 0.95938273 ... 0.80285821 0.80592952 0.80115679], ..., 
 [0.97768162 0.98087441 0.98014583 ... 0.87006474 0.87325722 0.87252819], 
 [0.97711028 0.98030547 0.9795793  ... 0.86948629 0.87268113 0.87587604], 
 [0.97653759 0.97581362 0.9711683  ... 0.8610633  0.86818208 0.87530095]]

Что я хотел бы сделать, так это сделать его каналом, который я могу использовать в cv2.merge((r,g,b))
Так что значения float64 для каждой строки умножаются на 255 и что-то, что принимает cv2.merge().
Я думаю, что NumPy может делать такие вещи, но я запутался, есть ли способ сделать это?

просто (arr * 256).astype('uint8')?

Quang Hoang 18.12.2020 18:33

@QuangHoang, если есть вероятность, что ввод будет 1.0, вы должны умножить на 255,99999 вместо 256, чтобы предотвратить ошибку переполнения.

Mark Ransom 18.12.2020 18:39

или просто умножьте на 255 и используйте np.round или np.clip

Christoph Rackwitz 18.12.2020 19:16
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python.
Некоторые методы, о которых вы не знали, что они существуют в Python.
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
3
1 065
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

давайте рассмотрим ваши три массива как r и g и b соответственно. В таком случае вам нужен следующий код:

Edit-1: на основе комментария Марка я предлагаю следующие изменения

r = (r*255).round(0).astype(np.uint8)
g = (g*255).round(0).astype(np.uint8)
b = (b*255).round(0).astype(np.uint8)

img = np.stack((r,g,b), axis=-1)

Edit-2: я могу ошибаться, но я не уверен, что умножение на 255,99999 лучше. Это приведет к тому, что многие другие значения пикселей будут сдвинуты до следующего значения, чем они были изначально или должны были быть, вот небольшой пример, который я мог бы придумать.

# random fraction values
a:  [3.2000e-04 5.5111e-01 9.9999e-01 9.8850e-01]

a*255.99999:  [8.19199968e-02 1.41084154e+02 2.55997430e+02 2.53055990e+02]
(a*255.99999).astype(np.uint8):  [  0 141 255 253] 

a*255:  [8.1600000e-02 1.4053305e+02 2.5499745e+02 2.5206750e+02]
(a*255).round(0).astype(np.uint8):  [  0 141 255 252]

Кроме того, я провел еще один небольшой эксперимент со всеми возможными значениями пикселей, и это удивительно говорит о том, что оба метода точны.

pixels = np.arange(256, dtype=np.float64)
pixels /= 255

print(sum((pixels*255.99999).astype(np.uint8) == np.arange(256)))
# output is 256
print(sum((pixels*255).round(0).astype(np.uint8) == np.arange(256)))
# output is 256

Я предпочитаю умножать на 255,9999 вместо 255, иначе 255 будет очень мало представлено в выводе.

Mark Ransom 18.12.2020 18:40

Нет, округление не лучше. Теперь и 0, и 255 недостаточно представлены.

Mark Ransom 18.12.2020 18:51

Можно ли как-то подтвердить на примере? @МаркРансом

sai 18.12.2020 18:54

если у вас есть критика этого ответа, вам нужно сделать шаг вперед и обосновать свои рассуждения. предложение использовать магическое число ставит вас в невыгодное положение.

Christoph Rackwitz 18.12.2020 19:18

@sai умножь на 256, тогда np.clip. в принципе, диапазон [0..1) сопоставляется с [0..256) (коэффициент 256), и если есть значения 1,0, которые сопоставляются с 256, просто обрежьте их до 255. чтобы правильно ответить на этот вопрос, нам нужно было бы знать, как эти значения с плавающей запятой были сгенерированы в первую очередь.

Christoph Rackwitz 18.12.2020 19:21

@ChristophRackwitz Я полностью с вами согласен, я готов учиться и защищать то, что я считаю правильным. Я также согласен с необходимостью знать, как изначально генерируются фракционные ценности.

sai 18.12.2020 19:30

@MarkRansom Не могли бы вы прокомментировать мои выводы?

sai 18.12.2020 19:31

Преобразование в целочисленные значения требует преобразования диапазонов в строке действительных чисел. В первом случае, умножая на 255 и усекая, каждый из этих диапазонов имеет ширину 1/255, кроме последнего для 255, который имеет диапазон 0. При округлении большинство диапазонов по-прежнему имеют ширину 1/255, за исключением первый и последний, которые теперь оба 0,5/255.

Mark Ransom 18.12.2020 19:35

Ваш недавно добавленный тестовый пример не говорит вам, что, по вашему мнению, он делает. Преобразование целых чисел туда и обратно намного проще, чем преобразование произвольных вещественных значений.

Mark Ransom 18.12.2020 19:38

Попробуйте протестировать с помощью pixels = np.arange(1024, dtype=np.float64) / 1024, и, возможно, станет понятно, о чем я говорю.

Mark Ransom 18.12.2020 19:43

Что ж, в моем случае умножьте на 255 швов, мои поплавки находятся в диапазоне от 0 до 1. поэтому максимальное значение может быть 255, а минимальное 0, в opencvt есть некоторые другие значения и фильтры для контраста и яркости, которые в конечном итоге также будут использоваться.

Peter 18.12.2020 20:03

@user219279 user219279 сравните шансы получить результат 255 с шансами получить результат 254.

Mark Ransom 18.12.2020 21:15

я поменял на 255.999 визуально разницы для глаз не было.

Peter 21.12.2020 03:05

Другие вопросы по теме