2011-05-25 25 views
5

我正在繪製PGM圖像: enter image description here 以下是我正在使用的data在imshow中關閉一個錯誤?

問題是一些顯示的像素是錯誤的。例如:

  • 靠近圖像的頂部的三個灰色框是的值11(因此它們應該是紅色,而不是紅色)
  • 頂行中兩個黃色像素 - 它們是值8,所以他們應該是黃綠色,不是黃色

任何人都可以解釋這些差異,以及如何解決它們?

這裏是我的源:

from pylab import * 
import numpy  
LABELS = range(13) 
NUM_MODES = len(LABELS) 
def read_ascii_pgm(fname): 
    """ 
    Very fragile PGM reader. It's OK since this is only for reading files 
    output by my own app. 
    """ 
    lines = open(fname).read().strip().split('\n') 
    assert lines[0] == 'P2' 
    width, height = map(int, lines[1].split(' ')) 
    assert lines[2] == '13' 
    pgm = numpy.zeros((height, width), dtype=numpy.uint8) 
    for i in range(height): 
     cols = lines[3+i].split(' ') 
     for j in range(width): 
      pgm[i,j] = int(cols[j]) 
    return pgm 
def main(): 
    import sys 
    assert len(sys.argv) > 1 
    fname = sys.argv[1] 
    pgm = read_ascii_pgm(fname) 
    # EDIT: HACK! 
    pgm[0,0] = 12 
    cmap = cm.get_cmap('spectral', NUM_MODES) 
    imshow(pgm, cmap=cmap, interpolation='nearest') 
    edit = True 
    if edit: 
     cb = colorbar() 
    else: 
     ticks = [ (i*11./NUM_MODES + 6./NUM_MODES) for i in range(NUM_MODES) ] 
     cb = colorbar(ticks=ticks) 
     cb.ax.set_yticklabels(map(str, LABELS)) 
    savefig('imshow.png') 
if __name__ == '__main__': 
    main() 

編輯

我現在看到這裏發生了什麼。基本上,imshow似乎是這樣:

  • 確定所述動態範圍(如[ min(image), max(image) ]
  • 表示的在彩色圖中指定的顏色(13色)

我想什麼此使用數字它做的是:

  • 使用我創建色彩映射時指定的動態範圍(13)
  • 表示此使用13種顏色的彩色映射

我可以通過強制的圖像的動態範圍驗證這是13(見線標記HACK)。有一個更好的方法嗎?

這裏有一個更新的圖像: enter image description here

+1

+1 - 這似乎是一個問題,很多人可能會遇到,讓「幾乎正確「的結果。會討厭這個__以後出版。 – samplebias 2011-05-25 17:37:56

回答

5

的解決方案是設置im.set_clim(vmin, vmax)。基本上,圖像中的值被翻譯成覆蓋整個顏色範圍。例如,如果3是您數據中的最大值,則會分配最大顏色值。

取而代之,您需要告訴它max_nodes是最高值(您的情況爲13),即使它沒有出現在數據中,例如, im.set_clim(0, 13)

我改變你的代碼略有不同值的其他數據文件,爲工作num_modes

import numpy 
from pylab import * 

def read_ascii_pgm(fname): 
    lines = open(fname).read().strip().split('\n') 
    assert lines[0] == 'P2' 
    width, height = map(int, lines[1].split(' ')) 
    num_modes = int(lines[2]) 
    pgm = numpy.zeros((height, width), dtype=numpy.uint8) 
    for i in range(height): 
     cols = lines[3+i].split(' ') 
     for j in range(width): 
      pgm[i,j] = int(cols[j]) 
    return pgm, num_modes + 1 

if __name__ == '__main__': 
    import sys 
    assert len(sys.argv) > 1 
    fname = sys.argv[1] 
    pgm, num_modes = read_ascii_pgm(fname) 
    labels = range(num_modes) 
    cmap = cm.get_cmap('spectral', num_modes) 
    im = imshow(pgm, cmap=cmap, interpolation='nearest') 
    im.set_clim(0, num_modes) 
    ticks = [(i + 0.5) for i in range(num_modes)] 
    cb = colorbar(ticks=ticks) 
    cb.ax.set_yticklabels(map(str, labels)) 
    savefig('imshow_new.png') 

一些簡單的測試數據來說明。請注意,num_modes的值爲10,但沒有數據點達到該級別。這提供瞭如何值索引顏色表1:1:

P2 
5 3 
10 
0 1 0 2 0 
3 0 2 0 1 
0 1 0 2 0 

輸出:

enter image description here

+0

是的,在我回到這裏看到你的答案之前,我發現了這個問題。實際上,我將min和max作爲參數傳遞給'imshow',但它本質上是一樣的。感謝易於理解的文章! – misha 2011-05-25 17:41:23

3

有沒有差異,你只是手動設置蜱與不是他們真正的價值被標記。

注意到你的LABELS只是range(13),在你真正的蜱位置(ticks)不從0到12

所以,你手動標註上打勾,其中有10.6的位置,如同12!

嘗試取出線cb.ax.set_yticklabels(map(str, LABELS)),你會明白我的意思(另外,matplotlib會自動將它們轉換爲字符串,沒有理由調用map(str, LABELS))。

也許不是使用一組靜態數字作爲標籤,而應該將實際的刻度位置轉換爲標籤?像[round(tick) for tick in ticks]

編輯:對不起,這聽起來似乎超過了我的意圖......我不是這個意思!:)

EDIT2: 響應於該更新的問題,是的,imshow自動從輸入的最小值和最大值確定的範圍內。 (我很困惑......它還會做什麼?)

如果你想要一個沒有插值的直接顏色映射,那麼使用一個離散的顏色映射,而不是LinearSegmentedColormap。但是,最簡單的方法是在matplotlib的LinearSegmentedColormaps(這是matplotlib.cm.spectral是什麼)之一上手工設置限制。

如果要手動設置所用顏色映射的範圍,請在imshow返回的coloraxis對象上調用set_clim([0,12])

E.g.

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

with open('temp.pgm') as infile: 
    header, nrows, ncols = [infile.readline().strip() for _ in range(3)] 
    data = np.loadtxt(infile).astype(np.uint8) 

cmap = mpl.cm.get_cmap('spectral', 13) 
cax = plt.imshow(data, cmap, interpolation='nearest') 
cax.set_clim([0,13]) 
cbar = plt.colorbar(cax, ticks=np.arange(0.5, 13, 1.0)) 
cbar.ax.set_yticklabels(range(13)) 
plt.show() 

enter image description here

+0

感謝您的回答。首先,我不同意你的看法。我認爲**有**差異。顏色條有13種顏色,其中灰色是最高值的顏色,深紅色是第二高的,紅色是第三種,等等。圖像最多有13個強度(如我在創建彩色圖時指定的),其中12個是最高的價值。我錯誤地認爲12應該表示爲灰色,11表示爲暗紅色? – misha 2011-05-25 17:10:16

+0

不要擔心聽起來不可思議。你只是給了我一個關於問題究竟是什麼的想法。請看我更新的問題。謝謝! – misha 2011-05-25 17:24:26

+1

Woops,沒有注意到@ samplebias的答案,它說的和我的完全一樣。我花了很長時間編輯! :)儘管如此,我會留下答案。 – 2011-05-25 17:58:04