Write an image and optionally coordinates into files.
Module sppas.src.imgdata
Class sppasCoordsImageWriter
Description
Constructor
Create a new sppasCoordsImageWriter instance.
Write the given image in the given filename. Parts of the image can be extracted in separate image files and/or surrounded on the given image. Output images can be resized.
View Source
def __init__(self):
"""Create a new sppasCoordsImageWriter instance.
Write the given image in the given filename.
Parts of the image can be extracted in separate image files and/or
surrounded on the given image.
Output images can be resized.
"""
self.options = ImageCoordsWriterOptions()
self._colors = sppasCoordsImageWriter.gen_colors(10)
self._csv_separator = ';'
self._xra_tiername = None
Public functions
gen_colors
Return a list of visually distinct colors.
Parameters
- nb: (int) A number of colors
Returns
- dict of(r, g, b) values
View Source
@staticmethod
def gen_colors(nb):
"""Return a list of visually distinct colors.
:param nb: (int) A number of colors
:return: dict of (r, g, b) values
"""
colors = {k: [] for k in 'rgb'}
for i in range(nb):
temp = {k: randint(0, 255) for k in 'rgb'}
for k in temp:
while 1:
c = temp[k]
t = set((j for j in range(c - 15, c + 15) if 0 <= j <= 255))
if t.intersection(colors[k]):
temp[k] = randint(0, 255)
else:
break
colors[k].append(temp[k])
return colors
get_colors
Return the list of (r, g, b) values to tag the image.
View Source
def get_colors(self):
"""Return the list of (r, g, b) values to tag the image."""
return self._colors
get_csv_sep
View Source
def get_csv_sep(self):
return self._csv_separator
set_xra_tiername
View Source
def set_xra_tiername(self, name):
if self._xra_tiername is None:
self._xra_tiername = name
return True
return False
get_xra_tiername
View Source
def get_xra_tiername(self):
return self._xra_tiername
get_width
View Source
def get_width(self):
return self.options.get_width()
get_height
View Source
def get_height(self):
return self.options.get_height()
set_options
Set the value of each option.
Parameters
- csv
- xra
- tag
- crop
- width
- height
View Source
def set_options(self, csv=None, xra=None, tag=None, crop=None, width=None, height=None):
"""Set the value of each option."""
if csv is not None:
self.options.set_csv_output(csv)
if xra is not None:
self.options.set_xra_output(xra)
if tag is not None:
self.options.set_tag_output(tag)
if crop is not None:
self.options.set_crop_output(crop)
if width is not None:
self.options.set_width(width)
if height is not None:
self.options.set_height(height)
write
Save the image into file(s) depending on the options.
Parameters
- image: (sppasImage) The image to write
- coords: (list or list of list of sppasCoords) The coordinates of objects
- outimgname: (str) The filename of the output image file
- pattern: (str) Pattern to add to a cropped image filename
Returns
- List of created file names
View Source
def write(self, image, coords, out_img_name, pattern=''):
"""Save the image into file(s) depending on the options.
:param image: (sppasImage) The image to write
:param coords: (list or list of list of sppasCoords) The coordinates of objects
:param out_img_name: (str) The filename of the output image file
:param pattern: (str) Pattern to add to a cropped image filename
:return: List of created file names
"""
if isinstance(image, sppasImage) is False:
raise sppasTypeError('image', 'sppasImage')
if isinstance(coords, (list, tuple)) is False:
raise sppasTypeError('coords', '(list, tuple)')
new_files = list()
if self.options.csv is True:
fn, fe = os.path.splitext(out_img_name)
out_csv_name = fn + '.csv'
self.write_csv_coords(coords, out_csv_name, out_img_name)
new_files.append(out_csv_name)
if self.options.xra is True:
fn, fe = os.path.splitext(out_img_name)
out_xra_name = fn + '.xra'
self.write_xra_coords(coords, out_xra_name, out_img_name)
new_files.append(out_xra_name)
if self.options.tag is True:
self.write_tagged_img(image, coords, out_img_name)
new_files.append(out_img_name)
if self.options.crop is True:
cropped_files = self.write_cropped_img(image, coords, out_img_name, pattern)
new_files.extend(cropped_files)
return new_files
write_csv_coords
Write or append a list of coordinates in a CSV file.
- index of the coords in the image
- confidence
- x, y, w, h
- image name
Parameters
- coords: (sppasCoords) The coordinates of objects
- outcsvname: (str) The filename of the CSV file to write
- img_name: (str) The filename of the image
View Source
def write_csv_coords(self, coords, out_csv_name, img_name=''):
"""Write or append a list of coordinates in a CSV file.
- index of the coords in the image
- confidence
- x, y, w, h
- image name
:param coords: (sppasCoords) The coordinates of objects
:param out_csv_name: (str) The filename of the CSV file to write
:param img_name: (str) The filename of the image
"""
mode = 'w'
if os.path.exists(out_csv_name) is True:
mode = 'a+'
with codecs.open(out_csv_name, mode, encoding='utf-8') as f:
for i, c1 in enumerate(coords):
if isinstance(c1, (list, tuple)) is False:
f.write('{:d}{:s}'.format(i + 1, self._csv_separator))
self.write_coords(f, c1)
else:
for j, c2 in enumerate(c1):
f.write('{:d}{:s}'.format(j + 1, self._csv_separator))
self.write_coords(f, c2, self._csv_separator)
if len(img_name) > 0:
f.write('{:s}{:s}'.format(img_name, self._csv_separator))
f.write('\n')
write_xra_coords
Write or append a list of coordinates in an XRA file.
- index of the coords in the image
- confidence
- x, y, w, h
- image name
Parameters
- coords: (sppasCoords) The coordinates of objects
- outxraname: (str) The filename of the XRA file to write
- img_name: (str) The filename of the image
View Source
def write_xra_coords(self, coords, out_xra_name, img_name=''):
"""Write or append a list of coordinates in an XRA file.
- index of the coords in the image
- confidence
- x, y, w, h
- image name
:param coords: (sppasCoords) The coordinates of objects
:param out_xra_name: (str) The filename of the XRA file to write
:param img_name: (str) The filename of the image
"""
tiername = 'ImgCoords'
if self._xra_tiername is not None:
tiername = self._xra_tiername
loc = sppasPoint(1)
if os.path.exists(out_xra_name):
trs = sppasXRA('ImageCoordinates')
trs.read(out_xra_name)
tier = trs.find(tiername)
if tier is None:
raise Exception('Invalid tier in XRA. Cant add coordinates.')
last_point = tier.get_last_point()
loc = sppasPoint(last_point.get_midpoint() + 1)
else:
m = mimetypes.guess_type(img_name)
if m[0] is None:
fn, fe = os.path.splitext(img_name)
mime_type = 'image/' + fe[1:]
else:
mime_type = m[0]
media = sppasMedia(img_name, mime_type=mime_type)
tier = sppasTier(tiername)
tier.set_media(media)
trs = sppasXRA('ImageCoordinates')
trs.append(tier)
labels = list()
for c in coords:
if isinstance(c, sppasCoords) is False:
c = sppasCoords.to_coords(c)
tag = sppasTag((c.x, c.y, c.w, c.h), tag_type='rect')
label = sppasLabel(tag, c.get_confidence())
labels.append(label)
ann = tier.create_annotation(sppasLocation(loc), labels)
ann.set_meta('image_name', img_name)
trs.write(out_xra_name)
write_coords
Write coordinates in the given stream.
Parameters
- fd: (Stream) File descriptor, String descriptor, stdout, etc
- coords: (sppasCoordinates) Coordinates to write in other columns
- sep: (char) CSV separator
View Source
def write_coords(self, fd, coords, sep=';'):
"""Write coordinates in the given stream.
:param fd: (Stream) File descriptor, String descriptor, stdout, etc
:param coords: (sppasCoordinates) Coordinates to write in other columns
:param sep: (char) CSV separator
"""
fd.write('{:f}{:s}'.format(coords.get_confidence(), sep))
fd.write('{:d}{:s}'.format(coords.x, sep))
fd.write('{:d}{:s}'.format(coords.y, sep))
fd.write('{:d}{:s}'.format(coords.w, sep))
fd.write('{:d}{:s}'.format(coords.h, sep))
write_tagged_img
Tag and save the images with colored squares at given coords.
Parameters
- image: (sppasImage) The image to write
- coords: (list or list of list of sppasCoords) The coordinates of objects
- outimgname: (str) The filename of the output image file
View Source
def write_tagged_img(self, image, coords, out_img_name):
"""Tag and save the images with colored squares at given coords.
:param image: (sppasImage) The image to write
:param coords: (list or list of list of sppasCoords) The coordinates of objects
:param out_img_name: (str) The filename of the output image file
"""
img = self.tag_image(image, coords)
if self.options.get_width() > 0 or self.options.get_height() > 0:
img = img.iresize(self.options.get_width(), self.options.get_height())
img.write(out_img_name)
return img
tag_image
Tag the image at the given coords.
Parameters
- image: (sppasImage) The image to write
- coords: (list of sppasCoords OR list(list of sppasCoords)) The coordinates of objects
- colors: list of(r,g,b) List of tuple with RGB int values
Returns
- a copy of the image with colored squares at the given coords
View Source
def tag_image(self, image, coords, colors=list()):
"""Tag the image at the given coords.
:param image: (sppasImage) The image to write
:param coords: (list of sppasCoords OR list(list of sppasCoords)) The coordinates of objects
:param colors: list of (r,g,b) List of tuple with RGB int values
:return: a copy of the image with colored squares at the given coords
"""
if coords is None:
return image
if isinstance(image, sppasImage) is False:
raise sppasTypeError('image', 'sppasImage')
if isinstance(coords, (list, tuple)) is False:
raise sppasTypeError('coords', '(list, tuple)')
img = sppasImage(input_array=image.copy())
w, h = img.size()
pen_width = max(2, int(float(w + h) / 500.0))
if len(colors) == 0 and len(coords) > len(self._colors['r']):
nb = max(10, len(coords) - len(self._colors['r']) + 1)
new_colors = sppasCoordsImageWriter.gen_colors(nb)
self._colors.update(new_colors)
return self.tag_coords(img, coords, pen_width, colors)
tag_coords
Tag image for the given coords.
Parameters
- img: (sppasImage) The image to write
- coords: (list of sppasCoords OR list(list of sppasCoords)) The coordinates of objects
- colors: List of(r,g,b) Tuple with RGB int values
Returns
- (sppasImage)
View Source
def tag_coords(self, img, coords, pen_width, colors=list()):
"""Tag image for the given coords.
:param img: (sppasImage) The image to write
:param coords: (list of sppasCoords OR list(list of sppasCoords)) The coordinates of objects
:param colors: List of (r,g,b) Tuple with RGB int values
:return: (sppasImage)
"""
if coords is None:
return img
if isinstance(img, sppasImage) is False:
raise sppasTypeError('image', 'sppasImage')
if isinstance(coords, (list, tuple)) is False:
raise sppasTypeError('coords', '(list, tuple)')
for i, c in enumerate(coords):
if c is None:
continue
if len(colors) != len(coords):
n = len(self._colors['r'])
r = self._colors['r'][i % n]
g = self._colors['g'][i % n]
b = self._colors['b'][i % n]
rgb = (r, g, b)
else:
rgb = colors[i]
if isinstance(c, (list, tuple)) is False:
c = [c]
img = img.isurround(c, color=rgb, thickness=pen_width, score=True)
return img
write_cropped_img
Crop and save the images with squares at given coords.
Parameters
- image: (sppasImage) The image to write
- coords: (sppasCoords) The coordinates of objects
- outimgname: (str) The filename of the output image files
- pattern: (str) Pattern to add to each file
Returns
- list of file names
View Source
def write_cropped_img(self, image, coords, out_img_name, pattern=''):
"""Crop and save the images with squares at given coords.
:param image: (sppasImage) The image to write
:param coords: (sppasCoords) The coordinates of objects
:param out_img_name: (str) The filename of the output image files
:param pattern: (str) Pattern to add to each file
:return: list of file names
"""
cropped_files = list()
for i, c in enumerate(coords):
fn, fe = os.path.splitext(out_img_name)
if len(pattern) > 0 and fn.endswith(pattern):
fn = fn[:len(fn) - len(pattern)]
out_iname = '{:s}_{:d}{:s}{:s}'.format(fn, i + 1, pattern, fe)
img = self.crop_and_size_image(image, c)
if self.options.get_width() > 0 or self.options.get_height() > 0:
img = img.iresize(self.options.get_width(), self.options.get_height())
img.write(out_iname)
cropped_files.append(out_iname)
return cropped_files
crop_and_size_image
Crop the given image at the given coords and resize.
Parameters
- image: (sppasImage) The image to write
- coord: (sppasCoords) The coordinates of the area to crop
Returns
- (sppasImage)
View Source
def crop_and_size_image(self, image, coord):
"""Crop the given image at the given coords and resize.
:param image: (sppasImage) The image to write
:param coord: (sppasCoords) The coordinates of the area to crop
:return: (sppasImage)
"""
img = image.icrop(coord)
img = img.iresize(self.options.get_width(), self.options.get_height())
return sppasImage(input_array=img)