¿Cómo leo datos de imágenes de una URL en Python?

182

Lo que intento hacer es bastante simple cuando tratamos con un archivo local, pero el problema surge cuando trato de hacer esto con una URL remota.

Básicamente, estoy tratando de crear un objeto de imagen PIL a partir de un archivo extraído de una URL. Claro, siempre podría buscar la URL y almacenarla en un archivo temporal, luego abrirla en un objeto de imagen, pero eso se siente muy ineficiente.

Esto es lo que tengo:

Image.open(urlopen(url))

Se queja de que seek()no está disponible, así que probé esto:

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

Pero eso tampoco funcionó. ¿Hay una mejor manera de hacer esto, o escribir en un archivo temporal es la forma aceptada de hacer este tipo de cosas?

Daniel Quinn
fuente

Respuestas:

282

En Python3, los módulos StringIO y cStringIO se han ido.

En Python3 deberías usar:

from PIL import Image
import requests
from io import BytesIO

response = requests.get(url)
img = Image.open(BytesIO(response.content))
Andres Kull
fuente
¿Cómo recuperar la imagen de response.content?
Amresh Giri
requestsel paquete arroja el código de estado 503 mientras recupera una imagen de una URL. En cambio, tuve que recurrir a http.clientpara obtener la imagen.
Manishankar Singh
Cuando intento esto obtengo: AttributeError: el módulo 'request' no tiene el atributo 'get'.
apiljic
2
Envolver manualmente en BytesIO ya no es necesario ya que PIL> = 2.8.0. Solo úsalo Image.open(response.raw). PIL comprueba automáticamente eso ahora y hace el BytesIO envolviendo debajo del capó. De: pillow.readthedocs.io/en/3.0.x/releasenotes/2.8.0.html
Vinícius M
GRACIAS YOUUUUUUUUUUUU, OP.
Sharl Sherif
166

podrías intentar usar un StringIO

import urllib, cStringIO

file = cStringIO.StringIO(urllib.urlopen(URL).read())
img = Image.open(file)
Fábio Diniz
fuente
Gracias, me gustaría agregar que el mismo código exacto funcionará con urllib2 (con Python2)
suavemente el
17
en python 3 sería de urllib.request import urlopen y io.io.BytesIO en lugar de StringIO
matyas
2
HELP, IOError: no se puede identificar el archivo de imagen <_io.BytesIO object en 0x7fb91b6a29b0> mi url es: ... model = product.template & id = 16 & field = image_medium
С. Дэлгэрцэцэг
56

Yo uso la biblioteca de solicitudes. Parece ser más robusto.

from PIL import Image
import requests
from StringIO import StringIO

response = requests.get(url)
img = Image.open(StringIO(response.content))
Saurav
fuente
3
Por alguna razón, urllib no funcionó para algunas URL, pero las solicitudes funcionaron donde eso falló
mirri66
No pude encontrar el paquete PIL, pero parece que la almohada se ha hecho cargo del esfuerzo PIL y puede instalarlo con python3 pip3.4 install pillow.
disruptivo
3
Tenga en cuenta que las solicitudes cargarán toda la respuesta en la memoria, y luego PIL cargará todo nuevamente como una imagen, por lo que tiene dos copias completas residentes en la memoria. La respuesta anterior con el método urllib transmite los datos, por lo que solo termina con una copia más el tamaño del búfer de transmisión. También puede transmitir los datos con solicitudes, pero debido a que la respuesta no admite la semántica read (), tendría que construir un adaptador.
sirdodger
@sirdodger ¿Te refieres a urllib2 o urllib?
CMCDragonkai
@CMCDragonkai Me refería a la respuesta aceptada urllib. Si la sobrecarga de memoria es una preocupación, es mejor que usar esta respuesta de solicitudes. (Sin embargo, como mencioné, una solución diferente usando solicitudes podría lograr el mismo efecto.)
sirdodger
27

Use StringIOpara convertir la cadena de lectura en un objeto similar a un archivo:

from StringIO import StringIO
import urllib

Image.open(StringIO(urllib.requests.urlopen(url).read()))
Dan D.
fuente
21

Para aquellos que realizan un procesamiento posterior de sklearn / numpy (es decir, aprendizaje profundo), puede envolver el objeto PIL con np.array (). Esto podría evitar que tenga que buscarlo en Google como lo hice yo:

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
fuente
19

Python 3

from urllib.request import urlopen
from PIL import Image

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

Jupyter Notebook e IPython

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

¡A diferencia de otros métodos, este método también funciona en un bucle for!

Milagrosos
fuente
12

La forma recomendada de hacer entrada / salida de imágenes en estos días es usar el paquete dedicado ImageIO . Los datos de imagen se pueden leer directamente desde una URL con una línea de código simple:

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

Muchas respuestas en esta página son anteriores al lanzamiento de ese paquete y, por lo tanto, no lo mencionan. ImageIO comenzó como componente del kit de herramientas Scikit-Image . Es compatible con varios formatos científicos además de los proporcionados por la popular biblioteca de procesamiento de imágenes PILlow . Lo envuelve todo en una API limpia centrada únicamente en la entrada / salida de imágenes. De hecho, SciPy eliminó su propio lector / escritor de imágenes a favor de ImageIO .

luego
fuente
3

seleccione la imagen en cromo, haga clic derecho sobre ella, haga clic en Copy image address, péguela en una strvariable ( my_url) para leer la imagen:

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

abrelo;

from PIL import Image

img = Image.open('my_image.png')
img.show()
Shivid
fuente