【问题标题】:How do I read image data from a URL in Python?如何从 Python 中的 URL 读取图像数据?
【发布时间】:2011-11-15 13:22:07
【问题描述】:

当我们处理本地文件时,我尝试做的事情相当简单,但是当我尝试使用远程 URL 执行此操作时,问题就出现了。

基本上,我正在尝试从从 URL 中提取的文件创建 PIL 图像对象。当然,我总是可以只获取 URL 并将其存储在一个临时文件中,然后将其打开到一个图像对象中,但这感觉非常低效。

这是我所拥有的:

Image.open(urlopen(url))

它抱怨seek() 不可用,所以我尝试了这个:

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

但这也没有用。有没有更好的方法来做到这一点,或者写入临时文件是接受这种事情的方式?

【问题讨论】:

标签: python python-imaging-library


【解决方案1】:

在 Python3 中,StringIO 和 cStringIO 模块消失了。

在 Python3 中你应该使用:

from PIL import Image
import requests
from io import BytesIO

response = requests.get(url)
img = Image.open(BytesIO(response.content))

【讨论】:

  • 如何从 response.content 中取回图片?
  • requests 包在从 URL 获取图像时抛出 503 状态代码。相反,我不得不求助于http.client 来获取图像。
  • 当我尝试这个时,我得到:AttributeError: module 'requests' has no attribute 'get'。
  • 自 PIL >= 2.8.0 以来不再需要手动包装 BytesIO。只需使用Image.open(response.raw)。 PIL 现在会自动检查它并在引擎盖下进行 BytesIO 包装。来自:pillow.readthedocs.io/en/3.0.x/releasenotes/2.8.0.html
  • @ViníciusM 你的答案应该在顶部!谢谢
【解决方案2】:

使用StringIO

import urllib, cStringIO

file = cStringIO.StringIO(urllib.urlopen(URL).read())
img = Image.open(file)

【讨论】:

  • 谢谢,只是想补充一点,同样的代码也适用于 urllib2(使用 Python2)
  • 在 python 3 中它将来自 urllib.request 导入 urlopen 和 io.io.BytesIO 而不是 StringIO
  • HELP, IOError: cannot identify image file <_io.bytesio object at> my url is: ...model=product.template&id=16&field=image_medium
【解决方案3】:

以下适用于 Python 3:

from PIL import Image
import requests

im = Image.open(requests.get(url, stream=True).raw)

参考资料:

【讨论】:

  • urllib2 我认为是用于 Python2 的,它已经过时了。对于 Python 3,它是 urllib.requests:urllib.request.urlopen(url).read()
  • 正如@wordsforthewise 提到的,urllib 已过时。我使用了第二个选项,因为我在我的代码中使用了“请求”并且它有效,所以赞成。解决方案的 urllib 部分是否应该被删除,这样读者就不会花时间尝试第一种方法,只是为了意识到它不起作用,然后转到下一种?
【解决方案4】:

使用requests:

from PIL import Image
import requests
from StringIO import StringIO

response = requests.get(url)
img = Image.open(StringIO(response.content))

【讨论】:

  • 由于某些原因 urllib 不适用于某些 URL,但请求在失败的地方有效
  • 我找不到 PIL 包,但看起来枕头已经接管了 PIL 工作,您可以使用 pip3.4 install pillow 为 python3 安装。
  • 请注意,requests 会将整个响应加载到内存中,然后 PIL 会再次将整个响应加载为图像,因此您有两个完整的副本驻留在内存中。上一个使用 urllib 方法流式传输数据的答案,因此您最终只会得到一个副本加上流式传输缓冲区大小。您也可以使用请求流式传输数据,但由于响应不支持 read() 语义,您必须构建一个适配器。
  • @sirdodger 你指的是 urllib2 还是 urllib?
  • @CMCDragonkai 我指的是接受的 urllib 答案。如果内存开销是一个问题,它比使用这个请求答案更好。 (但是,就像我提到的,使用请求的不同解决方案可以达到相同的效果。)
