SPPAS 4.22

https://sppas.org/

Module sppas.src.imgdata

Class sppasCoordsImageWriter

Description

Write an image and optionally coordinates into files.

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)