如何显示存储在熊猫数据框中的图像?

Posted

技术标签:

【中文标题】如何显示存储在熊猫数据框中的图像?【英文标题】:How to display image stored in pandas dataframe? 【发布时间】:2018-02-16 20:11:23 【问题描述】:
import pandas as pd
from scipy import misc
import numpy as np
import matplotlib.pyplot as plt

W = 'img':[misc.imread('pic.jpg')]
df = pd.DataFrame(W)

# This displays the image
plt.imshow(df.img1[0])
plt.show()

df.to_csv('mypic.csv')
new_df= pd.read_csv('mypic.csv')

# This does not display the image
plt.imshow(new_df.img1[0])
plt.show()

当我尝试显示由 csv 文件加载的图像时,我收到错误:图像数据无法转换为浮点数。但是,当使用数据框df 时,我能够正确显示图像。

我怀疑当我将 df 存储到 csv 文件时,数据类型出现了问题。我该如何解决这个问题?

编辑:我应该补充一点,我的主要目标是

    将包含图像的 pandas 数据帧写入 csv 文件 从磁盘读取 csv 文件,而不是将整个数据帧存储在 RAM 上

【问题讨论】:

您是否在每个单元格中存储 rgb 元组?你能提供一些 df 的样本吗? img是3维数据,to_csv无法处理(查看mypic.csv的内容)。 是的,我正在存储 rgb 图像。我可以将数据存储在其他类型的文件中吗? 【参考方案1】:

如何在 pandas 数据框中显示图像

如果您有包含 URL 或本地路径的 Pandas 列,您可以生成将显示缩略图或任何其他图像大小的图像列。

1.如果您在列表中有图片的 URL。

您首先需要根据图片 URL 下载图片。 adImageList 包含您要作为列添加到 pandas 的图像的 URL 列表。

dir_base = os.getcwd() # Get your current directory
for i, URL in enumerate(adImageList):
                image_name= '0_'.format(i+1,'_image.jpg') # This will show for example 01_image.jpg
                urllib.request.urlretrieve(URL, image_name)
                local_path_thumb = os.path.join(dir_base , image_name)
                df[i]['local_image_path']=local_path # adding that locally fetched image path to pandas column

2。如果您在 Pandas 数据框中的单独列中有图像 URL。 首先创建获取单个图像的本地 URL 的函数

   get_image_local(URL):            
        image_name= '0_'.format(i+1,'_image.jpg')
        urllib.request.urlretrieve(URL, image_name)
        local_path_image = os.path.join(dir_base, image_name)
        return (local_path_image)

而不是使用 lambda 表达式将其映射到新列 imageLocal

df['imageLocal'] = df.URL.map(lambda f: get_image_local(f)) 

df['imageLocal'] 应该如下所示:

0 C:\Users\username\Documents\Base_folder\01_image.jpg         
1 C:\Users\username\Documents\Base_folder\02_image.jpg                          
2 C:\Users\username\Documents\Base_folder\03_image.jpg

3.使用 PILL 函数,您现在只需复制粘贴即可:

import glob
import random
import base64
import pandas as pd

from PIL import Image
from io import BytesIO
from IPython.display import html
import io

pd.set_option('display.max_colwidth', -1)


def get_thumbnail(path):
    path = "\\\\?\\"+path # This "\\\\?\\" is used to prevent problems with long Windows paths
    i = Image.open(path)    
    return i

def image_base64(im):
    if isinstance(im, str):
        im = get_thumbnail(im)
    with BytesIO() as buffer:
        im.save(buffer, 'jpeg')
        return base64.b64encode(buffer.getvalue()).decode()

def image_formatter(im):
    return f'<img src="data:image/jpeg;base64,image_base64(im)">'

我们可以通过以下方式将本地图像路径传递给get_thumbnail(path)

df['imagePILL'] = df.imageLocal.map(lambda f: get_thumbnail(f))

df['imagePILL'] 应该是这样的:

0    <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=300x400 at 0x265BA323240>
1    <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=200x150 at 0x265BA3231D0>
2    <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=300x400 at 0x265BA3238D0>

您可以使用 pandas 数据框将新列放在所需位置:

df= df.reindex(sorted(df.columns), axis=1)

