Подтвердить что ты не робот

Matplotlib imshow графики разные, если использовать colormap или RGB массив

У меня возникает следующая проблема: я сохраняю 16-битные изображения TIFF с помощью микроскопа, и мне нужно их проанализировать. Я хочу сделать это с помощью numpy и matplotlib, но когда я хочу сделать что-то так же просто, как прорисовать изображение зеленым (мне потом придется накладывать другие изображения), он терпит неудачу.

Вот пример, когда я пытаюсь построить изображение либо в виде массива RGB, либо по умолчанию jet colormap.

import numpy as np
import matplotlib.pyplot as plt
import cv2

imageName = 'image.tif'

# image as luminance 
img1 = cv2.imread(imageName,-1)

# image as RGB array
shape = (img1.shape[0], img1.shape[1], 3)
img2 = np.zeros(shape,dtype='uint16')
img2[...,1] += img1

fig = plt.figure(figsize=(20,8))
ax1 = fig.add_subplot(1,2,1)
ax2 = fig.add_subplot(1,2,2)

im1 = ax1.imshow(img1,interpolation='none')
im2 = ax2.imshow(img2,interpolation='none')
fig.show()

Что мне дает следующий рисунок: enter image description here

Прошу прощения, если вопрос слишком прост, но я понятия не имею, почему именно этот сюжет показывает эти артефакты. Я хотел бы получить зеленый масштаб, что-то вроде того, как выглядит фигура (imageJ также дает нечто похожее на левый сюжет).

Благодарим вас за сотрудничество.

4b9b3361

Ответ 1

Я нахожу правильный сюжет гораздо более художественным...

matplotlib довольно сложна, когда дело доходит до интерпретации изображений. Это примерно так:

  • если изображение представляет собой массив NxM любого типа, оно интерпретируется через colormap (автомасштабирование, если не указано иное). (В принципе, если массив является массивом float, масштабированным до 0..1, его следует интерпретировать как изображение в градациях серого. Это то, что говорит документация, но на практике этого не происходит.)

    /li >
  • если изображение представляет собой массив NxMx3 float, компоненты RGB интерпретируются как компоненты RGB между 0..1. Если значения вне этого диапазона, они берутся с положительным модулем 1, то есть 1,2 → 0,2, -1,7 → 0,3 и т.д.

  • если изображение представляет собой массив NxMx3 uint8, оно интерпретируется как стандартное изображение (компоненты 0..255)

  • если изображение NxMx4, интерпретация имеет значение выше, но четвертым компонентом является непрозрачность (альфа)

Итак, если вы даете matplotlib массив целых чисел NxMx3, отличный от uint8 или float, результаты не определены. Однако, глядя на исходный код, можно понять нечетное поведение:

if A.dtype != np.uint8:
    A = (255*A).astype(np.uint8)

где A - массив изображений. Итак, если вы дадите uint16 значения 0, 1, 2, 3, 4..., вы получите 0, 255, 254, 253,... Да, это будет выглядеть очень странно. (ИМХО, интерпретация может быть немного более интуитивной, но так оно и делается.)


В этом случае самым простым решением является разделение массива на 65535. Затем изображение должно быть таким, как ожидалось. Кроме того, если исходное изображение действительно линейно, вам необходимо выполнить обратную гамма-коррекцию:

img1_corr = (img1 / 65535.)**(1/2.2)

В противном случае ваши средние тона будут слишком темными.