【问题标题】:Spark using PySpark read imagesSpark 使用 PySpark 读取图像
【发布时间】:2016-01-13 07:07:46
【问题描述】:

您好,我有很多图像(数百万以下)需要对其进行分类。我正在使用 Spark,并设法将 (filename1, content1), (filename2, content2) ... 格式的所有图像读入一个大 RDD。

images = sc.wholeTextFiles("hdfs:///user/myuser/images/image/00*")  

但是,我真的很困惑如何处理图像的 unicode 表示。

这是一个图像/文件的示例:

(u'hdfs://NameService/user/myuser/images/image/00product.jpg', u'\ufffd\ufffd\ufffd\ufffd\x00\x10JFIF\x00\x01\x01\x01\x00`\x00`\x00\x00\ufffd\ufffd\x01\x1eExif\x00\x00II*\x00\x08\x00\x00\x00\x08\x00\x12\x01\x03\x00\x01\x00\x00\x00\x01\x00\x00\x00\x1a\x01\x05\x00\x01\x00\x00\x00n\x00\x00\x00\x1b\x01\x05\x00\x01\x00\x00\x00v\x00\x00\x00(\x01\x03\x00\x01\x00\x00\x00\x02\x00\x00\x001\x01\x02\x00\x0b\x00\x00\x00~\x00\x00\x002\x01\x02\x00\x14\x00\x00\x00\ufffd\x00\x00\x00\x13\x02\x03\x00\x01\x00\x00\x00\x01\x00\x00\x00i\ufffd\x04\x00\x01\x00\x00\x00\ufffd\x00\x00\x00\x00\x00\x00\x00`\x00\x00\x00\x01\x00\x00\x00`\x00\x00\x00\x01\x00\x00\x00GIMP 2.8.2\x00\x002013:07:29 10:41:35\x00\x07\x00\x00\ufffd\x07\x00\x04\x00\x00\x000220\ufffd\ufffd\x02\x00\x04\x00\x00\x00407\x00\x00\ufffd\x07\x00\x04\x00\x00\x000100\x01\ufffd\x03\x00\x01\x00\x00\x00\ufffd\ufffd\x00\x00\x02\ufffd\x04\x00\x01\x00\x00\x00\x04\x04\x00\x00\x03\ufffd\x04\x00\x01\x00\x00\x00X\x01\x00\x00\x05\ufffd\x04\x00\x01\x00\x00\x00\ufffd\x00\x00\x00\x00\x00\x00\x00\x02\x00\x01\x00\x02\x00\x04\x00\x00\x00R98\x00\x02\x00\x07\x00\x04\x00\x00\x000100\x00\x00\x00\x00\ufffd\ufffd\x04_http://ns.adobe.com/xap/1.0/\x00<?xpacket begin=\'\ufeff\' id=\'W5M0MpCehiHzreSzNTczkc9d\'?>\n<x:xmpmeta xmlns:x=\'adobe:ns:meta/\'>\n<rdf:RDF xmlns:rdf=\'http://www.w3.org/1999/02/22-rdf-syntax-ns#\'>\n\n <rdf:Description xmlns:exif=\'http://ns.adobe.com/exif/1.0/\'>\n  <exif:Orientation>Top-left</exif:Orientation>\n  <exif:XResolution>96</exif:XResolution>\n  <exif:YResolution>96</exif:YResolution>\n  <exif:ResolutionUnit>Inch</exif:ResolutionUnit>\n  <exif:Software>ACD Systems Digital Imaging</exif:Software>\n  <exif:DateTime>2013:07:29 10:37:00</exif:DateTime>\n  <exif:YCbCrPositioning>Centered</exif:YCbCrPositioning>\n  <exif:ExifVersion>Exif Version 2.2</exif:ExifVersion>\n  <exif:SubsecTime>407</exif:SubsecTime>\n  <exif:FlashPixVersion>FlashPix Version 1.0</exif:FlashPixVersion>\n  <exif:ColorSpace>Uncalibrated</exif:ColorSpace>\n  

仔细一看,居然有一些字符看起来像元数据之类的

...
<x:xmpmeta xmlns:x=\'adobe:ns:meta/\'>\n<rdf:RDF xmlns:rdf=\'http://www.w3.org/1999/02/22-rdf-syntax-ns#\'>\n\n 
<rdf:Description xmlns:exif=\'http://ns.adobe.com/exif/1.0/\'>\n  
<exif:Orientation>Top-left</exif:Orientation>\n  
<exif:XResolution>96</exif:XResolution>\n  
<exif:YResolution>96</exif:YResolution>\n  
...

我以前的经验是使用包 scipy 和相关功能,如 'imread' ...输入通常是文件名。现在我真的迷失了这些 un​​icode 是什么意思,以及我可以做些什么来将其转换为我熟悉的格式。

谁能与我分享我如何将这些 un​​icode 读入 scipy 图像(ndarray)?

【问题讨论】:

  • 尝试使用 imread 映射 RDD。我认为这应该有效。详细说明:我不熟悉 JPEG 格式,但是每个图像都会变成一个文件,并且具有特定的格式,您可以使用 imread 之类的函数来简化复杂图像方案的操作。
  • @Dair 正在读取imread 的源代码,它确实是在尝试使用 PIL.Image 读取图像给定文件名,强制 imread 读取 unicode 不起作用。

标签: python image apache-spark scipy pyspark


【解决方案1】:

您的数据看起来像来自真实图像文件 (JPG?) 的原始字节。您的数据的问题在于它应该是字节,而不是 unicode。您必须弄清楚如何从 unicode 转换为字节。您必须处理一大堆充满编码陷阱的蠕虫,但使用img.encode('iso-8859-1') 可能会很幸运。我不知道,我不会在我的回答中处理这个问题。

PNG 图像的原始数据如下所示:

rawdata = '\x89PNG\r\n\x1a\n\x00\x00...\x00\x00IEND\xaeB`\x82'

一旦你得到它以字节为单位,你可以从原始数据创建一个 PIL 图像,并将它作为一个 nparray 读取:

>>> from StringIO import StringIO
>>> from PIL import Image
>>> import numpy as np
>>> np.asarray(Image.open(StringIO(rawdata)))

array([[[255, 255, 255,   0],
    [255, 255, 255,   0],
    [255, 255, 255,   0],
    ...,
    [255, 255, 255,   0],
    [255, 255, 255,   0],
    [255, 255, 255,   0]]], dtype=uint8)

要让它在 Spark 上运行,您只需 SparkContext.binaryFiles:

>>> images = sc.binaryFiles("path/to/images/")
>>> image_to_array = lambda rawdata: np.asarray(Image.open(StringIO(rawdata)))
>>> images.values().map(image_to_array)

【讨论】:

  • 我真的很喜欢 StringIO 方法,它也记录在 here 中,但是,将奇怪的 unicode 转换为字节可能是棘手的部分。 'utf-8' 和 'iso-8859-1' 都不起作用。虽然投票了:)
【解决方案2】:

在 Spark 2.3 或更高版本中,您可以使用内置的 Spark 工具将图像数据加载到 Spark DataFrame。在 2.3 中

from pyspark.ml.image import ImageSchema

ImageSchema.readImages("path/to/images/")

在 Spark 2.4 或更高版本中:

spark.read.format("image").load("path/to/images/")

这将创建一个具有以下架构的对象:

root
 |-- image: struct (nullable = true)
 |    |-- origin: string (nullable = true)
 |    |-- height: integer (nullable = false)
 |    |-- width: integer (nullable = false)
 |    |-- nChannels: integer (nullable = false)
 |    |-- mode: integer (nullable = false)
 |    |-- data: binary (nullable = false)

图片内容加载到image.data的位置。

目前此功能处于试验阶段,缺乏必要的生态系统,但未来应该会改进。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-02-04
    • 1970-01-01
    • 1970-01-01
    • 2020-04-14
    • 1970-01-01
    • 2022-01-03
    相关资源
    最近更新 更多