2012-05-03 50 views
8

Czy istnieje sposób na odczyt w pliku bmp w Pythonie, który nie wymaga użycia PIL? PIL nie działa z wersją 3, którą mam. Próbowałem użyć obiektu Image z graphics.py, Image (anchorPoint, filename), ale to zdaje się działać tylko z plikami GIF.Czytanie plików bmp w Pythonie

+0

[Ta strona] (http://www.lfd.uci.edu/~gohlke/pythonlibs/#pil) twierdzi, że ma wersje PIL zgodne z Python 3. –

Odpowiedz

0

Zależy od tego, co próbujesz osiągnąć i na jakiej platformie?

W każdym razie użycie biblioteki C do załadowania BMP może działać np. http://code.google.com/p/libbmp/ lub http://freeimage.sourceforge.net/, a biblioteki C można łatwo wywołać z Pythona np. przy użyciu ctypes lub owijając go jako moduł python.

czy można skompilować tę wersję PIL https://github.com/sloonz/pil-py3k

+0

Ctypes jest wykonalny, a ja go użyłem i utknąłem z nim, ale generuje on raczej kruche rozwiązania - bardziej niż samo C. To dlatego, że sprawdzanie typów może być lepsze dzięki ctypes. Dla bardzo stabilnego API, ctypes może być całkiem niezły (szczególnie, jeśli chcesz celować nie tylko w cpython, ale także w pypy), ale cyton może być lepszy dla wielu rzeczy, jeśli chcesz trzymać się cpythona. – user1277476

1

Wspólny port PIL do Python 3.x jest nazywany "Pillow". Proponuję także bibliotekę pygame dla prostych zadań. Jest to biblioteka, pełna funkcji do tworzenia gier - i wśród nich jest czytanie z popularnych formatów graficznych. Działa również z Pythonem 3.x.

10

W Pythonie można go po prostu odczytać jako:

import os 
from scipy import misc 
path = 'your_file_path' 
image= misc.imread(os.path.join(path,'image.bmp'), flatten= 0) 

## flatten=0 if image is required as it is 
## flatten=1 to flatten the color layers into a single gray-scale layer 
+0

Uwaga, w SciPy 1.0 [imread (etc.) jest amortyzowany i zostanie usunięty w wersji 1.2] (https://docs.scipy.org/doc/scipy/reference/generated/scipy.misc.imsave.html#scipy. misc.imread); SciPy 1.2 użyje 'imageio.imread' – uhoh

0

Zdaję sobie sprawę, że jest to stara sprawa, ale znalazłem go podczas rozwiązywania tego problemu się i pomyślałem, że to może pomóc komuś w przyszłości .

Dosyć łatwo jest odczytać plik BMP jako dane binarne. W zależności od tego, jak szerokie wsparcie i jak wiele przypadków narożnych trzeba wspierać oczywiście.

Poniżej znajduje się prosty analizator składniowy, który działa TYLKO dla 24-bitowych BMP 1920x1080 (jak te zapisane z MS Paint). Powinno być jednak łatwe do rozszerzenia. Pluje wartości piksela jako listę pytonów, taką jak (255, 0, 0, 255, 0, 0, ...), dla przykładu z czerwonym obrazem.

Jeśli potrzebujesz bardziej niezawodnego wsparcia, w odpowiedzi na to pytanie znajdziesz informacje, jak prawidłowo odczytać nagłówek: How to read bmp file header in python?. Korzystając z tych informacji, powinieneś być w stanie rozszerzyć prosty parser poniżej o dowolne potrzebne funkcje.

Istnieje również więcej informacji na temat formatu pliku BMP na stronie wikipedia https://en.wikipedia.org/wiki/BMP_file_format, jeśli jest to potrzebne.

def read_rows(path): 
    image_file = open(path, "rb") 
    # Blindly skip the BMP header. 
    image_file.seek(54) 

    # We need to read pixels in as rows to later swap the order 
    # since BMP stores pixels starting at the bottom left. 
    rows = [] 
    row = [] 
    pixel_index = 0 

    while True: 
     if pixel_index == 1920: 
      pixel_index = 0 
      rows.insert(0, row) 
      if len(row) != 1920 * 3: 
       raise Exception("Row length is not 1920*3 but " + str(len(row)) + "/3.0 = " + str(len(row)/3.0)) 
      row = [] 
     pixel_index += 1 

     r_string = image_file.read(1) 
     g_string = image_file.read(1) 
     b_string = image_file.read(1) 

     if len(r_string) == 0: 
      # This is expected to happen when we've read everything. 
      if len(rows) != 1080: 
       print "Warning!!! Read to the end of the file at the correct sub-pixel (red) but we've not read 1080 rows!" 
      break 

     if len(g_string) == 0: 
      print "Warning!!! Got 0 length string for green. Breaking." 
      break 

     if len(b_string) == 0: 
      print "Warning!!! Got 0 length string for blue. Breaking." 
      break 

     r = ord(r_string) 
     g = ord(g_string) 
     b = ord(b_string) 

     row.append(b) 
     row.append(g) 
     row.append(r) 

    image_file.close() 

    return rows 

def repack_sub_pixels(rows): 
    print "Repacking pixels..." 
    sub_pixels = [] 
    for row in rows: 
     for sub_pixel in row: 
      sub_pixels.append(sub_pixel) 

    diff = len(sub_pixels) - 1920 * 1080 * 3 
    print "Packed", len(sub_pixels), "sub-pixels." 
    if diff != 0: 
     print "Error! Number of sub-pixels packed does not match 1920*1080: (" + str(len(sub_pixels)) + " - 1920 * 1080 * 3 = " + str(diff) +")." 

    return sub_pixels 

rows = read_rows("my image.bmp") 

# This list is raw sub-pixel values. A red image is for example (255, 0, 0, 255, 0, 0, ...). 
sub_pixels = repack_sub_pixels(rows)