2010-09-15 6 views
9

Jak odwrócić kolor odwzorowany obraz?Jak odwrócić obraz mapy kolorów na wartości skalarne

Mam obraz 2D, który kreśli dane na mapie kolorów. Chciałbym odczytać obraz i odwrócić mapę kolorów, czyli wyszukać konkretną wartość RGB i zmienić ją w zmienną.

Na przykład: używając tego pliku: http://matplotlib.sourceforge.net/_images/mri_demo.png

powinienem być w stanie uzyskać 440x360 matrycę pływaków, znając colormap został cm.jet

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

Odpowiedz

8

Nie może być lepsze sposoby turystyczne to; Nie jestem pewny. Po przeczytaniu help(cm.jet) zobaczysz algorytm używany do odwzorowania wartości z przedziału [0,1] na 3-krotne RGB. Za pomocą małego papieru i ołówka można opracować formuły odwracające funkcje liniowo-liniowe, które definiują odwzorowanie.

Jednakże, istnieje wiele kwestii, które sprawiają, że rozwiązanie papier i ołówek nieco odpychające:

  1. To dużo żmudnej algebry i rozwiązanie jest specyficzny dla cm.jet. Gdy zmienisz mapę kolorów, musisz ponownie wykonać tę całą pracę . Jak zautomatyzować rozwiązywanie równań algebraicznych jest interesujące, ale nie jest to problem, który wiem, jak rozwiązać.

  2. Ogólnie rzecz biorąc, mapa kolorów może nie być odwracalna (więcej niż jedna wartość może być odwzorowana na ten sam kolor). W przypadku cm.jet , wartości między 0,11 i 0,125 są odwzorowane na przykład na 3-krotne (0,0,1) RGB . Jeśli więc Twój obraz zawiera czysty niebieski piksel , nie ma sposobu, aby powiedzieć, czy pochodzi on od wartości 0,11 lub wartości, powiedzmy, 0,125.

  3. Mapowanie od [0,1] do 3-krotne to krzywa w 3-spacji. Kolory na Twoim obrazie mogą nie leżeć idealnie na tej krzywej. Na przykład może być zaokrąglić błąd. Zatem każde praktyczne rozwiązanie musi być w stanie interpolować lub w jakiś sposób projektować punkty w 3-spacji na krzywej.

Z powodu problemu braku wyjątkowości oraz kwestii projekcji/interpolacji może istnieć wiele możliwych rozwiązań problemu. Poniżej jest tylko jedna możliwość.

Oto jeden ze sposobów rozwiązania wyjątkowości i projekcja/interpolacji zagadnienia:

Tworzenie gradient który działa jako „Kod książki”. gradient to tablica 4-krotnych RGBA na kolorowej mapie cm.jet. Kolory gradient odpowiadają wartościom od 0 do 1. Użyj funkcji kwantyzacji wektorowej scipy scipy.cluster.vq.vq, aby odwzorować wszystkie kolory na obrazku, mri_demo.png, na najbliższy kolor w gradient. Ponieważ mapa kolorów może używać tego samego koloru dla wielu wartości, gradient może zawierać zduplikowane kolory. Pozostawiam to do scipy.cluster.vq.vq, aby zdecydować, który (ewentualnie) nieunikalny indeks książki kodowej skojarzyć z określonym kolorem.

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

def colormap2arr(arr,cmap):  
    # http://stackoverflow.com/questions/3720840/how-to-reverse-color-map-image-to-scalar-values/3722674#3722674 
    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() 

Obraz widać powinna być zbliżona do odtwarzania mri_demo.png:

alt text

(Oryginalny mri_demo.png miał białą obwódkę Ponieważ biały kolor nie jest w cm.jet. należy pamiętać, że scipy.cluster.vq.vq mapy białego do do najbliższego punktu w książce kodów gradient, co dzieje się blady kolor zielony).

+0

Tak, to jest zasadniczo to, co uważałem za możliwe. Twoje początkowe rozwiązanie obejmowało odczytywanie linii z obrazu z tą samą mapą kolorów, co może być pomocne dla osób, które mówią, zeskanować postać i chcą wykonać własną analizę numeryczną. Utknąłem na kwantyzacji wektorowej - początkowo wydawało mi się, że najlepiej będzie przejść przez każdy możliwy kolor w lutym i obliczyć odległość 3D od faktycznej wartości piksela - której nie mogłem zobaczyć, jak zrobić szybko bez zapętlanie. Dzięki! – user448764

0

Hy unutbu,

Dziękuję za odpowiedź, rozumiem proces, który wyjaśniasz i powielasz. Działa bardzo dobrze, używam go do odwracania zdjęć z kamer IR w siatkach temperaturowych, ponieważ obraz może być łatwo przerobiony/przekształcony, aby spełnić mój cel za pomocą GIMP.

Jestem w stanie stworzyć siatki skalarne z ujęć kamery, które są naprawdę przydatne w moich zadaniach.

Używam pliku palety, który mogę utworzyć za pomocą GIMP + Sample a Gradient Along a Path. Wybieram pasek kolorów oryginalnego obrazu, zamieniam go na paletę, a następnie eksportuję jako sekwencję kolorów szesnastkowych. Przeczytałem ten plik palety, aby utworzyć mapę kolorów znormalizowaną przez próbkę temperatury, która będzie używana jako książka kodów. Przeczytałem oryginalny obraz i używam kwantyzacji wektorowej do odwrócenia kolorów na wartości. I nieznacznie polepsz styl pythonowy kodu, używając indeksów książki kodowej jako filtra indeksu w tablicy próbek temperatury i zastosuj niektóre filtry, aby wygładzić wyniki.

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') 

Wyniki wreszcie eksportowane csv

najważniejszą rzeczą jest stworzenie dobrze reprezentatywnej plik palety do uzyskania dobrej precyzji. Zaczynam uzyskiwać dobry gradient (książka kodowa) przy użyciu 12 kolorów i więcej. Ten proces jest przydatny, ponieważ czasami ujęcia kamery nie mogą być łatwo i liniowo przekształcane na skalę szarości.

Dzięki wszystkich płatników unutbu Rob A, scipy społeczność;)

0

LinearSegmentedColormap nie daje mi ten sam interpolacji jeśli nie to zrobić ręcznie podczas mojego testu, więc wolę używać mój własny:

Jako korzyść, matplotlib nie jest bardziej potrzebny, ponieważ integruję mój kod z istniejącym oprogramowaniem.

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')