【问题标题】:What's the fastest way to read images from urls?从网址读取图像的最快方法是什么?
【发布时间】:2019-09-13 06:03:49
【问题描述】:

我想制作一个生成器,从 url 生成批量图像以训练 keras 模型。我有另一个生成器,可以为我提供图像 url。

我目前所做的是将图像下载到磁盘,然后从磁盘加载图像。

def loadImage(URL):
    with urllib.request.urlopen(URL) as url:
        with open('temp.jpg', 'wb') as f:
            f.write(url.read())

    img_path = 'temp.jpg'
    img = image.load_img(img_path, target_size=(125, 125))
    os.remove(img_path)
    x = image.img_to_array(img)
    return x

def imageGenerator(batch_size):
    i = 0
    batch = []
    for URL in imageUrlGenerator():
        if i>batch_size:
            yield batch
            batch = []
            i=0
        batch.append(loadImage(URL))
        i+=1

这可行,但我想知道是否没有更快的方法从网络加载图像而无需在磁盘中写入和读取。

【问题讨论】:

    标签: python image url keras


    【解决方案1】:

    假设您实际使用的是keras,并且这个image.load_img 是您正在调用的方法,那么它将是call a function,最终应该是PIL.Image.open。在PIL.image.open 的文档中,第一个参数fp 可以是字符串文件名(这是您当前传递的内容),或者是实现readseektell 的类流对象。虽然urllib.request.urlopen返回的对象确实提供了所有三个方法,但它根本没有实现seek,所以不能直接使用。但是,可以将整个缓冲区读入一个确实实现了seekBytesIO 对象,因此它应该是可用的。综上所述,您的 loadImage 函数可能会简化为以下内容:

    from io import BytesIO
    
    def loadImage(URL):
        with urllib.request.urlopen(URL) as url:
            img = image.load_img(BytesIO(url.read()), target_size=(125, 125))
    
        return image.img_to_array(img)
    

    这会将下载的图像完全保存在内存中。

    【讨论】:

    • 听起来不错,但是使用 keras 函数 image.load_img(img_path, target_size=(125, 125)) 我可以选择目标大小,您如何建议使用这种方法? (记住速度很重要)
    • @CristianDesivo 它应该按预期工作。我现在更新了我的示例,以更能反映您正在尝试做的事情,因为我在复制您的代码时遗漏了一些位。
    • 缺少导入:from urllib.request import urlopenfrom tensorflow.keras.preprocessing.image import load_img, img_to_array
    • 更重要的是:它不再适用于 URL 字符串:TypeError: expected str, bytes or os.PathLike object, not _io.BytesIO:github.com/keras-team/keras-preprocessing/issues/293
    • @kilgoretrout 是的,你是对的,this was the commitpil_image.open 的直接调用修改为open 读入导致此损坏的BytesIO。一个快速的解决方法是让相关代码部分检查提供的参数是否已经是 BytesIO 实例,如果是则直接使用它。
    【解决方案2】:

    这是我见过的最简单的解决方案。

    from PIL import Image
    from urllib import request
    from io import BytesIO
    
    url = "https://github.com/ironmanciti/MachineLearningBasic/blob/master/datasets/TransferLearningData/watch.jpg?raw=true"
    res = request.urlopen(url).read()
    Sample_Image = Image.open(BytesIO(res)).resize((150,150))
    
    plt.imshow(Sample_Image)
    

    【讨论】:

    • 由于我在上面评论过的问题,现在这应该是公认的答案。
    【解决方案3】:

    Github问题得到这个

    from io import BytesIO
    from PIL import Image
    import requests
    
    def loadImage(url):
        response = requests.get(url)
        img_bytes = BytesIO(response.content)
        img = Image.open(img_bytes)
        img = img.convert('RGB')
        img = img.resize((250,250), Image.NEAREST)
        img = img_to_array(img)
        return img
    
    

    【讨论】:

      【解决方案4】:

      2 快速修复:

      • 考虑移动os.remove(img_path) 行。我假设这是从您的驱动器中删除文件,但我认为您可以将其保存到最后。您的模型只需要所有可能的信息。获得信息后,您可以异步开始删除文件,或者等到模型经过训练和清理。像你一样一件一件地做,可能会减慢你的速度。
      • 使用快速存储设备和配置、SSD、USB 3.x、USB C 等。

      其他修复:

      • 是否可以在缓存中保存内容?
      • 你能把东西放在一个数组里吗?我不这么认为,但有可能。
      • 您需要整个图像吗?你能降低图像的质量吗?
      • 图像的嵌套程度如何?解析图像可能不是问题,但检查也无妨。

      【讨论】:

        猜你喜欢
        • 2013-05-12
        • 1970-01-01
        • 2015-06-15
        • 2013-06-08
        • 2011-08-11
        • 2011-10-26
        • 1970-01-01
        • 1970-01-01
        • 2023-03-25
        相关资源
        最近更新 更多