I’m loading SVG images and everything was going fine except the resizing operation is somehow causing an error when I attempt to display the fastai image in my notebook.
What’s strange is that my assertions show that the ndarray is c-contiguous during my code, but once it gets down deep into PIL, somehow a copy of that data is no longer c-contiguous. Thus I couldn’t figure out how to manipulate my image to get rid of this error. Interestingly enough, the image successfully renders so it feels like more of a warning.
(As an aside, there’s other idiocracy going on here - why am I rasterizing an SVG only to the resize it later; shouldn’t I resize the SVG first. Yes, but I couldn’t figure out how to resize it to my target width. See comments).
You’ll first need:
pip install cairosvg
Then:
import fastai
from fastai import *
from fastai.vision import *
from fastai.callbacks import *
from fastai.utils.mem import *
import cairosvg
def load_svg_image(url, target_width=300):
""" Load SVG image with Cairo, and convert to FastAI Image
"""
import urllib.request
from PIL import Image as PilImage
import io
url = 'https://upload.wikimedia.org/wikipedia/commons/b/b2/Tom_Cruise_signature.svg'
bytestring = urllib.request.urlopen(url).read().decode('utf-8')
# This is really dumb given the point of SVG is scalable, but cairosvg
# doesn't seem to support target width very well.
# So we can scale it up, rasterize, then we'll resize it down to what
# we want, because cairosvg's output-width parameter isn't accesible
# from python and doesn't seem to work from the command line.
scale = 1.0
sig_bytes = cairosvg.svg2png(bytestring=bytestring, scale=scale)
sig_img_data = PilImage.open(io.BytesIO(sig_bytes))
img_tensor = pil2tensor(sig_img_data, np.float32)
img_tensor.div_(255)
img = Image(img_tensor)
# Resize the image to desired width.
ratio = target_width / img.shape[2]
new_sz = img.shape[0], int(img.shape[1] * ratio), int(img.shape[2] * ratio)
img = img.resize(size=new_sz).refresh()
# Attempt to make memory contiguous, but this doesn't matter, the problem
# happens later on.
#a = img.data.numpy()
#assert a.flags['C_CONTIGUOUS'] == True
#a = np.ascontiguousarray(a)
#assert a.flags['C_CONTIGUOUS'] == True
#img = Image(torch.from_numpy(a)).refresh()
#assert img.data.numpy().flags['C_CONTIGUOUS'] == True
return img
img = load_svg_image(sig_file)
img
Results in:
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
/opt/anaconda3/lib/python3.7/site-packages/IPython/core/formatters.py in __call__(self, obj)
343 method = get_real_method(obj, self.print_method)
344 if method is not None:
--> 345 return method()
346 return None
347 else:
/opt/anaconda3/lib/python3.7/site-packages/fastai/vision/image.py in _repr_jpeg_(self)
87 def __repr__(self): return f'{self.__class__.__name__} {tuple(self.shape)}'
88 def _repr_png_(self): return self._repr_image_format('png')
---> 89 def _repr_jpeg_(self): return self._repr_image_format('jpeg')
90
91 def _repr_image_format(self, format_str):
/opt/anaconda3/lib/python3.7/site-packages/fastai/vision/image.py in _repr_image_format(self, format_str)
91 def _repr_image_format(self, format_str):
92 with BytesIO() as str_buffer:
---> 93 plt.imsave(str_buffer, image2np(self.px), format=format_str)
94 return str_buffer.getvalue()
95
/opt/anaconda3/lib/python3.7/site-packages/matplotlib/pyplot.py in imsave(fname, arr, **kwargs)
2138 @docstring.copy(matplotlib.image.imsave)
2139 def imsave(fname, arr, **kwargs):
-> 2140 return matplotlib.image.imsave(fname, arr, **kwargs)
2141
2142
/opt/anaconda3/lib/python3.7/site-packages/matplotlib/image.py in imsave(fname, arr, vmin, vmax, cmap, format, origin, dpi)
1505 pil_shape = (rgba.shape[1], rgba.shape[0])
1506 image = Image.frombuffer(
-> 1507 "RGBA", pil_shape, rgba, "raw", "RGBA", 0, 1)
1508 if format in ["jpg", "jpeg"]:
1509 format = "jpeg" # Pillow doesn't recognize "jpg".
/opt/anaconda3/lib/python3.7/site-packages/PIL/Image.py in frombuffer(mode, size, data, decoder_name, *args)
2607 import numpy as np
2608 #data = np.ascontiguousarray(data)
-> 2609 im = im._new(core.map_buffer(data, size, decoder_name, None, 0, args))
2610 im.readonly = 1
2611 return im
ValueError: ndarray is not C-contiguous
Help appreciated!