Beispiel #1
0
class Slic(Segmenter, SkimageSegmenter):
    """Run SLIC (Simple Linear Iterative Clustering) segmentation."""
    def __init__(self,
                 n_segments=35,
                 sigma=2.0,
                 compactness=10.0,
                 border_color='Yellow',
                 border_outline='No'):
        """Constructor.

        Parameters
        ----------
        n_segments : integer, optional, default = 250
            The (approximate) number of labels in the segmented output image.
        sigma : float, optional, default = 5.0
            Width of Gaussian smoothing kernel for pre-processing.
        compactness : float, optional, default = 10.0
            Higher values give more weight to space proximity, making superpixel shapes more square/cubic.
        border_color : string
            X11Color name of segment border color.
        border_outline : string
            If 'yes' double the size of segment border.
        """
        super(self.__class__, self).__init__(border_color, border_outline)

        self.n_segments = Config("Segments", n_segments, int)
        self.sigma = Config("Sigma", sigma, float)
        self.compactness = Config("Compactness", compactness, float)

    def get_config(self):
        """Return configuration of segmenter. 
        
        Returns
        -------
        config : OrderedDict
            Current configs of segmenter.
        """
        slic_config = OrderedDict()

        slic_config["n_segments"] = self.n_segments
        slic_config["sigma"] = self.sigma
        slic_config["compactness"] = self.compactness
        slic_config["border_color"] = self.border_color
        slic_config["border_outline"] = self.border_outline

        return slic_config

    def set_config(self, configs):
        """Update configuration of segmenter. 
        
        Parameters
        ----------
        configs : OrderedDict
            New configs of segmenter.
        """
        self.n_segments = Config.nvl_config(configs["n_segments"],
                                            self.n_segments)
        self.sigma = Config.nvl_config(configs["sigma"], self.sigma)
        self.compactness = Config.nvl_config(configs["compactness"],
                                             self.compactness)
        self.border_color = Config.nvl_config(configs["border_color"],
                                              self.border_color)
        self.border_outline = Config.nvl_config(configs["border_outline"],
                                                self.border_outline)

        self.border_outline.value = self.border_outline.value if self.border_outline.value == 'Yes' else 'No'

    def get_summary_config(self):
        """Return fomatted summary of configuration. 
        
        Returns
        -------
        summary : string
            Formatted string with summary of configuration.
        """
        slic_config = OrderedDict()

        slic_config[self.n_segments.label] = self.n_segments.value
        slic_config[self.sigma.label] = self.sigma.value
        slic_config[self.compactness.label] = self.compactness.value
        slic_config[self.border_color.label] = self.border_color.value
        slic_config[self.border_outline.label] = self.border_outline.value

        summary = ''
        for config in slic_config:
            summary += "%s: %s\n" % (config, str(slic_config[config]))

        return summary

    def get_list_segments(self):
        """Return a list with segments after apply segmentation. 
        
        Returns
        -------
        segments : list
            List of segments of segmented image.
        """
        return self.get_list_segments_skimage()

    def get_segment(self, px=0, py=0, idx_segment=None, path_to_mask=None):
        """Return a specified segment using a index or position in image. 
        
        Parameters
        ----------
        px : integer, optional, default = 0
            Segment point inside the image in x-axis.
        py : integer, optional, default = 0
            Segment point inside the image in y-axis.
        idx_segment : integer, optional, default = None
            Index of segment returned by previous call of this method.
            
        Returns
        -------
        segment : opencv 3-channel color image.
            Rectangle encompassing the segment image.
        size_segment : integer
            Number of pixels of segment.
        idx_segment : integer
            Index of segment if found, -1 otherwise.
        run_time : integer
            Running time spent in milliseconds.
        """
        return self.get_segment_skimage(px, py, idx_segment, path_to_mask)

    def paint_segment(self,
                      image,
                      color,
                      px=0,
                      py=0,
                      idx_segment=[],
                      border=True,
                      clear=False):
        """Paint a list of segments using a index or position in image.
        
        Parameters
        ----------
        image : opencv 3-channel color image.
            Segmented image.
        color : string
            X11Color name.
        px : integer, optional, default = 0
            Segment point inside the image in x-axis.
        py : integer, optional, default = 0
            Segment point inside the image in y-axis.
        idx_segment : list, optional, default = []
            List of segments.
        border : boolean, optional, default = True
            If true paint the border of segments with default color.
        clear : boolean, optional, default = False
            If true clear previous painting in the image.

        Returns
        -------
        new_image : opencv 3-channel color image.
            Painted image.
        run_time : integer
            Running time spent in milliseconds.
        """
        return self.paint_segment_skimage(image, color, px, py, idx_segment,
                                          border, clear)

    def run(self, image):
        """Perform the segmentation 
        
        Parameters
        ----------
        image : opencv 3-channel color image.
            Original image.
            
        Returns
        -------
        new_image : opencv 3-channel color image.
            Segmented image.
        run_time : integer
            Running time spent in milliseconds.
        """
        args = {
            "n_segments": self.n_segments.get_cast_val(),
            "sigma": self.sigma.get_cast_val(),
            "compactness": self.compactness.get_cast_val()
        }

        return self.run_skimage(image, slic, **args)

    def reset(self):
        """Clean all data of segmentation. 
        """
        return self.reset_skimage()
