18

Tôi đang sử dụng Python Imaging Library để tô màu hình ảnh đen trắng với bảng tra cứu xác định mối quan hệ màu. Bảng tra cứu đơn giản là một danh sách 256 phần tử của các bộ RGB:Sử dụng phương pháp Image.point() trong PIL để thao tác dữ liệu pixel

>>> len(colors) 
256 
>>> colors[0] 
(255, 237, 237) 
>>> colors[127] 
(50, 196, 33) 
>>> 

phiên bản đầu tiên của tôi sử dụng các phương pháp getpixel()putpixel():

for x in range(w): 
     for y in range(h): 
      pix = img.getpixel((x,y)) 
      img.putpixel((x,y), colors[pix[0]]) 

Đây là khủng khiếp chậm. Báo cáo profile chỉ đến các phương pháp putpixelgetpixel là thủ phạm. Một điều tra nhỏ (ví dụ, đọc tài liệu) và tôi tìm thấy "Lưu ý rằng phương pháp này tương đối chậm." re: putpixel. (thực tế thời gian chạy: 53s trong putpixel và 50 getpixel cho một hình ảnh 1024x1024)

Dựa vào gợi ý trong các tài liệu, tôi đã sử dụng im.load() và truy cập pixel trực tiếp thay vì:

pixels = img.load() 
    for x in range(w): 
     for y in range(h): 
      pix = pixels[x, y] 
      pixels[x, y] = colors[pix[0]]     

chế biến tăng tốc bởi một thứ tự độ lớn, nhưng vẫn còn chậm: khoảng 3,5 để xử lý hình ảnh 1024x1024.

Một nghiên cứu thấu đáo hơn về các tài liệu PIL dường như chỉ ra Image.point()chính xác dành cho mục đích này:

im.point(table) => hình ảnh

im.point(function) => hình ảnh

Trả về một bản sao của hình ảnh nơi mỗi pixel được ánh xạ qua bảng đã cho. Bảng phải chứa 256 giá trị cho mỗi băng trong hình ảnh. Nếu một hàm được sử dụng thay vào đó, nó sẽ lấy một đối số duy nhất. Hàm này được gọi một lần cho mỗi giá trị pixel có thể và bảng kết quả được áp dụng cho tất cả các dải của hình ảnh.

Tôi đã dành một chút thời gian hack xung quanh với giao diện, nhưng dường như không thể làm đúng. Hãy tha thứ cho sự thiếu hiểu biết của tôi, nhưng tài liệu của PIL là curt và tôi không có nhiều kinh nghiệm xử lý hình ảnh. Tôi đã googled xung quanh một chút và bật lên một vài ví dụ, nhưng không có gì mà làm cho việc sử dụng "click" cho tôi. Do đó, cuối cùng, câu hỏi của tôi:

  • Image.point() công cụ phù hợp cho công việc này?
  • Định dạng/cấu trúc nào Image.point() mong đợi bảng?
  • Ai đó có thể thực hiện một ví dụ không? Mỗi lần lặp lại tôi đã cố gắng cho đến nay đã kết thúc với một hình ảnh đen thẳng.

Trả lời

15

Là Image.point() công cụ phù hợp cho công việc này?

Đúng vậy, Image.point() là hoàn hảo cho việc làm này

định dạng gì/cấu trúc không Image.point() mong đợi bảng?

Bạn nên flatten danh sách để thay vì [(12, 140, 10), (10, 100, 200), ...] sử dụng:

[12, 140, 10, 10, 100, 200, ...] 

Dưới đây là một ví dụ nhanh Tôi chỉ cố gắng:

im = im.point(range(256, 0, -1) * 3) 

alt text alt text

Và bởi nếu bạn cần kiểm soát nhiều màu hơn và bạn cảm thấy Image.point không dành cho bạn, bạn cũng có thể sử dụng Image.getdataImage.putdata để thay đổi màu sắc nhanh hơn cả số loadputpixel. Tuy nhiên nó chậm hơn Image.point.

Image.getdata cung cấp cho bạn danh sách tất cả các pixel, sửa đổi chúng và viết lại bằng Image.putdata. Nó là đơn giản. Nhưng hãy thử làm điều đó bằng cách sử dụng Image.point trước tiên.


EDIT

Tôi đã phạm sai lầm trong lời giải thích đầu tiên, tôi sẽ giải thích một cách chính xác bây giờ:

Bảng màu thực sự là như thế này

[0, 1, 2, 3, 4, 5, ...255, 0, 1, 2, 3, ....255, 0, 1, 2, 3, ...255] 

Mỗi ban nhạc phạm vi bên cạnh khác. Để thay đổi màu (0, 0, 0) đến (10, 100, 10) nó cần phải trở nên như thế này:

[10, 1, 2, 3, 4, 5, ...255, 100, 1, 2, 3, ....255, 10, 1, 2, 3, ...255] 

Để chuyển đổi danh sách màu sắc của bạn thành định dạng phù hợp thử điều này:

table = sum(zip(*colors),()) 

Tôi nghĩ ví dụ đầu tiên của tôi sẽ chứng minh formate cho bạn.

+0

flatten danh sách? ok, nhưng nó hoạt động như thế nào? Tôi muốn các pixel có giá trị 0 -> (12, 140, 10) và pixel có giá trị 255 -> (254, 237, 220). –

+4

bạn biết đấy, tôi nghĩ đây có thể là Địa điểm duy nhất trên Internet nơi định dạng được mong đợi của bảng đó được mô tả. // Tôi chỉ có img.point() làm việc với bảng tra cứu, nhờ vào mô tả của bạn. Kết quả không chính xác như những gì tôi mong đợi, nhưng tôi đã có đủ để hack xung quanh và tìm ra. Cám ơn rất nhiều! –

+0

@ J.J., Định dạng này không thực sự rõ ràng. Tôi đã làm sai trong lời giải thích đầu tiên của mình và tôi đã sửa nó ngay bây giờ. Tôi hy vọng tôi đã nhận nó đúng thời gian này. Tôi sẽ ngủ vì vậy tôi sẽ không thể trả lời câu hỏi. –

3

Tôi nghĩ rằng nó có thể là điển hình hơn để point trên cơ sở ban nhạc-by-band như vậy (dỡ bỏ trực tiếp từ PIL tutorial):

# split the image into individual bands 
source = im.split() 

R, G, B = 0, 1, 2 

# select regions where red is less than 100 
mask = source[R].point(lambda i: i < 100 and 255) 

# process the green band 
out = source[G].point(lambda i: i * 0.7) 

# paste the processed band back, but only where red was < 100 
source[G].paste(out, None, mask) 

# build a new multiband image 
im = Image.merge(im.mode, source) 
+0

định dạng bảng có ý nghĩa hơn với một ban nhạc duy nhất, đó là chắc chắn. Tôi có thể phải sử dụng tuyến đường này để xử lý kênh alpha với một trường hợp đặc biệt ... –

+0

cảm thấy trơn tru và nhanh chóng. – Conex

Các vấn đề liên quan