【解决方案5】:

Python 3

from urllib.request import urlopen
from PIL import Image

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

Jupyter Notebook 和 IPython

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

与其他方法不同,此方法也适用于 for 循环!

【讨论】:

    【解决方案6】:

    使用StringIO将读取的字符串转成文件类对象:

    from StringIO import StringIO
    import urllib
    
    Image.open(StringIO(urllib.requests.urlopen(url).read()))
    

    【讨论】:

      【解决方案7】:

      对于那些进行 sklearn/numpy 后处理(即深度学习)的人,您可以使用 np.array() 包装 PIL 对象。这可能会让您不必像我一样使用 Google 搜索:

      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)))
      

      【讨论】:

        【解决方案8】:

        目前可以说推荐的图像输入/输出方法是使用专用包ImageIO。只需一行简单的代码,就可以直接从 URL 读取图像数据:

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

        此页面上的许多答案早于该软件包的发布,因此不提。 ImageIO 最初是 Scikit-Image 工具包的组件。除了流行的图像处理库PILlow 提供的格式之外,它还支持许多科学格式。它将所有内容封装在一个只专注于图像输入/输出的干净 API 中。事实上,SciPy removed 有自己的图像读取器/写入器 in favor of ImageIO

        【讨论】:

        • 非常慢。如果你想在一行中做 skimage 方法会是更好的选择
        • skimage (Scikit-Image) 方法,正如答案所解释的那样。它和你的互联网连接一样慢。
        【解决方案9】:

        选择chrome中的图片,右键点击Copy image address,粘贴到str变量中(my_url)读取图片:

        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
        

        打开它;

        from PIL import Image
        
        img = Image.open('my_image.png')
        img.show()
        

        【讨论】:

          【解决方案10】:

          由于 PIL >= 2.8.0,不再需要手动包装 BytesIO。只需使用 Image.open(response.raw)

          在 Vinícius 的评论之上添加:

          您应该传递stream=True,如https://requests.readthedocs.io/en/master/user/quickstart/#raw-response-content所述

          所以

          img = Image.open(requests.get(url, stream=True).raw)
          

          【讨论】:

            【解决方案11】:

            不使用 PIL 直接将图像作为 numpy 数组获取

            import requests, io
            import matplotlib.pyplot as plt 
            
            response = requests.get(url).content
            img = plt.imread(io.BytesIO(response), format='JPG')
            plt.imshow(img)
            

            【讨论】:

              【解决方案12】:

              使用 urllib.request.urlretrieve() 和 PIL.Image.open() 下载和读取图像数据:

              导入请求

              导入 urllib.request

              import PIL
              urllib.request.urlretrieve("https://i.imgur.com/ExdKOOz.png", "sample.png")
              img = PIL.Image.open("sample.png")
              img.show()
              

              或调用 requests.get(url) ,将 url 作为目标文件的地址,通过 GET 请求下载。以 obj 作为响应内容调用 io.BytesIO(obj) 以将原始数据加载为字节对象。要加载图像数据,请调用 PIL.Image.open(bytes_obj) 并将 bytes_obj 作为字节对象:

              import io
              response = requests.get("https://i.imgur.com/ExdKOOz.png")
              image_bytes = io.BytesIO(response.content)
              img = PIL.Image.open(image_bytes)
              img.show()
              

              【讨论】:

                【解决方案13】:
                from PIL import Image
                import cv2
                import numpy as np
                import requests
                image=Image.open(requests.get("https://previews.123rf.com/images/darrenwhi/darrenwhi1310/darrenwhi131000024/24022179-photo-of-many-cars-with-one-a-different-color.jpg", stream=True).raw)
                #image =resize((420,250))
                
                image_array=np.array(image)
                image 
                

                【讨论】:

                  猜你喜欢
                  • 2014-01-30
                  • 1970-01-01
                  • 2011-06-13
                  • 2011-05-25
                  • 2021-08-10
                  • 1970-01-01
                  • 2022-12-21
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多