class Felzenszwalb(Segmenter, SkimageSegmenter):
    """Run Felzenszwalb's method segmentation."""
    def __init__(self,
                 scale=100.0,
                 sigma=1.0,
                 min_size=20,
                 border_color='Yellow',
                 border_outline='No'):
        """Constructor.

        Parameters
        ----------
        scale : integer, float, default = 100.0
            Free parameter. Higher means larger clusters.
        sigma : float, optional, default = 1.0
            Width of Gaussian kernel used in preprocessing.
        min_size : integer, optional, default = 20
            Minimum component size. Enforced using postprocessing.
        border_color : string
            X11Color name of segment border color.
        border_outline : string
            If 'yes' double the size of segment border.
        """
        super(self.__class__, self).__init__(border_color, border_outline)

        self.scale = Config("Scale", scale, float)
        self.sigma = Config("Sigma", sigma, float)
        self.min_size = Config("Min Size", min_size, int)

    def get_config(self):
        """Return configuration of segmenter. 
        
        Returns
        -------
        config : OrderedDict
            Current configs of segmenter.
        """
        felzenszwalb_config = OrderedDict()

        felzenszwalb_config["scale"] = self.scale
        felzenszwalb_config["sigma"] = self.sigma
        felzenszwalb_config["min_size"] = self.min_size
        felzenszwalb_config["border_color"] = self.border_color
        felzenszwalb_config["border_outline"] = self.border_outline

        return felzenszwalb_config

    def set_config(self, configs):
        """Update configuration of segmenter. 
        
        Parameters
        ----------
        configs : OrderedDict
            New configs of segmenter.
        """
        self.scale = Config.nvl_config(configs["scale"], self.scale)
        self.sigma = Config.nvl_config(configs["sigma"], self.sigma)
        self.min_size = Config.nvl_config(configs["min_size"], self.min_size)
        self.border_color = Config.nvl_config(configs["border_color"],
                                              self.border_color)
        self.border_outline = Config.nvl_config(configs["border_outline"],
                                                self.border_outline)

        self.border_outline.value = self.border_outline.value if self.border_outline.value == 'Yes' else 'No'

    def get_summary_config(self):
        """Return fomatted summary of configuration. 
        
        Returns
        -------
        summary : string
            Formatted string with summary of configuration.
        """
        felzenszwalb_config = OrderedDict()

        felzenszwalb_config[self.scale.label] = self.scale.value
        felzenszwalb_config[self.sigma.label] = self.sigma.value
        felzenszwalb_config[self.min_size.label] = self.min_size.value
        felzenszwalb_config[self.border_color.label] = self.border_color.value
        felzenszwalb_config[
            self.border_outline.label] = self.border_outline.value

        summary = ''
        for config in felzenszwalb_config:
            summary += "%s: %s\n" % (config, str(felzenszwalb_config[config]))

        return summary

    def get_list_segments(self):
        """Return a list with segments after apply segmentation. 
        
        Returns
        -------
        segments : list
            List of segments of segmented image.
        """
        return self.get_list_segments_skimage()

    def get_segment(self, px=0, py=0, idx_segment=None, path_to_mask=None):
        """Return a specified segment using a index or position in image. 
        
        Parameters
        ----------
        px : integer, optional, default = 0
            Segment point inside the image in x-axis.
        py : integer, optional, default = 0
            Segment point inside the image in y-axis.
        idx_segment : integer, optional, default = None
            Index of segment returned by previous call of this method.
            
        Returns
        -------
        segment : opencv 3-channel color image.
            Rectangle encompassing the segment image.
        size_segment : integer
            Number of pixels of segment.
        idx_segment : integer
            Index of segment if found, -1 otherwise.
        run_time : integer
            Running time spent in milliseconds.
        """
        return self.get_segment_skimage(px, py, idx_segment, path_to_mask)

    def paint_segment(self,
                      image,
                      color,
                      px=0,
                      py=0,
                      idx_segment=[],
                      border=True,
                      clear=False):
        """Paint a list of segments using a index or position in image.
        
        Parameters
        ----------
        image : opencv 3-channel color image.
            Segmented image.
        color : string
            X11Color name.
        px : integer, optional, default = 0
            Segment point inside the image in x-axis.
        py : integer, optional, default = 0
            Segment point inside the image in y-axis.
        idx_segment : list, optional, default = []
            List of segments.
        border : boolean, optional, default = True
            If true paint the border of segments with default color.
        clear : boolean, optional, default = False
            If true clear previous painting in the image.

        Returns
        -------
        new_image : opencv 3-channel color image.
            Painted image.
        run_time : integer
            Running time spent in milliseconds.
        """
        return self.paint_segment_skimage(image, color, px, py, idx_segment,
                                          border, clear)

    def run(self, image):
        """Perform the segmentation 
        
        Parameters
        ----------
        image : opencv 3-channel color image.
            Original image.
            
        Returns
        -------
        new_image : opencv 3-channel color image.
            Segmented image.
        run_time : integer
            Running time spent in milliseconds.
        """
        args = {
            "scale": self.scale.get_cast_val(),
            "sigma": self.sigma.get_cast_val(),
            "min_size": self.min_size.get_cast_val()
        }

        return self.run_skimage(image, felzenszwalb, **args)

    def reset(self):
        """Clean all data of segmentation. 
        """
        return self.reset_skimage()
