'''
Created on Feb 28, 2014

@author: Vance Zuo
'''

import argparse
import numpy as np
import cv2
import os
from math import sqrt, hypot

class SegmentedObject(object):
    '''
    A SegmentedObject attempts to represent an object from an image,
    based on a reference background image.
    
    Attributes:
        bg_img: Background image that does not contain object.
        fg_img: Foreground image of the same area as bg_img, but containing
                the object for detection.
        fg_mask: Foreground mask, with white pixels representing hypothesized 
                 foreground and black pixels representing definite background.
        color_mask: Foreground color mask, where black pixels represent areas 
                     to treat automatically as background. This can be used to 
                     prevent arms from being treated as part of the foreground 
                     object.
        rect_mask: Foreground rectangle mask, where black pixels represent
                   areas to treat automatically as background. This can be used
                   to establish a region of focus.
    '''
    
    def __init__(self, bg_path, fg_path, method="simple", color_range=None,
                 rectangle=None):
        '''
        Initiates SegmentedObject with user-specified background and foreground
        image paths.
        
        Args:
            bg_path: file path to background image.
            fg_path: file path to foreground image.
            method: (optional) algorithm to use to create the foreground mask. 
            rectangle: (optional) 4-tuple representing the foreground rectangle
                       mask to use.
            color_range: (optional) 2-tuple representing the color range for
                         the foreground color mask.
        '''

        self.bg_img = cv2.imread(bg_path)
        if self.bg_img is None:
            raise IOError("Background image not loaded successfully.")
        self.fg_img = cv2.imread(fg_path)
        if self.fg_img is None:
            raise IOError("Foreground image not loaded successfully.")
      
        # Blurring images smooths out noise 
        self.bg_img = cv2.bilateralFilter(self.bg_img, 5, 100, 100)
        self.fg_img = cv2.bilateralFilter(self.fg_img, 5, 100, 100)
        #self.bg_img = cv2.medianBlur(self.bg_img, 9)
        #self.fg_img = cv2.medianBlur(self.fg_img, 9)
        
        # Initalizes masks
        white_mask = cv2.bitwise_not(np.zeros(self.fg_img.shape[:-1], np.uint8))
        self.rect_mask = white_mask
        if not rectangle is None:
            self.set_rectangle(*rectangle)
        self.color_mask = white_mask
        if not color_range is None:
            self.set_ignore_color(*color_range)
        self.set_fg_mask_method(method)
        return
    
    def export_background(self, output_path):
        '''
        Writes the background image of the SegmentedObject to a file path
        specified by the user.
        
        Args:
            output_path: file path of output image.
        '''
        
        cv2.imwrite(output_path, self.bg_img)
        return
    
    def export_foreground(self, output_path):
        '''
        Writes the foreground image of the SegmentedObject to a file path
        specified by the user.
        
        Args:
            output_path: file path of output image.
        '''
        
        cv2.imwrite(output_path, self.fg_path)
        return
    
    def export_region_mask(self, output_path):
        '''
        Writes the region of interest of the SegmentedObject to a file path
        specified by the user. The region of interest denotes the area of the
        image considered as possible foreground (in white).
        
        Args:
            output_path: file path of output image.
        '''
        
        region_mask = cv2.bitwise_and(self.rect_mask, self.color_mask)
        cv2.imwrite(output_path, region_mask)
        return
    
    def export_region_segment(self, output_path):
        '''
        Applies the object mask of the SegmentedObject to its foreground image,
        and writes the result to a user-specified file path.
        
        Args:
            output_path: file path of output image.
        '''
        
        region_mask = cv2.bitwise_and(self.rect_mask, self.color_mask)
        segment = cv2.bitwise_and(self.fg_img, self.fg_img, mask=region_mask)
        cv2.imwrite(output_path, segment)
        return
    
    def export_object_mask(self, output_path):
        '''
        Computes the object mask of the SegmentedObject, and writes is to a 
        file path specified by the user.
        
        Args:
            output_path: file path of output image.
        '''
        
        cv2.imwrite(output_path, self.get_object_mask())
        return
    
    def export_object_segment(self, output_path, draw_rectangle=False):
        '''
        Applies the object mask of the SegmentedObject to its foreground image,
        and writes the result to a user-specified file path.
        
        Args:
            output_path: file path of output image.
        '''
        
        obj_mask = self.get_object_mask()
        segment = cv2.bitwise_and(self.fg_img, self.fg_img, mask=obj_mask)
        if draw_rectangle: