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()
When I try to display the image as loaded by the csv file I obtain the error: Image data can not convert to float. However, I was able to correctly display the image when using the dataframe df
.
I suspect that something went wrong with the data type when I stored df onto a csv file. How would I fix this issue?
edit: I should add that my main objective is to
Assign the country list to the existing dataframe df . This would be appended as a new column to the existing dataframe. Write a function that will convert the given path of the images to the HTML tag. Render the dataframe as an HTML table, and then call the HTML method to display the rendered images.
This image data source is used to load image files from a directory, it can load compressed image (jpeg, png, etc.) into raw image representation via ImageIO in Java library. The loaded DataFrame has one StructType column: “image”, containing image data stored as image schema.
Pandas is a third-party data analysis library where its dataframe class is used primarily to store primitive types (str, int, float, boolean, datetime, etc.) for numeric/indicator data. For general purpose object storage, use built-in python types (e.g., lists, dicts).
If you have Pandas column that contains URL or local path you can generate Image column which will display thumbnail or any other image size.
1. In case you have URLs of images in list.
You will first need to download images based on image URLs. adImageList
contains list of URL of images which you want to add to pandas as column.
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. In case you have image URLs in separate column in Pandas dataframe. First create function for getting local URL for single image
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)
Than use lambda expression to map that to new column imageLocal
:
df['imageLocal'] = df.URL.map(lambda f: get_image_local(f))
df['imageLocal']
should look something like this:
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. With PILL functions you can just copy paste now:
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)}">'
We can pass our local image path to get_thumbnail(path)
with following:
df['imagePILL'] = df.imageLocal.map(lambda f: get_thumbnail(f))
And df['imagePILL']
should look like this:
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>
You can resort pandas dataframe to get your new column in desired position:
df= df.reindex(sorted(df.columns), axis=1)
And now if you want to view pandas dataframe with resized images just call image_formatter
function in IPython.display
HTML function:
HTML(df.to_html(formatters={'imagePILL': image_formatter}, escape=False))
You can use any other way of showing HTML, important thing is to get PIL object inside pandas dataframe.
It is not clear from the question why you would want to use pandas dataframes to store the image. I think this makes things unnecessarily complicated. You may instead directly store the numpy array in binary format and load it again at some point later.
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()
As a response to the comments below, which turn the question somehow in a different direction, you may surely store the path/name of the image in the dataframe.
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()
Last, you may go along the initally planned way of storing the actual image in a dataframe cell, but instead of writing to csv, you map pickle the dataframe, such that it can be read out just as if it had never been saved before.
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()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With