Beispiel #3
0
class Quickshift(Segmenter, SkimageSegmenter):
    """Run Quickshift segmentation."""
    def __init__(self,
                 ratio=0.5,
                 kernel_size=2.0,
                 max_dist=10.0,
                 border_color='Yellow',
                 border_outline='No'):
        """Constructor.

        Parameters
        ----------
        ratio : float, optional, between 0 and 1, default = 0.5
            Balances color-space proximity and image-space proximity. Higher values give more weight to color-space.
        kernel_size : float, optional, default = 2.0
            Width of Gaussian kernel used in smoothing the sample density. Higher means fewer clusters.
        max_dist : float, optional, default = 10.0
            Cut-off point for data distances. Higher means fewer clusters.
        border_color : string
            X11Color name of segment border color.
        border_outline : string
            If 'yes' double the size of segment border.
        """
        super(self.__class__, self).__init__(border_color, border_outline)

        self.ratio = Config("Ratio [0-1]", ratio, float)
        self.kernel_size = Config("Kernel Size", kernel_size, float)
        #self.sigma = Config("Sigma", sigma, float)
        self.max_dist = Config("Max Dist", max_dist, float)

    def get_config(self):
        """Return configuration of segmenter. 
        
        Returns
        -------
        config : OrderedDict
            Current configs of segmenter.
        """
        quickshift_config = OrderedDict()

        quickshift_config["ratio"] = self.ratio
        quickshift_config["kernel_size"] = self.kernel_size
        #quickshift_config["sigma"] = self.sigma
        quickshift_config["max_dist"] = self.max_dist
        quickshift_config["border_color"] = self.border_color
        quickshift_config["border_outline"] = self.border_outline

        return quickshift_config

    def set_config(self, configs):
        """Update configuration of segmenter. 
        
        Parameters
        ----------
        configs : OrderedDict
            New configs of segmenter.
        """
        self.ratio = Config.nvl_config(configs["ratio"], self.ratio)
        self.kernel_size = Config.nvl_config(configs["kernel_size"],
                                             self.kernel_size)
        #self.sigma = Config.nvl_config(configs["sigma"], self.sigma)
        self.max_dist = Config.nvl_config(configs["max_dist"], self.max_dist)
        self.border_color = Config.nvl_config(configs["border_color"],
                                              self.border_color)
        self.border_outline = Config.nvl_config(configs["border_outline"],
                                                self.border_outline)

        self.ratio.value = self.ratio.value if self.ratio.value <= 1 else 1
        self.border_outline.value = self.border_outline.value if self.border_outline.value == 'Yes' else 'No'

    def get_summary_config(self):
        """Return fomatted summary of configuration. 
        
        Returns
        -------
        summary : string
            Formatted string with summary of configuration.
        """
        quickshift_config = OrderedDict()

        quickshift_config[self.ratio.label] = self.ratio.value
        quickshift_config[self.kernel_size.label] = self.kernel_size.value
        #quickshift_config[self.sigma.label] = self.sigma.value
        quickshift_config[self.max_dist.label] = self.max_dist.value
        quickshift_config[self.border_color.label] = self.border_color.value
        quickshift_config[
            self.border_outline.label] = self.border_outline.value

        summary = ''
        for config in quickshift_config:
            summary += "%s: %s\n" % (config, str(quickshift_config[config]))

        return summary

    def get_list_segments(self):
        """Return a list with segments after apply segmentation. 
        
        Returns
        -------
        segments : list
            List of segments of segmented image.
        """
        return self.get_list_segments_skimage()

    def get_segment(self, px=0, py=0, idx_segment=None, path_to_mask=None):
        """Return a specified segment using a index or position in image. 
        
        Parameters
        ----------
        px : integer, optional, default = 0
            Segment point inside the image in x-axis.
        py : integer, optional, default = 0
            Segment point inside the image in y-axis.
        idx_segment : integer, optional, default = None
            Index of segment returned by previous call of this method.
            
        Returns
        -------
        segment : opencv 3-channel color image.
            Rectangle encompassing the segment image.
        size_segment : integer
            Number of pixels of segment.
        idx_segment : integer
            Index of segment if found, -1 otherwise.
        run_time : integer
            Running time spent in milliseconds.
        """
        return self.get_segment_skimage(px, py, idx_segment, path_to_mask)

    def paint_segment(self,
                      image,
                      color,
                      px=0,
                      py=0,
                      idx_segment=[],
                      border=True,
                      clear=False):
        """Paint a list of segments using a index or position in image.
        
        Parameters
        ----------
        image : opencv 3-channel color image.
            Segmented image.
        color : string
            X11Color name.
        px : integer, optional, default = 0
            Segment point inside the image in x-axis.
        py : integer, optional, default = 0
            Segment point inside the image in y-axis.
        idx_segment : list, optional, default = []
            List of segments.
        border : boolean, optional, default = True
            If true paint the border of segments with default color.
        clear : boolean, optional, default = False
            If true clear previous painting in the image.

        Returns
        -------
        new_image : opencv 3-channel color image.
            Painted image.
        run_time : integer
            Running time spent in milliseconds.
        """
        return self.paint_segment_skimage(image, color, px, py, idx_segment,
                                          border, clear)

    def run(self, image):
        """Perform the segmentation 
        
        Parameters
        ----------
        image : opencv 3-channel color image.
            Original image.
            
        Returns
        -------
        new_image : opencv 3-channel color image.
            Segmented image.
        run_time : integer
            Running time spent in milliseconds.
        """
        args = {
            "ratio": self.ratio.get_cast_val(),
            "kernel_size": self.kernel_size.get_cast_val(),
            #"sigma": self.sigma.get_cast_val(),
            "max_dist": self.max_dist.get_cast_val()
        }

        return self.run_skimage(image, quickshift, **args)

    def reset(self):
        """Clean all data of segmentation. 
        """
        return self.reset_skimage()
class SkimageSegmenter(object):
    """Abstract class for segmenters implemented in skimage.segmentation."""

    __metaclass__ = ABCMeta

    # flag FORCE_OPT highly increases speed of method paint_segment_skimage but performs a flawed painting
    FORCE_OPT = True

    def __init__(self, border_color='Yellow', border_outline='No'):
        """Constructor.

        Parameters
        ----------
        border_color : string
            X11Color name of segment border color.
        border_outline : string
            If 'yes' double the size of segment border.
        """
        self.border_color = Config("Border Color", border_color, 'color')
        self.border_outline = Config("Border Outline", border_outline, str)

        self._segments = None
        self._original_image = None

    def get_list_segments_skimage(self):
        """Return a list with segments after apply segmentation. 
        
        Returns
        -------
        segments : list
            List of segments of segmented image.
        """
        if self._segments is None:
            return []

        # print(np.unique(self._segments))
        return np.unique(self._segments)

    def get_segment_skimage(self,
                            px=0,
                            py=0,
                            idx_segment=None,
                            path_to_mask=None):
        """Return a specified segment using a index or position in image. 
        
        Parameters
        ----------
        px : integer, optional, default = 0
            Segment point inside the image in x-axis.
        py : integer, optional, default = 0
            Segment point inside the image in y-axis.
        idx_segment : integer, optional, default = None
            Index of segment returned by previous call of this method.
            
        Returns
        -------
        segment : opencv 3-channel color image.
            Rectangle encompassing the segment image.
        size_segment : integer
            Number of pixels of segment.
        idx_segment : integer
            Index of segment if found, -1 otherwise.
        run_time : integer
            Running time spent in milliseconds.
        """
        # Check if segmentation was already performed
        if self._segments is None:
            return None, 0, -1, 0

        start_time = TimeUtils.get_time()

        # If idx_segment not passed, get the segment index using the points (px, py)
        if idx_segment is None:
            idx_segment = self._segments[py, px]

        # Create a mask, painting black all pixels outside of segment and white the pixels inside.
        mask_segment = np.zeros(self._original_image.shape[:2], dtype="uint8")
        mask_segment[self._segments == idx_segment] = 255

        minas_mask_segment = mask_segment = np.zeros(
            self._original_image.shape[:2], dtype="uint8")
        minas_mask_segment[self._segments == idx_segment] = 1
        # minas_idx_segment = idx_segment

        txt = np.loadtxt(path_to_mask)
        txt = np.add(txt, minas_mask_segment)
        np.savetxt(path_to_mask, txt, fmt='%d')

        print("Modified mask: ", path_to_mask)

        size_segment = mask_segment[self._segments == idx_segment].size

        segment = self._original_image.copy()
        segment = cv2.bitwise_and(segment, segment, mask=mask_segment)

        # Get the countours around the segment
        contours, _ = cv2.findContours(mask_segment, cv2.RETR_LIST,
                                       cv2.CHAIN_APPROX_SIMPLE)[-2:]

        m = -1
        max_contour = None
        for cnt in contours:
            if (len(cnt) > m):
                m = len(cnt)
                max_contour = cnt

        # Get the rectangle that encompasses the countour
        x, y, w, h = cv2.boundingRect(max_contour)
        segment = segment[y:y + h, x:x + w]

        end_time = TimeUtils.get_time()

        # Return the rectangle that encompasses the countour
        return segment, size_segment, idx_segment, (end_time - start_time)

    def paint_segment_skimage(self,
                              image,
                              color,
                              px=0,
                              py=0,
                              idx_segment=[],
                              border=True,
                              clear=False):
        """Paint a list of segments using a index or position in image.
        
        Parameters
        ----------
        image : opencv 3-channel color image.
            Segmented image.
        color : string
            X11Color name.
        px : integer, optional, default = 0
            Segment point inside the image in x-axis.
        py : integer, optional, default = 0
            Segment point inside the image in y-axis.
        idx_segment : list, optional, default = []
            List of segments.
        border : boolean, optional, default = True
            If true paint the border of segments with default color.
        clear : boolean, optional, default = False
            If true clear previous painting in the image.

        Returns
        -------
        new_image : opencv 3-channel color image.
            Painted image.
        run_time : integer
            Running time spent in milliseconds.
        """
        # Check if segmentation was already performed
        if self._segments is None:
            return image, 0

        start_time = TimeUtils.get_time()

        # If idx_segment not passed, get the segment index using the points (px, py)
        if len(idx_segment) == 0:
            idx_segment = [self._segments[py, px]]
        height, width, channels = self._original_image.shape

        # Create a mask, painting black all pixels outside of segments and white the pixels inside
        mask_segment = np.zeros(self._original_image.shape[:2], dtype="uint8")
        for idx in idx_segment:
            mask_segment[self._segments == idx] = 255
        mask_inv = cv2.bitwise_not(mask_segment)

        # Paint all pixels in original image with choosed color
        class_color = np.zeros((height, width, 3), np.uint8)
        class_color[:, :] = X11Colors.get_color(color)
        if SkimageSegmenter.FORCE_OPT == False:
            colored_image = cv2.addWeighted(self._original_image, 0.7,
                                            class_color, 0.3, 0)
        else:
            colored_image = cv2.addWeighted(image, 0.7, class_color, 0.3, 0)
        colored_image = cv2.bitwise_and(colored_image,
                                        colored_image,
                                        mask=mask_segment)

        # Create a new image keeping the painting only in pixels inside of segments
        new_image = image if clear == False else self._original_image
        new_image = cv2.bitwise_and(new_image, new_image, mask=mask_inv)
        mask_segment[:] = 255
        new_image = cv2.bitwise_or(new_image, colored_image, mask=mask_segment)

        # If border is true, paint the segments borders
        if border == True and SkimageSegmenter.FORCE_OPT == False:
            color = X11Colors.get_color_zero_one(
                self.border_color.get_cast_val())
            outline_color = color if self.border_outline.value == 'Yes' else None

            new_image = img_as_ubyte(
                mark_boundaries(img_as_float(new_image),
                                self._segments.astype(np.int8),
                                color=color,
                                outline_color=outline_color))

        end_time = TimeUtils.get_time()

        # Return painted image
        return new_image, (end_time - start_time)

    def run_skimage(self, image, method, **kwargs):
        """Perform the segmentation 
        
        Parameters
        ----------
        image : opencv 3-channel color image.
            Original image.
        method : function
            Method from skyimage that performs the image segmentation.
        **kwargs : keyword arguments
            Dict of the keyword args passed to the function.
    
        Returns
        -------
        new_image : opencv 3-channel color image.
            Segmented image.
        run_time : integer
            Running time spent in milliseconds.
        """
        self._original_image = image

        # Run the segmentation using the method passed
        start_time = TimeUtils.get_time()
        self._segments = method(img_as_float(image), **kwargs)
        end_time = TimeUtils.get_time()

        color = X11Colors.get_color_zero_one(self.border_color.get_cast_val())
        outline_color = color if self.border_outline.value == 'Yes' else None

        #  Ignore UserWarning: Possible precision loss when converting from float64 to uint8
        #  because the returned image is used just for visualization
        #  The original image, without loss, is stored in self._original_image
        return img_as_ubyte(
            mark_boundaries(image,
                            self._segments.astype(np.int8),
                            color=color,
                            outline_color=outline_color)), (end_time -
                                                            start_time)

    def reset_skimage(self):
        """Clean all data of segmentation. 
        """
        self._segments = None
        self._original_image = None