как преобразовать изображение цветовой карты в скалярные значения - PullRequest
9 голосов
/ 15 сентября 2010

Как инвертировать изображение с цветным изображением?

У меня есть 2D-изображение, которое отображает данные на карте цветов.Я хотел бы прочитать изображение и «перевернуть» цветовую карту, то есть найти конкретное значение RGB и превратить его в число с плавающей точкой.

Например: используя это изображение: http://matplotlib.sourceforge.net/_images/mri_demo.png

Я должен быть в состоянии получить матрицу с плавающей точкой 440x360, зная, что карта цветов была cm.jet

from pylab import imread
import matplotlib.cm as cm
a=imread('mri_demo.png')
b=colormap2float(a,cm.jet) #<-tricky part

Ответы [ 3 ]

8 голосов
/ 16 сентября 2010

Там могут быть лучшие способы сделать это;Я не уверен.Если вы прочитаете help(cm.jet), вы увидите алгоритм, используемый для сопоставления значений в интервале [0,1] с 3-кортежами RGB.С небольшим количеством бумаги и карандаша вы могли бы разработать формулы для инвертирования кусочно-линейных функций, которые определяют отображение.

Однако существует ряд проблем, которые делают решение для бумаги и карандаша несколько непривлекательным:

  1. Это много трудоемкой алгебры, и решение является специфическим для cm.jet.Вам придется снова проделать всю эту работу, если вы измените карту цветов.Как автоматизировать решение этих алгебраических уравнений интересно, но я не знаю, как решить эту проблему.

  2. В общем случае карта цветов может быть необратимой (может быть несколько значенийбыть сопоставлены с тем же цветом).В случае cm.jet значения от 0,11 до 0,125 отображаются, например, в 3-кортеже RGB (0,0,1).Поэтому, если ваше изображение содержит чистый синий пиксель, на самом деле нет никакого способа узнать, пришло ли оно из значения 0,11 или, скажем, 0,125.

  3. Отображение из [0,1] к 3-кортежу - это кривая в 3-пространстве.Цвета на вашем изображении могут не идеально лежать на этой кривой.Например, может быть ошибка округления.Таким образом, любое практическое решение должно иметь возможность интерполировать или каким-либо образом проецировать точки в трехмерном пространстве на кривую.

Из-за проблемы неединственности и проблемы проекции / интерполяции может быть многовозможные решения проблемы, которую вы ставите.Ниже приведена только одна возможность.

Вот один из способов решения проблем уникальности и проекции / интерполяции:

Создайте gradient, который действует как «кодовая книга».gradient - это массив RGBA 4-х кортежей в цветовой карте cm.jet.Цвета gradient соответствуют значениям от 0 до 1. Используйте функцию векторного квантования scipy scipy.cluster.vq.vq , чтобы отобразить все цвета в вашем изображении, mri_demo.png, на ближайший цвет.в gradient.Поскольку цветовая карта может использовать один и тот же цвет для многих значений, градиент может содержать повторяющиеся цвета.Я оставляю до scipy.cluster.vq.vq, чтобы решить, какой (возможно) неуникальный индекс кодовой книги связать с конкретным цветом.

import matplotlib.pyplot as plt
import matplotlib.cm as cm
import numpy as np
import scipy.cluster.vq as scv

def colormap2arr(arr,cmap):    
    # /2669779/kak-preobrazovat-izobrazhenie-tsvetovoi-karty-v-skalyarnye-znacheniya
    gradient=cmap(np.linspace(0.0,1.0,100))

    # Reshape arr to something like (240*240, 4), all the 4-tuples in a long list...
    arr2=arr.reshape((arr.shape[0]*arr.shape[1],arr.shape[2]))

    # Use vector quantization to shift the values in arr2 to the nearest point in
    # the code book (gradient).
    code,dist=scv.vq(arr2,gradient)

    # code is an array of length arr2 (240*240), holding the code book index for
    # each observation. (arr2 are the "observations".)
    # Scale the values so they are from 0 to 1.
    values=code.astype('float')/gradient.shape[0]

    # Reshape values back to (240,240)
    values=values.reshape(arr.shape[0],arr.shape[1])
    values=values[::-1]
    return values

arr=plt.imread('mri_demo.png')
values=colormap2arr(arr,cm.jet)    
# Proof that it works:
plt.imshow(values,interpolation='bilinear', cmap=cm.jet,
           origin='lower', extent=[-3,3,-3,3])
plt.show()

Изображение, которое вы видите, должно быть близко к воспроизведению mri_demo.png:

alt text

(Исходный файл mri_demo.png имел белую рамку. Так как белыйэто не цвет в cm.jet, обратите внимание, что scipy.cluster.vq.vq отображает белый цвет на ближайшую точку в кодовой книге gradient, которая бывает бледно-зеленого цвета.)

0 голосов
/ 06 октября 2014

LinearSegmentedColormap не дает мне такую ​​же интерполяцию, если я не делаю это вручную во время теста, поэтому я предпочитаю использовать свою собственную:

В качестве преимущества matplotlib больше не требуется, поскольку я интегрирую свой код в существующее программное обеспечение.

def codeBook(color_list, N=256):
    """
    return N colors interpolated from rgb color list
    !!! workaround to matplotlib colormap to avoid dependency !!!
    """
    # seperate r g b channel
    rgb = np.array(color_list).T
    # normalize data points sets
    new_x = np.linspace(0., 1., N)
    x = np.linspace(0., 1., len(color_list))
    # interpolate each color channel
    rgb = [np.interp(new_x, x, channel) for channel in rgb]
    # round elements of the array to the nearest integer.
    return np.rint(np.column_stack( rgb )).astype('int')
0 голосов
/ 12 мая 2014

Hy unutbu,

Спасибо за ваш ответ, я понимаю процесс, который вы объясняете, и воспроизводит его. Он работает очень хорошо, я использую его для реверса снимков ИК-камер в температурных сетках, поскольку изображение можно легко переделать / изменить, чтобы выполнить мою задачу с помощью GIMP.

Я могу создавать скалярные сетки из снимков с камеры, которые действительно полезны в моих задачах.

Я использую файл палитры, который я могу создать с помощью GIMP + Образец градиента по пути . Я выбираю цветную полосу моего исходного изображения, преобразую его в палитру, а затем экспортирую в шестнадцатеричную цветовую последовательность. Я прочитал этот файл палитры, чтобы создать цветовую карту, нормированную по образцу температуры, для использования в качестве кодовой книги. Я читаю исходное изображение и использую векторное квантование для преобразования цвета в значения. Я немного улучшаю стиль кода кода , используя индексы кодовых книг в качестве фильтра индекса в массиве образцов температуры, и применяю некоторые фильтры для сглаживания моих результатов.

from numpy import linspace, savetxt
from matplotlib.colors import Normalize, LinearSegmentedColormap
from  scipy.cluster.vq import vq

# sample the values to find from colorbar extremums
vmin = -20.
vmax = 120.
precision = 1.

resolution = 1 + vmax-vmin/precision
sample = linspace(vmin,vmax,resolution)

# create code_book from sample
cmap = LinearSegmentedColormap.from_list('Custom', hex_color_list)
norm = Normalize()
code_book = cmap(norm(sample))

# quantize colors
indices = vq(flat_image,code_book)[0]
# filter sample from quantization results **(improved)**
values = sample[indices]

savetxt(image_file_name[:-3]+'.csv',values ,delimiter=',',fmt='%-8.1f')

Результаты наконец экспортируются в .csv

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

Спасибо всем авторам unutbu, Rob A, scipy community;)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...