Mercurial > repos > galaxyp > qupath_roi_splitter
comparison qupath_roi_splitter.py @ 2:7bee859bbd11 draft
planemo upload for repository hhttps://github.com/npinter/ROIsplitter commit 7391296e0c7c8d48b42a129d154b50b29fd41737
author | galaxyp |
---|---|
date | Thu, 11 Apr 2024 07:52:58 +0000 (9 months ago) |
parents | 064b53fd3131 |
children | 24ccdcfbabac |
comparison
equal
deleted
inserted
replaced
1:064b53fd3131 | 2:7bee859bbd11 |
---|---|
4 import geojson | 4 import geojson |
5 import numpy as np | 5 import numpy as np |
6 import pandas as pd | 6 import pandas as pd |
7 | 7 |
8 | 8 |
9 def draw_poly(input_df, input_img, col=(0, 0, 0)): | 9 def draw_poly(input_df, input_img, col=(0, 0, 0), fill=False): |
10 s = np.array(input_df) | 10 s = np.array(input_df) |
11 output_img = cv2.fillPoly(input_img, pts=np.int32([s]), color=col) | 11 if fill: |
12 output_img = cv2.fillPoly(input_img, pts=np.int32([s]), color=col) | |
13 else: | |
14 output_img = cv2.polylines(input_img, np.int32([s]), True, color=col, thickness=1) | |
12 return output_img | 15 return output_img |
16 | |
17 | |
18 def draw_roi(input_roi, input_img, fill): | |
19 if len(input_roi["geometry"]["coordinates"]) == 1: | |
20 # Polygon w/o holes | |
21 input_img = draw_poly(input_roi["geometry"]["coordinates"][0], input_img, fill=fill) | |
22 else: | |
23 first_roi = True | |
24 for sub_roi in input_roi["geometry"]["coordinates"]: | |
25 # Polygon with holes | |
26 if not isinstance(sub_roi[0][0], list): | |
27 if first_roi: | |
28 input_img = draw_poly(sub_roi, input_img, fill=fill) | |
29 first_roi = False | |
30 else: | |
31 # holes in ROI | |
32 input_img = draw_poly(sub_roi, input_img, col=(255, 255, 255), fill=fill) | |
33 else: | |
34 # MultiPolygon with holes | |
35 for sub_coord in sub_roi: | |
36 if first_roi: | |
37 input_img = draw_poly(sub_coord, input_img, fill=fill) | |
38 first_roi = False | |
39 else: | |
40 # holes in ROI | |
41 input_img = draw_poly(sub_coord, input_img, col=(255, 255, 255), fill=fill) | |
42 | |
43 return input_img | |
13 | 44 |
14 | 45 |
15 def split_qupath_roi(in_roi): | 46 def split_qupath_roi(in_roi): |
16 with open(in_roi) as file: | 47 with open(in_roi) as file: |
17 qupath_roi = geojson.load(file) | 48 qupath_roi = geojson.load(file) |
26 # create numpy array with white background | 57 # create numpy array with white background |
27 img = np.zeros((dim_plt[1], dim_plt[0], 3), dtype="uint8") | 58 img = np.zeros((dim_plt[1], dim_plt[0], 3), dtype="uint8") |
28 img.fill(255) | 59 img.fill(255) |
29 | 60 |
30 for i, roi in enumerate(qupath_roi["features"]): | 61 for i, roi in enumerate(qupath_roi["features"]): |
31 if roi["properties"]["classification"]["name"] == cell_type: | 62 if not args.all: |
32 if len(roi["geometry"]["coordinates"]) == 1: | 63 if "classification" not in roi["properties"]: |
33 # Polygon w/o holes | 64 continue |
34 img = draw_poly(roi["geometry"]["coordinates"][0], img) | 65 if roi["properties"]["classification"]["name"] == cell_type: |
35 else: | 66 img = draw_roi(roi, img, args.fill) |
36 first_roi = True | 67 else: |
37 for sub_roi in roi["geometry"]["coordinates"]: | 68 img = draw_roi(roi, img, args.fill) |
38 # Polygon with holes | |
39 if not isinstance(sub_roi[0][0], list): | |
40 if first_roi: | |
41 img = draw_poly(sub_roi, img) | |
42 first_roi = False | |
43 else: | |
44 # holes in ROI | |
45 img = draw_poly(sub_roi, img, col=(255, 255, 255)) | |
46 else: | |
47 # MultiPolygon with holes | |
48 for sub_coord in sub_roi: | |
49 if first_roi: | |
50 img = draw_poly(sub_coord, img) | |
51 first_roi = False | |
52 else: | |
53 # holes in ROI | |
54 img = draw_poly(sub_coord, img, col=(255, 255, 255)) | |
55 | 69 |
56 # get all black pixel | 70 # get all black pixel |
57 coords_arr = np.column_stack(np.where(img == (0, 0, 0))) | 71 coords_arr = np.column_stack(np.where(img == (0, 0, 0))) |
58 | 72 |
59 # remove duplicated rows | 73 # remove duplicated rows |
61 | 75 |
62 # remove last column | 76 # remove last column |
63 coords_arr_xy = np.delete(coords_arr_xy, 2, axis=1) | 77 coords_arr_xy = np.delete(coords_arr_xy, 2, axis=1) |
64 | 78 |
65 # to pandas and rename columns to x and y | 79 # to pandas and rename columns to x and y |
66 coords_df = pd.DataFrame(coords_arr_xy, columns=['x', 'y']) | 80 coords_df = pd.DataFrame(coords_arr_xy, columns=['y', 'x']) |
81 | |
82 # reorder columns | |
83 coords_df = coords_df[['x', 'y']] | |
67 | 84 |
68 # drop duplicates | 85 # drop duplicates |
69 coords_df = coords_df.drop_duplicates( | 86 coords_df = coords_df.drop_duplicates( |
70 subset=['x', 'y'], | 87 subset=['x', 'y'], |
71 keep='last').reset_index(drop=True) | 88 keep='last').reset_index(drop=True) |
74 | 91 |
75 | 92 |
76 if __name__ == "__main__": | 93 if __name__ == "__main__": |
77 parser = argparse.ArgumentParser(description="Split ROI coordinates of QuPath TMA annotation by cell type (classfication)") | 94 parser = argparse.ArgumentParser(description="Split ROI coordinates of QuPath TMA annotation by cell type (classfication)") |
78 parser.add_argument("--qupath_roi", default=False, help="Input QuPath annotation (GeoJSON file)") | 95 parser.add_argument("--qupath_roi", default=False, help="Input QuPath annotation (GeoJSON file)") |
96 parser.add_argument("--fill", action="store_true", required=False, help="Fill pixels in ROIs") | |
79 parser.add_argument('--version', action='version', version='%(prog)s 0.1.0') | 97 parser.add_argument('--version', action='version', version='%(prog)s 0.1.0') |
98 parser.add_argument("--all", action="store_true", required=False, help="Extracts all ROIs") | |
80 args = parser.parse_args() | 99 args = parser.parse_args() |
81 | 100 |
82 if args.qupath_roi: | 101 if args.qupath_roi: |
83 split_qupath_roi(args.qupath_roi) | 102 split_qupath_roi(args.qupath_roi) |