def generate_chromosome_cluster(karyotyping_image, save_dir=None, popup=None): chromosome_size = 256 chromosomes = data_utils.process_karyotyping_image(karyotyping_image, verbose=True) chromosome_cluster = 255 - np.zeros( shape=(chromosome_size * 7, chromosome_size * 7, 3), dtype='uint8') i, j = 0, 0 for chromosome in chromosomes: chromosome = cv2.resize(chromosome, (256, 256)) chromosome_cluster[i * chromosome_size: (i + 1) * chromosome_size, j * chromosome_size: (j + 1) * chromosome_size] = \ chromosome[0:chromosome_size, 0:chromosome_size] # this is equivalent to 2 for-loops j += 1 i += int(j / 7) j = j % 7 if save_dir is not None: general_utils.create_directory(save_dir) cv2.imwrite(save_dir + "/chromosome_cluster.bmp", chromosome_cluster) return chromosome_cluster
def run(image_file, save_dir, model_path): general_utils.create_directory(save_dir + "/pipeline") image = Pipeline.read_image(image_file) image = Pipeline.generate_chromosome_cluster( image, save_dir=save_dir + "/pipeline/1_generate_chromosome_cluster") chromosomes = Pipeline.extract_chromosomes( image, save_dir=save_dir + "/pipeline/2_extract_chromosomes") straightened_chromosomes = Pipeline.straighten_chromosomes( chromosomes, save_dir=save_dir + "/pipeline/3_straighten_chromosomes") interesting_points = Pipeline.detect_interesting_points( straightened_chromosomes, save_dir=save_dir + "/pipeline/4_detect_interesting_points", model_path=model_path) classified_chromosomes = Pipeline.classify_chromosomes( straightened_chromosomes, interesting_points) karyotyping_image = Pipeline.organize_chromosomes( classified_chromosomes, save_dir=save_dir + "/pipeline/5_organize_chromosomes") return karyotyping_image
def image_files_to_bounding_box_csv(image_files, labels, csv_dir, prefix="", verbose=False): general_utils.create_directory(csv_dir) boxes = list() for image_file in image_files: image = image_utils.read_image(image_file, cmap="rgb") box = image_utils.get_chromosome_bounding_box(image) boxes.append(box) train_data, val_data, test_data = data_utils.split_multiple_data_lists( [image_files, boxes, labels]) annotations_train_file = csv_dir + "/" + prefix + "annotations_train.csv" image_and_bounding_boxes_to_csv(*train_data, annotations_train_file) annotations_val_file = csv_dir + "/" + prefix + "annotations_val.csv" image_and_bounding_boxes_to_csv(*val_data, annotations_val_file) annotations_test_file = csv_dir + "/" + prefix + "annotations_test.csv" image_and_bounding_boxes_to_csv(*test_data, annotations_test_file) class_mapping = [[str(i), i] for i in range(len(labels))] class_mapping_file = csv_dir + "/" + prefix + "class_mapping.csv" general_utils.write_list_to_csv(class_mapping, class_mapping_file) if verbose: print("Train: ", annotations_train_file) print("Validation: ", annotations_val_file) print("Test: ", annotations_test_file) print("Class mapping:", class_mapping_file)
def extract_chromosomes(image, save_dir=None, popup=None): chromosomes = data_utils.process_karyotyping_image(image) if save_dir is not None: general_utils.create_directory(save_dir) for idx in range(len(chromosomes)): cv2.imwrite(save_dir + "/" + str(idx + 1) + ".bmp", chromosomes[idx]) return chromosomes
def straighten_chromosomes(chromosomes, save_dir=None, popup=None): num_chromosome = len(chromosomes) """ Handle popup """ popup_counter = 1 if popup is not None: popup.set_text("0/" + str(num_chromosome) + " chromosomes processed.") straightened_chromosomes = list() for idx in range(num_chromosome): chromosome = chromosomes[idx].copy() gray = cv2.cvtColor(chromosome, cv2.COLOR_RGB2GRAY) _, binary = cv2.threshold(gray, 254, 255, cv2.THRESH_BINARY_INV) # get 2 end points of the best line x1, y1, x2, y2 = image_utils.find_best_line_hough_transform(binary) # make the first point higher than the second point if y1 > y2: x1, x2 = math_utils.swap(x1, x2) y1, y2 = math_utils.swap(y1, y2) angle = math_utils.get_angle_between_two_points([x1, y1], [x2, y2]) straightened_chromosome = image_utils.rotate_image( chromosome, angle + 90) if save_dir is not None: general_utils.create_directory(save_dir) chromosome_with_line = cv2.line(chromosome.copy(), (x1, y1), (x2, y2), (0, 255, 0), 2) straightened_line = image_utils.rotate_points( [[x1, y1], [x2, y2]], angle + 90, shape=chromosome.shape) rotated_x1, rotated_y1 = straightened_line[0] rotated_x2, rotated_y2 = straightened_line[1] straightened_chromosome_with_line = cv2.line( straightened_chromosome.copy(), (rotated_x1, rotated_y1), (rotated_x2, rotated_y2), (0, 255, 0), 2) """ Save images """ cv2.imwrite(save_dir + "/" + str(idx) + ".bmp", chromosome_with_line) cv2.imwrite(save_dir + "/" + str(idx) + "_straightened.bmp", straightened_chromosome_with_line) straightened_chromosomes.append(straightened_chromosome) """ Handle popup """ if popup is not None: popup.set_text( str(popup_counter) + "/" + str(num_chromosome) + " chromosomes processed.") popup_counter += 1 return straightened_chromosomes
def organize_chromosomes(chromosomes, debug=False, save_dir=None): template = 255 - np.zeros(shape=(800, 2048, 3), dtype='uint8') blocks = { "1": [0, 0, 256, 200], "2": [256, 0, 512, 200], "3": [512, 0, 768, 200], "4": [1536, 0, 1792, 200], "5": [1792, 0, 2048, 200], "6": [0, 200, 256, 400], "7": [256, 200, 512, 400], "8": [512, 200, 768, 400], "9": [768, 200, 1024, 400], "10": [1024, 200, 1280, 400], "11": [1280, 200, 1536, 400], "12": [1536, 200, 1792, 400], "13": [0, 400, 256, 600], "14": [256, 400, 512, 600], "15": [512, 400, 768, 600], "16": [1280, 400, 1536, 600], "17": [1536, 400, 1792, 600], "18": [1792, 400, 2048, 600], "19": [0, 600, 256, 800], "20": [256, 600, 512, 800], "21": [768, 600, 1024, 800], "22": [1024, 600, 1280, 800], "x": [1536, 600, 1792, 800], "y": [1792, 600, 2048, 800], } chromosome_ids = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "x", "y" ] for idx in chromosome_ids: x1, y1, x2, y2 = blocks[idx] block_image = image_utils.get_block_image(chromosomes[idx], idx, shape=(200, 256, 3)) template[y1:y2, x1:x2] = block_image if debug: image_utils.get_block_image(chromosomes[idx], idx, shape=(200, 256, 3)) if save_dir is not None: general_utils.create_directory(save_dir) cv2.imwrite(save_dir + "/karyotyping.bmp", template) return template
def classify_chromosomes(chromosomes, points, save_dir=None, popup=None): """ This function randomly classifies chromosomes. :param chromosomes: :param points: :param save_dir: :param popup: :return: """ # TODO: Remove this in the future if chromosomes is None: print("No chromosomes. Return None.") return None """ Default chromosome ids """ chromosome_ids = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "x", "y" ] """ Duplicate chromosomes ids (because of having 2 chromosomes/id, 'x' and 'y' excepted) and shuffle all """ all_chromosome_ids = chromosome_ids + chromosome_ids all_chromosome_ids.remove("x") all_chromosome_ids.remove("y") from random import shuffle shuffle(all_chromosome_ids) """ Put chromosomes to ids """ classified_chromosomes = dict() for i in range(len(chromosomes)): idx = all_chromosome_ids[i] if idx not in classified_chromosomes: classified_chromosomes[idx] = [chromosomes[i]] else: classified_chromosomes[idx].append(chromosomes[i]) if save_dir is not None: counter = 0 general_utils.create_directory(save_dir) for idx in chromosome_ids: for chromosome in classified_chromosomes[idx]: cv2.imwrite(save_dir + "/" + str(counter) + ".bmp", chromosome) counter += 1 return classified_chromosomes
def detect_interesting_points(chromosomes, model_path="default", verbose=False, save_dir=None, popup=None): """ Local import """ from script.pipeline.detection import detect_interesting_points, load_model interesting_points = list() model = load_model(model_path=model_path) for idx in range(len(chromosomes)): chromosome = chromosomes[idx] points, draw, image_with_points = detect_interesting_points( chromosome, model, verbose=verbose) if save_dir is not None: general_utils.create_directory(save_dir) cv2.imwrite(save_dir + "/" + str(idx + 1) + "_draw.bmp", draw) cv2.imwrite(save_dir + "/" + str(idx + 1) + "_points.bmp", image_with_points) interesting_points.append(points) return interesting_points
def process_karyotyping_images(directory, chromosome_type="xx", debug=False, load_karyotype_info=False, max_p=None, need_confirm=False): last_chromosome = chromosome_type[1] chromosome_ids = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, "x", "y" ] save_directory = directory + "/" + chromosome_type + "/chromosome" karyotype_directory = directory + "/" + chromosome_type if debug: print("Save directory: " + save_directory) print("Karyotype directory: " + karyotype_directory) general_utils.create_directory(save_directory) if not load_karyotype_info: # Create directories to store output images for idx in chromosome_ids: general_utils.create_directory(save_directory + "/" + str(idx)) karyotypes = dict() image_files = general_utils.get_all_files(karyotype_directory) for image_file in image_files: if not image_file.endswith(".bmp"): continue if debug: print(image_file) image = cv2.imread(karyotype_directory + "/" + image_file, 0) # ret, thresh = threshold.partial_otsu_threshold(image, minval=0, maxval=255, dark_background=False) ret, thresh = cv2.threshold(image, 254, 255, cv2.THRESH_BINARY_INV) # if debug: # image_utils.show_image(thresh) _, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) num_contour = len(contours) # Find area threshold - taking the 46-th largest area areas = list() for idx in range(num_contour): is_outer_contour = hierarchy[0][idx][3] == -1 if is_outer_contour: area = cv2.contourArea(contours[idx]) areas.append(area) areas.sort(reverse=True) if len(areas) < 46: print("Wrong at " + image_file) continue area_threshold = areas[45] - 0.01 chosen_contours = list() for idx in range(num_contour): contour = contours[idx] if cv2.contourArea(contour) < area_threshold: continue chosen_contours.append(contour) if len(chosen_contours) < 46: print("Wrong at " + image_file) continue contour_info = list() for contour in chosen_contours: x, y, w, h = cv2.boundingRect(contour) contour_info.append([x, y, w, h, contour]) def sorted_by(a, b): x_a, y_a, w_a, h_a, _ = a x_b, y_b, w_b, h_b, _ = b if (y_a + h_a) < y_b: return -1 if x_a < x_b: return -1 return 1 cmp = functools.cmp_to_key(sorted_by) contour_info.sort(key=cmp) if need_confirm: rgb_image = np.stack((image, ) * 3, axis=-1) image_utils.show_image(image_utils.get_image_with_contours( rgb_image, chosen_contours, thickness=-1), cmap=None) user_input = input() if "yes".startswith(user_input): karyotypes[image_file] = contour_info else: print("Skipping: " + image_file) else: rgb_image = np.stack((image, ) * 3, axis=-1) image_utils.show_image(image_utils.get_image_with_contours( rgb_image, chosen_contours, thickness=-1), cmap=None) karyotypes[image_file] = contour_info # Save data in case of bugs pickle.dump( karyotypes, open(directory + "/" + chromosome_type + "_karyotype_info.data", 'wb')) else: with open(directory + "/" + chromosome_type + "_karyotype_info.data", 'rb') as f: karyotypes = pickle.load(f) # Find maximum perimeter if max_p is None: max_p = -1 for idx in karyotypes.keys(): contour_info = karyotypes[idx] if len(contour_info) != 46: print("Skipping:" + idx) continue con_1 = contour_info[0][4] con_2 = contour_info[1][4] p_1 = cv2.arcLength(con_1, True) p_2 = cv2.arcLength(con_2, True) max_p = max(p_1, max_p) max_p = max(p_2, max_p) if debug: print("Max p: " + str(max_p)) # Resize all images according to max perimeter for image_file in karyotypes.keys(): image = cv2.imread(karyotype_directory + "/" + image_file, 0) contour_info = karyotypes[image_file] if debug: print(image_file) if len(contour_info) != 46: print("Skipping:" + image_file) continue # Get max perimeter of two chromosome 1 con_1 = contour_info[0][4] con_2 = contour_info[1][4] p_1 = cv2.arcLength(con_1, True) p_2 = cv2.arcLength(con_2, True) local_max_p = max(p_1, p_2) # Get scale according to above local max scale = max_p * 1.0 / local_max_p print(scale) component_size = 512 counter = 1 pixel_open = 0 for idx in range(len(contour_info)): x, y, w, h, contour = contour_info[idx] # open the bounding box a little bit x -= pixel_open y -= pixel_open w += pixel_open h += pixel_open # create a white image of size 512 white_image = 255 - np.zeros(shape=(component_size, component_size)) # calculate corresponding top-left point in white image new_x = int((component_size - w) / 2) new_y = int((component_size - h) / 2) # copy bounding box patch from karyotype image into white image white_image[new_y:(new_y + h), new_x:(new_x + w)] = image[y:(y + h), x:(x + w)] # rescale chromosome image white_image = cv2.resize( white_image, (int(component_size * scale), int(component_size * scale))) white_image = white_image.astype('uint8') # get the center patch of size 512 white_image = image_utils.get_center_sub_image(white_image, size=component_size) # get current chromosome name (1, 2, ..., x, y) chromosome_name = str(chromosome_ids[int(idx / 2)]) # the last chromosome name depends on what karyotype image (xx or xy) if idx == 45: chromosome_name = last_chromosome # save the patch contain only 1 chromosome cv2.imwrite( save_directory + "/" + chromosome_name + "/" + chromosome_type + "_" + image_file + "_" + str(idx), white_image) counter += 1