现在,如果您想查看带有调整大小图像的 pandas 数据框,只需在 IPython.display HTML 函数中调用 image_formatter 函数:

HTML(df.to_html(formatters='imagePILL': image_formatter, escape=False))

您可以使用任何其他方式显示 HTML,重要的是在 pandas 数据帧中获取 PIL 对象。

【讨论】:

【参考方案2】:

从问题中不清楚为什么要使用 pandas 数据帧来存储图像。我认为这使事情变得不必要地复杂。您可以改为直接以二进制格式存储 numpy 数组,并在稍后再次加载。

import numpy as np
import matplotlib.pyplot as plt

#create an image
imar = np.array([[[1.,0.],[0.,0.]],
                 [[0.,1.],[0.,1.]],
                 [[0.,0.],[1.,1.]]]).transpose()
plt.imsave('pic.jpg', imar)

# read the image
im = plt.imread('pic.jpg')
# show the image
plt.imshow(im)
plt.show()

#save the image array to binary file
np.save('mypic', im)
# load the image from binary file
new_im= np.load('mypic.npy')
# show the loaded image
plt.imshow(new_im)
plt.show()

作为对以下 cmets 的回应,它们以某种方式将问题转向不同的方向,您肯定可以将图像的路径/名称存储在数据框中。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

#create an image
imar = np.array([[[1.,0.],[0.,0.]],
                 [[0.,1.],[0.,1.]],
                 [[0.,0.],[1.,1.]]]).transpose()
plt.imsave('pic.jpg', imar)

#create dataframe

df = pd.DataFrame([[0,""]], columns=["Feature1","Feature2"])

# read the image
im = plt.imread('pic.jpg')

plt.imshow(im)
plt.show()

#save the image array to binary file
np.save('mypic.npy', im)
# store name of image in dataframe
df.iloc[0,1] = 'mypic.npy'
#save dataframe
df.to_csv("mydf.csv")
del df

#read dataframe from csv
df = pd.read_csv("mydf.csv")
# load the image from binary file, given the path from the Dataframe
new_im= np.load(df["Feature2"][0])
# show the loaded image
plt.imshow(new_im)
plt.show()

最后,您可以按照最初计划的方式将实际图像存储在数据框单元格中,但不是写入 csv,而是对数据框进行映射,以便可以像从未读取过一样读取它之前保存过。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import pickle

#create an image
imar = np.array([[[1.,0.],[0.,0.]],
                 [[0.,1.],[0.,1.]],
                 [[0.,0.],[1.,1.]]]).transpose()
plt.imsave('pic.jpg', imar)

#create dataframe

df = pd.DataFrame([[0,""]], columns=["Feature1","Feature2"])

# read the image
im = plt.imread('pic.jpg')

plt.imshow(im)
plt.show()

# store the image itself  in dataframe
df.iloc[0,1] = [im]
#save dataframe
pickle.dump(df, file("mydf.pickle", "wb"))
del df

#read dataframe from pickle
df = pickle.load(file("mydf.pickle", "rb"))

# show the loaded image from dataframe cell
plt.imshow(df["Feature2"][0][0])
plt.show()

【讨论】:

我有一个数据电子表格,其中每一行是一个不同的项目,每一列代表项目的一个特征。特征之一由图像文件描述。我认为最好使用 pandas 数据框来有效地访问我的数据。此外,它是一个大型数据集,因此我想从磁盘读取它。是否可以使用 pandas 数据框来做到这一点? 我是否可以链接到我的数据框中的图像文件,而不是将整个图像存储在数据框中? 问题中需要有关您要完成的工作的这类信息。现在我用两种可能对你有帮助的新方法更新了答案。

以上是关于如何显示存储在熊猫数据框中的图像?的主要内容,如果未能解决你的问题,请参考以下文章

如何隐藏显示序列号的熊猫数据框中的第一列[重复]

如何舍入仅用于在熊猫中显示的值,同时在数据框中保留原始值?

从存储为熊猫数据框中的字符串的列表中提取项目

熊猫从数据框中的一列中提取部分字符串并将其存储在一个新列中

如何在 Pandas 数据框中的特定位置插入一列? (更改熊猫数据框中的列顺序)

如何在 for 循环中附加熊猫数据框中的行?