Jak odczytać dane obrazu z adresu URL w Pythonie?

182

To, co próbuję zrobić, jest dość proste, gdy mamy do czynienia z plikiem lokalnym, ale problem pojawia się, gdy próbuję to zrobić za pomocą zdalnego adresu URL.

Zasadniczo próbuję utworzyć obiekt obrazu PIL z pliku pobranego z adresu URL. Jasne, zawsze mogę pobrać adres URL i zapisać go w pliku tymczasowym, a następnie otworzyć go w obiekcie obrazu, ale wydaje się to bardzo nieefektywne.

Oto co mam:

Image.open(urlopen(url))

Płatki narzekają, że seek()nie są dostępne, więc spróbowałem:

Image.open(urlopen(url).read())

Ale to też nie działało. Czy istnieje lepszy sposób, aby to zrobić, czy też zapisywanie w pliku tymczasowym jest akceptowanym sposobem wykonywania tego rodzaju czynności?

Daniel Quinn
źródło

Odpowiedzi:

281

W Python3 nie ma modułów StringIO i cStringIO.

W Python3 powinieneś użyć:

from PIL import Image
import requests
from io import BytesIO

response = requests.get(url)
img = Image.open(BytesIO(response.content))
Andres Kull
źródło
Jak odzyskać obraz z response.content?
Amresh Giri
requestspakiet zgłasza kod stanu 503 podczas pobierania obrazu z adresu URL. Zamiast tego musiałem http.clientskorzystać z obrazu.
Manishankar Singh,
Gdy próbuję, otrzymuję: AttributeError: moduł „żądania” nie ma atrybutu „get”.
apiljic
2
Ręczne owijanie w BytesIO nie jest już potrzebne, ponieważ PIL> = 2.8.0. Po prostu użyj Image.open(response.raw). PIL automatycznie sprawdza to teraz i wykonuje zawijanie BytesIO pod maską. Od: pillow.readthedocs.io/en/3.0.x/releasenotes/2.8.0.html
Vinícius M
DZIĘKUJEMY ZA OPU.
Sharl Sherif
166

możesz spróbować użyć StringIO

import urllib, cStringIO

file = cStringIO.StringIO(urllib.urlopen(URL).read())
img = Image.open(file)
Fábio Diniz
źródło
Dzięki, chciałbym tylko dodać, że ten sam dokładny kod będzie działał z urllib2 (z Python2)
delikatnie
17
w pythonie 3 byłoby to z urllib.request import urlopen i io.io.BytesIO zamiast StringIO
matyas
2
POMOC, IOError: nie można zidentyfikować pliku obrazu <_io.BytesIO obiekt pod 0x7fb91b6a29b0> mój adres URL to: ... model = product.template & id = 16 & field = image_medium
С. Дэлгэрцэцэг
56

Korzystam z biblioteki żądań. Wydaje się być bardziej solidny.

from PIL import Image
import requests
from StringIO import StringIO

response = requests.get(url)
img = Image.open(StringIO(response.content))
Sauraw
źródło
3
Z jakiegoś powodu urllib nie działał dla niektórych adresów URL, ale żądania działały tam, gdzie się nie
udawało
Nie mogłem znaleźć pakietu PIL, ale wygląda na to, że poduszka przejęła wysiłek PIL i można go zainstalować dla python3 pip3.4 install pillow.
destrukcyjny
3
Zauważ, że żądania załadują całą odpowiedź do pamięci, a następnie PIL ponownie załaduje całą rzecz jako obraz, więc masz w pamięci dwie pełne kopie. Poprzednia odpowiedź przy użyciu metody urllib przesyła strumieniowo dane, więc otrzymujesz tylko jedną kopię plus rozmiar bufora przesyłania strumieniowego. Możesz również przesyłać strumieniowo dane z żądaniami, ale ponieważ odpowiedź nie obsługuje semantyki read (), musisz zbudować adapter.
sirdodger
@sirdodger Czy masz na myśli urllib2 lub urllib?
CMCDragonkai
@CMCDragonkai Miałem na myśli zaakceptowaną odpowiedź na urllib. Jeśli narzut pamięci stanowi problem, jest lepszy niż użycie tej odpowiedzi na żądanie. (Jednak, jak wspomniałem, inne rozwiązanie wykorzystujące żądania może osiągnąć ten sam efekt.)
sirdodger
27

Użyj, StringIOaby zmienić ciąg odczytywany w obiekt podobny do pliku:

from StringIO import StringIO
import urllib

Image.open(StringIO(urllib.requests.urlopen(url).read()))
Dan D.
źródło
21

Dla tych, którzy wykonują niektóre przetwarzanie końcowe sklearn / numpy (tj. Głębokie uczenie), możesz owinąć obiekt PIL przy pomocy np.array (). Może to uratować Cię przed koniecznością korzystania z Google, tak jak ja:

from PIL import Image
import requests
import numpy as np
from StringIO import StringIO

response = requests.get(url)
img = np.array(Image.open(StringIO(response.content)))
Ben
źródło
19

Python 3

from urllib.request import urlopen
from PIL import Image

img = Image.open(urlopen(url))
img

Jupyter Notebook i IPython

import IPython
url = 'https://newevolutiondesigns.com/images/freebies/colorful-background-14.jpg'
IPython.display.Image(url, width = 250)

W przeciwieństwie do innych metod, ta metoda działa również w pętli for!

Milady
źródło
12

Prawdopodobnie obecnie zalecanym sposobem wprowadzania / wysyłania obrazów jest użycie dedykowanego pakietu ImageIO . Dane obrazu można odczytać bezpośrednio z adresu URL za pomocą jednego prostego wiersza kodu:

from imageio import imread
image = imread('https://cdn.sstatic.net/Sites/stackoverflow/img/logo.png')

Wiele odpowiedzi na tej stronie poprzedza wydanie tego pakietu i dlatego nie wspominają o nim. ImageIO zaczynał jako składnik zestawu narzędzi Scikit-Image . Obsługuje wiele formatów naukowych oprócz tych udostępnianych przez popularną bibliotekę przetwarzania obrazu PILlow . Zawija to wszystko w czysty interfejs API skoncentrowany wyłącznie na wejściach / wyjściach obrazu. W rzeczywistości SciPy usunął własny program do odczytu / zapisu obrazów na rzecz ImageIO .

zaraz
źródło
3

wybierz obraz w chromie, kliknij go prawym przyciskiem myszy, kliknij Copy image address, wklej do strzmiennej ( my_url), aby odczytać obraz:

import shutil
import requests

my_url = 'https://www.washingtonian.com/wp-content/uploads/2017/06/6-30-17-goat-yoga-congressional-cemetery-1-994x559.jpg'
response = requests.get(my_url, stream=True)
with open('my_image.png', 'wb') as file:
    shutil.copyfileobj(response.raw, file)
del response

Otwórz to;

from PIL import Image

img = Image.open('my_image.png')
img.show()
Shivid
źródło