def is_skin_hair_block(self, block, block_type): ''' Return true if the block (given by the argument 'block' which is the coordinate-tuple for the top-left corner) is a skin/hair-block - it is if a majority (as per the threshold attribute) of the pixels in the block are skin/hair colored. 'block_type' says whether we are testing for a skin block ('s') or a hair block ('h). ''' # Your code pyimage_object=PyImage(self.filename) k=pyimage_object.size() pixel_x=block[0] pixel_y=block[1] lst_skin=[] lst_hair=[] temp_x=0 while(pixel_x<k[0]): temp_y=0 while(pixel_y<k[1] and temp_y<self.block_size): rgb_a=pyimage_object.get_rgba(pixel_x,pixel_y) pixel_color=Color(rgb_a) if(self.is_skin(pixel_color)): lst_skin.append((pixel_x,pixel_y)) elif(self.is_hair(pixel_color)): lst_hair.append((pixel_x,pixel_y)) pixel_y+=1 temp_y+=1 pixel_x+=1 temp_x+=1 if(len(lst_skin)>self.majority*self.block_size and block_type=='s'): return True elif(len(lst_hair)>self.majority*self.block_size and block_type=='h'): return True else: return False
class FaceDetector(object): ''' classdocs ''' def __init__(self, filename, block_size=11, min_component_size=11, majority=0.56): ''' Constructor - keeps input image filename, image read from the file as a PyImage object, block size (in pixels), threshold to decide how many skin color pixels are required to declare a block as a skin-block and min number of blocks required for a component. The majority argument says what fraction of the block pixels must be skin/hair colored for the block to be a skin/hair block - the default value is 0.5 (half). ''' self.image = PyImage(filename) self.block_sz = block_size self.min_blocks = min_component_size self.fraction_pixel = majority def skin_green_limits(self, red): ''' Return the limits of normalized green given the normalized red component as a tuple (min, max) ''' return ((-0.776 * red * red + 0.5601 * red + 0.18), (-1.376 * red * red + 1.0743 * red + 0.2)) def is_skin(self, pixel_color): ''' Given the pixel color (as a Color object) return True if it represents the skin color Color is skin if hue in degrees is (> 240 or less than or equal to 20) and green is in the green limits and it is not white ''' hue = pixel_color.hue_degrees() abs_rgb = pixel_color.rgb_abs() green = pixel_color.g green_limits = self.skin_green_limits(pixel_color.r) if ((hue > 240 or hue <= 20) and (green > green_limits[0] and green < green_limits[1]) and abs_rgb != (255, 255, 255)): return True def is_hair(self, pixel_color): ''' Return True if the pixel color represents hair - it is if intensity < 80 and ((B-G)<15 or (B-R)<15 or hue is between 20 and 40) ''' hue = pixel_color.hue_degrees() intensity = pixel_color.intensity abs_rgb = pixel_color.rgb_abs() if (intensity < 80 and (abs_rgb[2] - abs_rgb[1] < 15) or (abs_rgb[2] - abs_rgb[0] < 15) or (hue > 20 and hue < 40)): return True def is_skin_hair_block(self, block, block_type): ''' Return true if the block (given by the argument 'block' which is the coordinate-tuple for the top-left corner) is a skin/hair-block - it is if a majority (as per the threshold attribute) of the pixels in the block are skin/hair colored. 'block_type' says whether we are testing for a skin block ('s') or a hair block ('h). ''' total_pixels = 0 if block_type == 's': num_pixels = 0 for width in range(block[0], block[0] + self.block_sz): for height in range(block[1], block[1] + self.block_sz): if 0 <= width < self.image.size( )[0] and 0 <= height < self.image.size()[1]: total_pixels += 1 pixel_cl = Color(self.image.get_rgba(width, height)) if self.is_skin(pixel_cl): num_pixels += 1 else: num_pixels = 0 for width in range(block[0], block[0] + self.block_sz): for height in range(block[1], block[1] + self.block_sz): if 0 <= width < self.image.size( )[0] and 0 <= height < self.image.size()[1]: total_pixels += 1 pixel_cl = Color(self.image.get_rgba(width, height)) if self.is_hair(pixel_cl): num_pixels += 1 if (float(num_pixels) / total_pixels >= self.fraction_pixel): return True def add_neighbour_blocks(self, block, graph): ''' Given a block (given by the argument 'block' which is the coordinate-tuple for the top-left corner) and a graph (could be a hair or a skin graph), add edges from the current block to its neighbours on the image that are already nodes of the graph Check blocks to the left, top-left and top of the current block and if any of these blocks is in the graph (means the neighbour is also of the same type - skin or hair) add an edge from the current block to the neighbour. ''' left_x = block[0] - self.block_sz left_y = block[1] topleft_x = block[0] - self.block_sz topleft_y = block[1] - self.block_sz top_x = block[0] top_y = block[1] - self.block_sz topright_x = block[0] + self.block_sz topright_y = block[1] - self.block_sz for (block_x, block_y) in ((left_x, left_y), (topleft_x, topleft_y), (top_x, top_y), (topright_x, topright_y)): if 0 <= block_x < self.image.size( )[0] and 0 <= block_y < self.image.size()[1]: block2 = (block_x, block_y) graph.add_edge(block, block2) def make_block_graph(self): ''' Return the skin and hair graphs - nodes are the skin/hair blocks respectively Initialize skin and hair graphs. For every block if it is a skin(hair) block add edges to its neighbour skin(hair) blocks in the corresponding graph For this to work the blocks have to be traversed in the top->bottom, left->right order ''' skin_graph = Graph() hair_graph = Graph() for x_cordinate in range(0, self.image.size()[0] - 1, self.block_sz): for y_cordinate in range(0, self.image.size()[1] - 1, self.block_sz): if self.is_skin_hair_block((x_cordinate, y_cordinate), 's'): skin_graph.add_node((x_cordinate, y_cordinate)) self.add_neighbour_blocks((x_cordinate, y_cordinate), skin_graph) if self.is_skin_hair_block((x_cordinate, y_cordinate), 'h'): hair_graph.add_node((x_cordinate, y_cordinate)) self.add_neighbour_blocks((x_cordinate, y_cordinate), hair_graph) return skin_graph, hair_graph def find_bounding_box(self, component): ''' Return the bounding box - a box is a pair of tuples - ((minx, miny), (maxx, maxy)) for the component Argument 'component' - is just the list of blocks in that component where each block is represented by the coordinates of its top-left pixel. ''' minx = component[0][0] miny = component[0][1] maxx = component[0][0] maxy = component[0][1] for i in range(0, len(component), 1): if component[i][0] < minx: minx = component[i][0] if component[i][1] < miny: miny = component[i][1] if component[i][0] > maxx: maxx = component[i][0] if component[i][1] > maxy: maxy = component[i][1] return ((minx, miny), (maxx, maxy)) def skin_hair_match(self, skin_box, hair_box): ''' Return True if the skin-box and hair-box given are matching according to one of the pre-defined patterns ''' if skin_box[0][0] in range(hair_box[0][0], hair_box[1][0]): if skin_box[1][0] in range(hair_box[0][0], hair_box[1][0]): if skin_box[0][1] in range(hair_box[0][1], hair_box[1][1]): return True #pattern 1,2,3,4,7,8,12,13 if skin_box[0][1] in range(hair_box[0][1], hair_box[1][1]): if skin_box[0][0] in range(hair_box[0][0], hair_box[1][0]): return True #pattern 6 elif skin_box[1][0] in range(hair_box[0][0], hair_box[1][0]): return True #pattern 5 if hair_box[0][1] in range(skin_box[0][1], skin_box[1][1]): if hair_box[1][1] in range(skin_box[0][1], skin_box[1][1]): if hair_box[1][0] in range(skin_box[0][0], skin_box[1][0]): return True elif hair_box[0][0] in range(skin_box[0][0], skin_box[1][0]): return True # 9, 10, 11 def detect_faces(self): ''' Main method - to detect faces in the image that this class was initialized with Return list of face boxes - a box is a pair of tuples - ((minx, miny), (maxx, maxy)) Algo: (i) Make block graph (ii) get the connected components of the graph (iii) filter the connected components (iv) find bounding box for each component (v) Look for matches between face and hair bounding boxes Return the list of face boxes that have matching hair boxes ''' skin_graph, hair_graph = self.make_block_graph() skin_comp1 = skin_graph.get_connected_components() hair_comp1 = hair_graph.get_connected_components() skin_comp = [] hair_comp = [] list1 = len(skin_comp1) for i in range(0, list1): if len(skin_comp1[i]) > self.min_blocks: skin_comp += [skin_comp1[i]] list1 -= 1 list1 = len(hair_comp1) for i in range(0, list1): if len(skin_comp1[i]) > self.min_blocks: hair_comp += [hair_comp1[i]] list1 -= 1 face_list = [] for skin in skin_comp: for hair in hair_comp: skin_box = self.find_bounding_box(skin) hair_box = self.find_bounding_box(hair) if self.skin_hair_match(skin_box, hair_box): face_list.append(skin_box) return face_list def mark_box(self, box, color): ''' Mark the box (same as in the above methods) with a given color (given as a raw triple) This is just a one-pixel wide line showing the box. ''' for i in range(box[0][0], box[1][0]): self.image.set(i, box[0][1], color) self.image.set(i, box[1][1], color) for i in range(box[0][1], box[1][1]): self.image.set(box[0][0], i, color) self.image.set(box[1][0], i, color) def mark_faces(self, marked_file): ''' Detect faces and mark each face detected -- mark the bounding box of each face in red and save the marked image in a new file ''' face_list = self.detect_faces() for i in face_list: self.mark_box(i, (255, 0, 0)) self.image.save(marked_file)
class FaceDetector(object): ''' classdocs ''' def __init__(self, filename, block_size = 5, min_component_size = 10, majority = 0.5): ''' Constructor - keeps input image filename, image read from the file as a PyImage object, block size (in pixels), threshold to decide how many skin color pixels are required to declare a block as a skin-block and min number of blocks required for a component. The majority argument says what fraction of the block pixels must be skin/hair colored for the block to be a skin/hair block - the default value is 0.5 (half). ''' self.input_image = PyImage(filename) self.block_size = block_size self.threshold = block_size * block_size * majority self.component_length = min_component_size self.majority = majority def skin_green_limits(self, red): ''' Return the limits of normalized green given the normalized red component as a tuple (min, max) ''' return ((-0.776*red.norm_r*red.norm_r + 0.5601*red.norm_r + 0.18), (-1.376*red.norm_r*red.norm_r + 1.0743*red.norm_r + 0.2)) def is_skin(self, pixel_color): ''' Given the pixel color (as a Color object) return True if it represents the skin color Color is skin if hue in degrees is (> 240 or less than or equal to 20) and green is in the green limits and it is not white ''' if((pixel_color.red > 95) and (pixel_color.green > 40) and (pixel_color.blue > 20) and ((max(pixel_color.red, pixel_color.green, pixel_color.blue)- min(pixel_color.red, pixel_color.green, pixel_color.blue)) > 15 ) and (pixel_color.red-pixel_color.green > 15) and (pixel_color.red > pixel_color.green)\ and (pixel_color.red > pixel_color.blue)): return True def is_hair(self, pixel_color): ''' Return True if the pixel color represents hair - it is if intensity < 80 and ((B-G)<15 or (B-R)<15 or hue is between 20 and 40) ''' if (pixel_color.intensity < 80 and ((pixel_color.norm_b - pixel_color.norm_g < 15) or (pixel_color.norm_b - pixel_color.norm_r < 15) or pixel_color.hue() in range (20, 41))): return True return False def is_skin_hair_block(self, block, block_type): ''' Return true if the block (given by the argument 'block' which is the coordinate-tuple for the top-left corner) is a skin/hair-block - it is if a majority (as per the threshold attribute) of the pixels in the block are skin/hair colored. 'block_type' says whether we are testing for a skin block ('s') or a hair block ('h). ''' block_check = 0 pixelx = block[0] pixely = block[1] for pixelx in range (pixelx, pixelx + self.block_size ): for pixely in range (pixely, pixely + self.block_size): if self.input_image.get_rgba(pixelx, pixely) == None: continue color_block = Color(self.input_image.get_rgba(pixelx, pixely)) if (self.is_skin(color_block) and block_type == 's'): block_check += 1 elif (self.is_hair(color_block) and block_type == 'h'): block_check += 1 return block_check >= self.threshold def add_neighbour_blocks(self, block, graph): ''' Given a block (given by the argument 'block' which is the coordinate-tuple for the top-left corner) and a graph (could be a hair or a skin graph), add edges from the current block to its neighbours on the image that are already nodes of the graph Check blocks to the left, top-left and top of the current block and if any of these blocks is in the graph (means the neighbour is also of the same type - skin or hair) add an edge from the current block to the neighbour. ''' for direction in ((-self.block_size, 0), (-self.block_size, -self.block_size), (0, -self.block_size), (self.block_size, -self.block_size)): if (graph.is_node((block[0] + direction[0], block[1] + direction[1]))): graph.add_directed_edge(block, (block[0] + direction[0], block[1] + direction[1])) def make_block_graph(self): ''' Return the skin and hair graphs - nodes are the skin/hair blocks respectively Initialize skin and hair graphs. For every block if it is a skin(hair) block add edges to its neighbour skin(hair) blocks in the corresponding graph For this to work the blocks have to be traversed in the top->bottom, left->right order ''' comparison = lambda x, y : (1 if (x[0] > y[0]) else (0 if x[0]==y[0] else -1)) skin_graph = Graph(comparison) hair_graph = Graph(comparison) pixelx = 0 pixely = 0 while pixely <= (self.input_image.size()[1] - self.block_size): while pixelx <= (self.input_image.size()[0] - self.block_size): if self.is_skin_hair_block((pixelx, pixely), 's'): skin_graph.add_node((pixelx, pixely)) self.add_neighbour_blocks((pixelx, pixely), skin_graph) elif self.is_skin_hair_block((pixelx, pixely), 'h'): hair_graph.add_node((pixelx, pixely)) self.add_neighbour_blocks((pixelx, pixely), hair_graph) pixelx += self.block_size pixelx = 0 pixely += self.block_size return skin_graph, hair_graph def find_bounding_box(self, component): ''' Return the bounding box - a box is a pair of tuples - ((minx, miny), (maxx, maxy)) for the component Argument 'component' - is just the list of blocks in that component where each block is represented by the coordinates of its top-left pixel. ''' pixelx_list = [] pixely_list = [] for nodes in component: pixelx_list.append(nodes[0]) pixely_list.append(nodes[1]) return (((min(pixelx_list), min(pixely_list)), (max(pixelx_list), max(pixely_list)))) def inside(self, corners, box): ''' Check if a given coordinate lies inside the given box ''' #print corners for corner in corners: if ((corner[0] >= box[0][0] and corner[1] >= box[0][1]) and (corner[0] <= box[1][0] and corner[1] <= box[1][1])): return True return False def skin_hair_match(self, skin_box, hair_box): ''' Return True if the skin-box and hair-box given are matching according to one of the pre-defined patterns ''' corner = [(skin_box[0][0], skin_box[0][1]), (skin_box[0][0], skin_box[1][1]), (skin_box[1][0], skin_box[0][1]), (skin_box[1][0], skin_box[1][1])] if (self.inside(corner, hair_box)): return True elif skin_box[0][1] == hair_box[1][1]: return True else: return False def detect_faces(self): ''' Main method - to detect faces in the image that this class was initialized with Return list of face boxes - a box is a pair of tuples - ((minx, miny), (maxx, maxy)) Algo: (i) Make block graph (ii) get the connected components of the graph (iii) filter the connected components (iv) find bounding box for each component (v) Look for matches between face and hair bounding boxes Return the list of face boxes that have matching hair boxes ''' skin_graph, hair_graph = self.make_block_graph() skin_components = skin_graph.get_connected_components() hair_components = hair_graph.get_connected_components() filtered_skin = [] filtered_hair = [] for component in skin_components: if len(component) >= self.component_length: filtered_skin.append(component) for component in hair_components: if len(component) >= self.component_length: filtered_hair.append(component) bound_face = [] bound_hair = [] for block in filtered_skin: bound_face.append(self.find_bounding_box(block)) for block in filtered_hair: bound_hair.append(self.find_bounding_box(block)) del filtered_skin, filtered_hair face_box = [] for component in bound_face: for match in bound_hair: if (self.skin_hair_match(component, match) == True): face_box.append(component) return face_box def mark_box(self, box, color): ''' Mark the box (same as in the above methods) with a given color (given as a raw triple) This is just a one-pixel wide line showing the box. ''' for pixelx in range(box[0][0], box[1][0]): self.input_image.set(pixelx, box[0][1], color) for pixelx in range(box[0][0], box[1][0]): self.input_image.set(pixelx, box[1][1], color) for pixely in range(box[0][1], box[1][1]): self.input_image.set(box[0][0], pixely, color) for pixely in range(box[0][1], box[1][1]): self.input_image.set(box[1][0], pixely, color) def mark_faces(self, marked_file): ''' Detect faces and mark each face detected -- mark the bounding box of each face in red and save the marked image in a new file ''' face_box = self.detect_faces() for box in face_box: self.mark_box(box, (255, 0, 0)) self.input_image.save(marked_file)
class FaceDetector(object): ''' classdocs ''' def __init__(self, filename, block_size=5, min_component_size=15, majority=0.5): ''' Constructor - keeps input image filename, image read from the file as a PyImage object, block size (in pixels), threshold to decide how many skin color pixels are required to declare a block as a skin-block and min number of blocks required for a component. The majority argument says what fraction of the block pixels must be skin/hair colored for the block to be a skin/hair block - the default value is 0.5 (half). ''' # Your code self.filename = filename self.block_size = block_size self.min_component_size = min_component_size self.majority = majority self.skin = Graph() self.hair = Graph() self.pyim = PyImage(filename) def skin_green_limits(self, red): ''' Return the limits of normalized green given the normalized red component as a tuple (min, max) ''' return ((-0.776 * red * red + 0.5601 * red + 0.1766), (-1.376 * red * red + 1.0743 * red + 0.1452)) def is_skin(self, pixel_color): ''' Given the pixel color (as a Color object) return True if it represents the skin color Color is skin if hue in degrees is (> 240 or less than or equal to 20) and green is in the green limits and it is not white ''' # Your code color = Color(pixel_color) hue = color.hue_degrees() W = (color.R - 0.33) * (color.R - 0.33) + (color.G - 0.33) * (color.G - 0.33) green_limits = self.skin_green_limits(color.R) cond1 = (hue > 240 or hue <= 20) cond2 = green_limits[0] < color.G and color.G < green_limits[1] cond3 = color.rgb_abs()[0] < 230 and color.rgb_abs( )[1] < 230 and color.rgb_abs()[2] < 230 cond4 = 0.6 > color.R and color.R > 0.2 if cond1 and cond2 and cond3 and cond4 and W > 0.0004: return True return False def is_hair(self, pixel_color): ''' Return True if the pixel color represents hair - it is if intensity < 80 and ((B-G)<15 or (B-R)<15 or hue is between 20 and 40) ''' # Your code color = Color(pixel_color) hue = color.hue_degrees() R = pixel_color[0] G = pixel_color[1] B = pixel_color[2] if ((20 <= hue and hue <= 40) or (B - G) < 15 or (B - R) < 15) and color.intensity < 80: return True return False def is_skin_hair_block(self, block, block_type): ''' Return true if the block (given by the argument 'block' which is the coordinate-tuple for the top-left corner) is a skin/hair-block - it is if a majority (as per the threshold attribute) of the pixels in the block are skin/hair colored. 'block_type' says whether we are testing for a skin block ('s') or a hair block ('h). ''' # Your code count_pixels = 0 for pixely in range(block[1], block[1] + self.block_size): for pixelx in range(block[0], block[0] + self.block_size): if pixelx < self.pyim.size()[0] and pixely < self.pyim.size( )[1]: color = self.pyim.get_rgba(pixelx, pixely) if block_type == 's' and self.is_skin(color): count_pixels += 1 elif block_type == 'h' and self.is_hair(color): count_pixels += 1 if ((count_pixels * 1.0) / (self.block_size * self.block_size * 1.0)) >= self.majority: return True return False def add_neighbour_blocks(self, block, graph): ''' Given a block (given by the argument 'block' which is the coordinate-tuple for the top-left corner) and a graph (could be a hair or a skin graph), add edges from the current block to its neighbours on the image that are already nodes of the graph Check blocks to the left, top-left and top of the current block and if any of these blocks is in the graph (means the neighbour is also of the same type - skin or hair) add an edge from the current block to the neighbour. ''' # Your code valid_rangeX = range(self.pyim.size()[0]) valid_rangeY = range(self.pyim.size()[1]) length = self.block_size if self.is_skin_hair_block(block, 's'): if (block[0] - length) in valid_rangeX and self.is_skin_hair_block( (block[0] - length, block[1]), 's'): self.skin.add_edge((block[0] - length, block[1]), block) if (block[0] - length) in valid_rangeX and ( block[1] - length) in valid_rangeY and self.is_skin_hair_block( (block[0] - length, block[1] - length), 's'): self.skin.add_edge((block[0] - length, block[1] - length), block) if (block[1] - length) in valid_rangeY and self.is_skin_hair_block( (block[0], block[1] - length), 's'): self.skin.add_edge((block[0], block[1] - length), block) if (block[0] + length) in valid_rangeX and ( block[1] - length) in valid_rangeY and self.is_skin_hair_block( (block[0] + length, block[1] - length), 's'): self.skin.add_edge((block[0] + length, block[1] - length), block) elif self.is_skin_hair_block(block, 'h'): #self.hair.add_node(block) if (block[0] - length) in valid_rangeX and self.is_skin_hair_block( (block[0] - length, block[1]), 'h'): self.hair.add_edge((block[0] - length, block[1]), block) if (block[0] - length) in valid_rangeX and ( block[1] - length) in valid_rangeY and self.is_skin_hair_block( (block[0] - length, block[1] - length), 'h'): self.hair.add_edge((block[0] - length, block[1] - length), block) if (block[1] - length) in valid_rangeY and self.is_skin_hair_block( (block[0], block[1] - length), 'h'): self.hair.add_edge((block[0], block[1] - length), block) if (block[0] + length) in valid_rangeX and ( block[1] - length) in valid_rangeY and self.is_skin_hair_block( (block[0] + length, block[1] - length), 'h'): self.hair.add_edge((block[0] + length, block[1] - length), block) def make_block_graph(self): ''' Return the skin and hair graphs - nodes are the skin/hair blocks respectively Initialize skin and hair graphs. For every block if it is a skin(hair) block add edges to its neighbour skin(hair) blocks in the corresponding graph For this to work the blocks have to be traversed in the top->bottom, left->right order ''' # Your code for col in range(0, self.pyim.size()[1], self.block_size): for row in range(0, self.pyim.size()[0], self.block_size): if self.is_skin_hair_block((row, col), 's'): self.skin.add_node((row, col)) self.add_neighbour_blocks((row, col), self.skin.adjacency) elif self.is_skin_hair_block((row, col), 'h'): self.hair.add_node((row, col)) self.add_neighbour_blocks((row, col), self.hair.adjacency) def find_bounding_box(self, component): ''' Return the bounding box - a box is a pair of tuples - ((minx, miny), (maxx, maxy)) for the component Argument 'component' - is just the list of blocks in that component where each block is represented by the coordinates of its top-left pixel. ''' # Your code minx = miny = maxx = maxy = component[0][0] for tup in component: if tup[0] > maxx: maxx = tup[0] if tup[0] < minx: minx = tup[0] if tup[1] > maxy: maxy = tup[1] if tup[1] < miny: miny = tup[1] return ((minx, miny), (maxx, maxy)) def skin_hair_match(self, skin_box, hair_box): ''' Return True if the skin-box and hair-box given are matching according to one of the pre-defined patterns ''' # Your code hair_minx = hair_box[0][0] hair_miny = hair_box[0][1] hair_maxx = hair_box[1][0] hair_maxy = hair_box[1][1] skin_minx = skin_box[0][0] skin_miny = skin_box[0][1] skin_maxx = skin_box[1][0] skin_maxy = skin_box[1][1] '''if skin_miny == hair_maxy : return True if skin_miny > hair_miny and skin_minx > hair_minx and skin_maxy < hair_maxy and skin_maxx > hair_maxx: return True if hair_miny < skin_miny and skin_miny < hair_maxy: return True if hair_maxy == skin_maxy : return True if skin_miny <= hair_miny and hair_maxy <= skin_maxy: return True''' return True def detect_faces(self): ''' Main method - to detect faces in the image that this class was initialized with Return list of face boxes - a box is a pair of tuples - ((minx, miny), (maxx, maxy)) Algo: (i) Make block graph (ii) get the connected components of the graph (iii) filter the connected components (iv) find bounding box for each component (v) Look for matches between face and hair bounding boxes Return the list of face boxes that have matching hair boxes ''' # Your code index = 0 self.make_block_graph() skin_components = self.skin.get_connected_components() hair_components = self.hair.get_connected_components() skin_components = skin_components[::-1] hair_components = hair_components[::-1] for comp in skin_components: if len(comp) >= self.min_component_size: break index += 1 skin_components = skin_components[index:] index = 0 for comp in hair_components: if len(comp) >= self.min_component_size: break index += 1 hair_components = hair_components[index:] skin_boxes = [] hair_boxes = [] for component in skin_components: skin_boxes.append(self.find_bounding_box(component)) for component in hair_components: hair_boxes.append(self.find_bounding_box(component)) faces = [] for skin_box in skin_boxes: for hair_box in hair_boxes: if self.skin_hair_match(skin_box, hair_box): faces.append(skin_box) return faces, hair_boxes def mark_box(self, box, color): ''' Mark the box (same as in the above methods) with a given color (given as a raw triple) This is just a one-pixel wide line showing the box. ''' # Your code minx = box[0][0] miny = box[0][1] maxx = box[1][0] maxy = box[1][1] if minx > self.pyim.size()[0]: minx = self.pyim.size()[0] - 1 if maxx > self.pyim.size()[0]: maxx = self.pyim.size()[0] - 1 if miny > self.pyim.size()[1]: miny = self.pyim.size()[1] - 1 if maxy > self.pyim.size()[1]: maxy = self.pyim.size()[1] - 1 for pixel in range(minx, maxx + 1): self.pyim.set(pixel, miny, color) for pixel in range(minx, maxx + 1): self.pyim.set(pixel, maxy, color) for pixel in range(miny, maxy + 1): self.pyim.set(minx, pixel, color) for pixel in range(miny, maxy + 1): self.pyim.set(maxx, pixel, color) def mark_faces(self, marked_file): ''' Detect faces and mark each face detected -- mark the bounding box of each face in red and save the marked image in a new file ''' # Your code faces, hair = self.detect_faces() for box in faces: self.mark_box(box, (255, 0, 0)) '''for box in hair: self.mark_box(box, (0, 255, 0))''' self.pyim.save(marked_file)