def __init__(self):
     self.skin_histogram = HistogramUV()
     self.non_skin_histogram = HistogramUV()
     self.skin_dist = ProbDist()
     self.theta_max = 0.4
     self.lower_boundary_skin = [0, 0, 0]
     self.upper_boundary_skin = [255, 255, 255]
     self.masks = []
class SkinClassifierUV:
    def __init__(self):
        self.skin_histogram = HistogramUV()
        self.non_skin_histogram = HistogramUV()
        self.skin_dist = ProbDist()
        self.theta_max = 0.4
        self.lower_boundary_skin = [0, 0, 0]
        self.upper_boundary_skin = [255, 255, 255]
        self.masks = []

    def load_rgb(self, url):
        return cv2.imread(url, 1)

    def load_yuv(self, url):
        img_in = cv2.imread(url, 1)
        img_out = cv2.cvtColor(img_in, cv2.COLOR_BGR2YUV)
        return img_out

    def learn_from_database(self):
        for i in range(1,60):
            # img_name = 'img (' + str(i) + ').jpg'
            img_name = 'img (' + str(i) + ').jpg'
            img_original = self.load_rgb("sfa_database/original/" + img_name)
            img_skin = self.load_rgb("sfa_database/skin_extracted/" + img_name)
            img_yuv = self.load_yuv("sfa_database/original/" + img_name)

            height, width, channels = img_original.shape
            v, u, y = cv2.split(img_yuv)

            for i in range(0, width):
                for j in range(0, height):
                    key = u[j][i]//8, v[j][i]//8
                    if self.is_background_color(img_skin[j][i]):
                        self.non_skin_histogram.fill_bin(key)
                    else:
                        self.skin_histogram.fill_bin(key)

            print("[LEARNING] " + img_name + " loaded")

        self.calculate_prob_dist()
        self.calculate_boundaries()

    def is_background_color(self, color):
        return color[0] == 0 and color[1] == 0 and color[2] == 0

    def calculate_prob_dist(self):
        for u in range(0,32):
            for v in range (0, 32):
                key = u, v
                is_skin = self.skin_histogram.get_probability(key)
                is_non_skin = self.non_skin_histogram.get_probability(key)

                if is_skin == 0 or is_non_skin == 0:
                    continue

                T_skin = self.skin_histogram.count / (self.skin_histogram.count + self.non_skin_histogram.count)
                T_non_skin = 1.0 - T_skin
                result = (is_skin * T_skin) / (is_skin * T_skin + is_non_skin * T_non_skin)
                self.skin_dist.fill_bin(key,result)
                print('bin: ', u, v, 'prob', result)

    def calculate_boundaries(self):
        self.masks = []
        U_min_bin = 0
        U_max_bin = 32
        V_min_bin = 0
        V_max_bin = 32
        U_skin_bins = []
        V_skin_bins = []
        temp = []

        # Collect bins with skin colors
        for u in range(0,32):
            for v in range(0,32):
                key = u, v
                if self.skin_dist.get_probability(key) > self.theta_max:
                    U_skin_bins.append(u)
                    V_skin_bins.append(v)
                    temp.append([u,v])

        U_min_bin = min(int(s) for s in U_skin_bins)
        V_min_bin = min(int(s) for s in V_skin_bins)
        U_max_bin = max(int(s) for s in U_skin_bins)
        V_max_bin = max(int(s) for s in V_skin_bins)

        # print('mins: ', U_min_bin, V_min_bin, 'maxs: ', U_max_bin, V_max_bin)
        # print(temp)

        for mask in temp:
            lower = np.array([mask[1]*8, mask[0]*8,0])
            upper = np.array([mask[1]*8 + 8, mask[0]*8 + 8,255])
            self.masks.append([lower, upper])

        # print(self.masks)

    def test(self):
        for i in range(57,65):
            img_name = 'img (' + str(i) + ').jpg'
            print('[TESTING]',img_name)
            img_yuv = self.load_yuv("sfa_database/original/" + img_name)

            height, width, channels = img_yuv.shape
            v, u, y = cv2.split(img_yuv)

            for i in range(0, width):
                for j in range(0, height):
                    key = u[j][i]//8, v[j][i]//8
                    prob = self.skin_dist.get_probability(key)
                    if(prob > self.theta_max):
                        img_yuv[j][i] = [255, 255, 255]

            cv2.imshow('image',img_yuv)
            cv2.waitKey(0)
            cv2.destroyAllWindows()


    def mark_skin(self, img_rgb):

        img_yuv = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2YUV)
        # e1 = cv2.getTickCount()
        ############## TEST ########################
        # just for one mask
        new_masks = []
        for mask in self.masks:
            new_masks.append(cv2.inRange(img_yuv, mask[0], mask[1]))

        final_mask = new_masks[0]
        for i in range(1, len(new_masks)):
            final_mask = cv2.bitwise_or(final_mask, new_masks[i])

        img_rgb = cv2.bitwise_and(img_rgb,img_rgb, mask = final_mask)

        # e2 = cv2.getTickCount()
        # t = (e2 - e1)/cv2.getTickFrequency()
        # print(t)

        return img_rgb

    def increase_theta(self):
        self.theta_max += 0.1
        print('theta_max:',self.theta_max)