Làm việc với TIFF (nhập, xuất) bằng Python bằng numpy


84

Tôi cần một phương thức python để mở và nhập hình ảnh TIFF vào các mảng numpy để tôi có thể phân tích và sửa đổi dữ liệu pixel, sau đó lưu lại chúng dưới dạng TIFF. (Về cơ bản chúng là bản đồ cường độ ánh sáng ở thang độ xám, đại diện cho các giá trị tương ứng trên mỗi pixel)

Tôi không thể tìm thấy bất kỳ tài liệu nào về các phương pháp PIL liên quan đến TIFF. Tôi đã cố gắng tìm ra nó, nhưng chỉ gặp lỗi "chế độ kém" hoặc "loại tệp không được hỗ trợ".

Tôi cần dùng gì ở đây?

Câu trả lời:


103

Đầu tiên, tôi tải xuống hình ảnh TIFF thử nghiệm từ trang này có tên a_image.tif. Sau đó, tôi đã mở bằng PIL như thế này:

>>> from PIL import Image
>>> im = Image.open('a_image.tif')
>>> im.show()

Điều này cho thấy hình ảnh cầu vồng. Để chuyển đổi thành một mảng numpy, nó đơn giản như sau:

>>> import numpy
>>> imarray = numpy.array(im)

Chúng ta có thể thấy rằng kích thước của hình ảnh và hình dạng của mảng khớp với nhau:

>>> imarray.shape
(44, 330)
>>> im.size
(330, 44)

Và mảng chứa uint8các giá trị:

>>> imarray
array([[  0,   1,   2, ..., 244, 245, 246],
       [  0,   1,   2, ..., 244, 245, 246],
       [  0,   1,   2, ..., 244, 245, 246],
       ..., 
       [  0,   1,   2, ..., 244, 245, 246],
       [  0,   1,   2, ..., 244, 245, 246],
       [  0,   1,   2, ..., 244, 245, 246]], dtype=uint8)

Sau khi sửa đổi xong mảng, bạn có thể biến nó trở lại thành hình ảnh PIL như sau:

>>> Image.fromarray(imarray)
<Image.Image image mode=L size=330x44 at 0x2786518>

4
tôi đang gặp sự cố với các loại dữ liệu. hoạt động tốt đối với một số, vì tôi có số numpy.int16 trong mảng của mình, nhưng đối với numpy.uint16 image.fromarray cho kết quả: "TypeError: Không thể xử lý kiểu dữ liệu này"
Jakob

4
Nhìn vào nguồn của fromarray, có vẻ như nó không xử lý các mảng 16 bit không dấu.
jterrace

@Jakob kể từ tháng 6 năm 2020, PIL không hỗ trợ hình ảnh màu với nhiều hơn 8 bit mỗi màu , bạn sẽ phải sử dụng một thư viện khác (hoặc tự đóng góp chức năng).
Boris

56

Tôi sử dụng matplotlib để đọc các tệp TIFF:

import matplotlib.pyplot as plt
I = plt.imread(tiff_file)

Isẽ thuộc loại ndarray.

Theo tài liệu, mặc dù nó thực sự là PIL hoạt động đằng sau hậu trường khi xử lý TIFF vì matplotlib chỉ đọc PNG nguyên bản, nhưng điều này đã hoạt động tốt đối với tôi.

Ngoài ra còn có một plt.imsavechức năng để tiết kiệm.


Đây là cách dễ dàng nhất để làm việc với TIFF! Đã thử hàng tá cách và tất cả đều là vé. Ủng hộ cho chắc chắn!
zachd1_618

làm thế nào về phần xem?
Monica Heddneck

5
Có vẻ như matplotlib đã thay đổi chiến lược:ValueError: Only know how to handle extensions: ['png']; with Pillow installed matplotlib can handle more images
strpeter

17

Bạn cũng có thể sử dụng GDAL để thực hiện việc này. Tôi nhận ra rằng nó là một bộ công cụ không gian địa lý, nhưng không có gì yêu cầu bạn phải có một sản phẩm bản đồ.

Liên kết đến mã nhị phân GDAL được biên dịch trước dành cho windows (giả sử là windows ở đây) http://www.gisinternals.com/sdk/

Để truy cập mảng:

from osgeo import gdal

dataset = gdal.Open("path/to/dataset.tiff", gdal.GA_ReadOnly)
for x in range(1, dataset.RasterCount + 1):
    band = dataset.GetRasterBand(x)
    array = band.ReadAsArray()

mã trên là TIF đơn hay TIF nhiều trang? Tôi muốn sử dụng gdal để tải các ngăn xếp tiff 16 bit vào nparrays.
user391339

Điều này sẽ đọc ở kiểu dữ liệu đầu vào hoặc di chuyển mọi thứ sang float64 của numpy. Bạn có thể thêm một .astype(sometype)cuộc gọi vào cuối ReadAsArray()cuộc gọi để truyền. Không chắc chắn nếu điều này tạo ra một bản sao (chỉ cần chưa kiểm tra).
Jzl5325,

@Chikinn Từ đánh giá: stackoverflow.com/review/suggested-edits/17962780 xrange không có lỗi đánh máy, xrangelà phiên bản python 2 của range. Tôi đã chấp nhận chỉnh sửa này vì python 3 vẫn đang được cải thiện tích cực trong khi python 2 thì không.
abccd

12

pylibtiff làm việc tốt hơn cho tôi so với PIL, tính đến tháng 6 năm 2020 không hỗ trợ hình ảnh màu với hơn 8 bit mỗi màu .

from libtiff import TIFF

tif = TIFF.open('filename.tif') # open tiff file in read mode
# read an image in the currect TIFF directory as a numpy array
image = tif.read_image()

# read all images in a TIFF file:
for image in tif.iter_images(): 
    pass

tif = TIFF.open('filename.tif', mode='w')
tif.write_image(image)

Bạn có thể cài đặt pylibtiff với

pip3 install numpy libtiff

Readme của pylibtiff cũng đề cập đến tifffile, nhưng tôi chưa thử nó và mặc dù nó có vẻ là mã nguồn mở, tôi không nghĩ rằng mã có sẵn ở bất kỳ đâu nữa (ngoài việc giải nén thủ công từ gói PyPI).


2
Điều này là rất tốt. Bởi bây giờ, tifffile được bao gồm trong SciKit skimage.external.tifffile nhưng nó cũng có thể được nhập khẩu như là một module nếu bạn tải tifffile.py từ ông Christoph Gohlke
lesolorzanov

7

Bạn cũng có thể sử dụng pytiff mà tôi là tác giả.

    import pytiff

    with pytiff.Tiff("filename.tif") as handle:
        part = handle[100:200, 200:400]

    # multipage tif
    with pytiff.Tiff("multipage.tif") as handle:
        for page in handle:
            part = page[100:200, 200:400]

Đây là một mô-đun khá nhỏ và có thể không có nhiều tính năng như các mô-đun khác, nhưng nó hỗ trợ gạch lát và bigtiff, vì vậy bạn có thể đọc các phần của hình ảnh lớn.


Tính năng này chính xác là những gì tôi cần! (Có thể đọc một đoạn nhỏ của tệp lớn). Tuy nhiên khi tôi cố gắng pip cài đặt nó tôi nhận được một lỗi gcc
Fractaly

Nếu bạn tạo một vấn đề với các thông báo lỗi, tôi sẽ xem liệu tôi có thể tìm ra các vấn đề.
hnfl

Vâng, tôi cũng quan tâm nhưng cũng gặp lỗi khi tôi cố gắng cài đặt nó. Tôi đã làm như vậy bằng cách sử dụng pip - trong Windows và Ubuntu. Thật không may là nó không hoạt động! Tôi đã tạo ra sự cố ở đây: github.com/FZJ-INM1-BDA/pytiff/issues/15
Dobedani

6

Trong trường hợp ngăn xếp hình ảnh, tôi thấy nó dễ sử dụng hơn scikit-imageđể đọc và matplotlibhiển thị hoặc lưu. Tôi đã xử lý ngăn xếp hình ảnh TIFF 16-bit với mã sau.

from skimage import io
import matplotlib.pyplot as plt

# read the image stack
img = io.imread('a_image.tif')
# show the image
plt.imshow(mol,cmap='gray')
plt.axis('off')
# save the image
plt.savefig('output.tif', transparent=True, dpi=300, bbox_inches="tight", pad_inches=0.0)

0

Tôi khuyên bạn nên sử dụng các liên kết python với OpenImageIO, đây là tiêu chuẩn để xử lý các định dạng hình ảnh khác nhau trong thế giới vfx. Tôi đã thấy nó đáng tin cậy hơn trong việc đọc các kiểu nén khác nhau so với PIL.

import OpenImageIO as oiio
input = oiio.ImageInput.open ("/path/to/image.tif")

Không thể cài đặt Borderline trên Windows trừ khi bạn đã có trình biên dịch.
Jimmy Carter
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.