-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #136 from kostrykin/points2label/dev
Merge the `points2binaryimage` tool into `points2labelimage`
- Loading branch information
Showing
16 changed files
with
261 additions
and
56 deletions.
There are no files selected for viewing
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
../../macros/creators.xml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,47 +1,125 @@ | ||
import argparse | ||
import sys | ||
import os | ||
import warnings | ||
|
||
import giatools.pandas | ||
import numpy as np | ||
import pandas as pd | ||
import scipy.ndimage as ndi | ||
import skimage.io | ||
import skimage.segmentation | ||
|
||
|
||
def points2label(labels, shape, output_file=None, has_header=False, is_TSV=True): | ||
labelimg = np.zeros([shape[0], shape[1]], dtype=np.int32) | ||
def rasterize(point_file, out_file, shape, has_header=False, swap_xy=False, bg_value=0, fg_value=None): | ||
|
||
if is_TSV: | ||
if has_header: | ||
df = pd.read_csv(labels, sep='\t', skiprows=1, header=None) | ||
else: | ||
df = pd.read_csv(labels, sep='\t', header=None) | ||
else: | ||
img = np.full(shape, dtype=np.uint16, fill_value=bg_value) | ||
if os.path.exists(point_file) and os.path.getsize(point_file) > 0: | ||
|
||
# Read the tabular file with information from the header | ||
if has_header: | ||
df = pd.read_csv(labels, skiprows=1, header=None) | ||
df = pd.read_csv(point_file, delimiter='\t') | ||
|
||
pos_x_column = giatools.pandas.find_column(df, ['pos_x', 'POS_X']) | ||
pos_y_column = giatools.pandas.find_column(df, ['pos_y', 'POS_Y']) | ||
pos_x_list = df[pos_x_column].round().astype(int) | ||
pos_y_list = df[pos_y_column].round().astype(int) | ||
assert len(pos_x_list) == len(pos_y_list) | ||
|
||
try: | ||
radius_column = giatools.pandas.find_column(df, ['radius', 'RADIUS']) | ||
radius_list = df[radius_column] | ||
assert len(pos_x_list) == len(radius_list) | ||
except KeyError: | ||
radius_list = [0] * len(pos_x_list) | ||
|
||
try: | ||
label_column = giatools.pandas.find_column(df, ['label', 'LABEL']) | ||
label_list = df[label_column] | ||
assert len(pos_x_list) == len(label_list) | ||
except KeyError: | ||
label_list = list(range(1, len(pos_x_list) + 1)) | ||
|
||
# Read the tabular file without header | ||
else: | ||
df = pd.read_csv(labels, header=None) | ||
df = pd.read_csv(point_file, header=None, delimiter='\t') | ||
pos_x_list = df[0].round().astype(int) | ||
pos_y_list = df[1].round().astype(int) | ||
assert len(pos_x_list) == len(pos_y_list) | ||
radius_list = [0] * len(pos_x_list) | ||
label_list = list(range(1, len(pos_x_list) + 1)) | ||
|
||
# Optionally swap the coordinates | ||
if swap_xy: | ||
pos_x_list, pos_y_list = pos_y_list, pos_x_list | ||
|
||
for i in range(0, len(df)): | ||
a_row = df.iloc[i] | ||
labelimg[a_row[0], a_row[1]] = i + 1 | ||
# Perform the rasterization | ||
for y, x, radius, label in zip(pos_y_list, pos_x_list, radius_list, label_list): | ||
if fg_value is not None: | ||
label = fg_value | ||
|
||
if y < 0 or x < 0 or y >= shape[0] or x >= shape[1]: | ||
raise IndexError(f'The point x={x}, y={y} exceeds the bounds of the image (width: {shape[1]}, height: {shape[0]})') | ||
|
||
# Rasterize circle and distribute overlapping image area | ||
if radius > 0: | ||
mask = np.ones(shape, dtype=bool) | ||
mask[y, x] = False | ||
mask = (ndi.distance_transform_edt(mask) <= radius) | ||
|
||
# Compute the overlap (pretend there is none if the rasterization is binary) | ||
if fg_value is None: | ||
overlap = np.logical_and(img > 0, mask) | ||
else: | ||
overlap = np.zeros(shape, dtype=bool) | ||
|
||
# Rasterize the part of the circle which is disjoint from other foreground. | ||
# | ||
# In the current implementation, the result depends on the order of the rasterized circles if somewhere | ||
# more than two circles overlap. This is probably negligable for most applications. To achieve results | ||
# that are invariant to the order, first all circles would need to be rasterized independently, and | ||
# then blended together. This, however, would either strongly increase the memory consumption, or | ||
# require a more complex implementation which exploits the sparsity of the rasterized masks. | ||
# | ||
disjoint_mask = np.logical_xor(mask, overlap) | ||
if disjoint_mask.any(): | ||
img[disjoint_mask] = label | ||
|
||
# Distribute the remaining part of the circle | ||
if overlap.any(): | ||
dist = ndi.distance_transform_edt(overlap) | ||
foreground = (img > 0) | ||
img[overlap] = 0 | ||
img = skimage.segmentation.watershed(dist, img, mask=foreground) | ||
|
||
# Rasterize point (there is no overlapping area to be distributed) | ||
else: | ||
img[y, x] = label | ||
|
||
if output_file is not None: | ||
with warnings.catch_warnings(): | ||
warnings.simplefilter("ignore") | ||
skimage.io.imsave(output_file, labelimg, plugin='tifffile') | ||
else: | ||
return labelimg | ||
raise Exception("{} is empty or does not exist.".format(point_file)) # appropriate built-in error? | ||
|
||
with warnings.catch_warnings(): | ||
warnings.simplefilter("ignore") | ||
skimage.io.imsave(out_file, img, plugin='tifffile') # otherwise we get problems with the .dat extension | ||
|
||
|
||
if __name__ == "__main__": | ||
parser = argparse.ArgumentParser() | ||
parser.add_argument('label_file', type=argparse.FileType('r'), default=sys.stdin, help='label file') | ||
parser.add_argument('out_file', type=argparse.FileType('w'), default=sys.stdin, help='out file') | ||
parser.add_argument('org_file', type=argparse.FileType('r'), default=sys.stdin, help='input original file') | ||
parser.add_argument('--has_header', dest='has_header', type=bool, default=False, help='label file has header') | ||
parser.add_argument('--is_tsv', dest='is_tsv', type=bool, default=True, help='label file is TSV') | ||
args = parser.parse_args() | ||
parser.add_argument('point_file', type=argparse.FileType('r'), help='point file') | ||
parser.add_argument('out_file', type=str, help='out file (TIFF)') | ||
parser.add_argument('shapex', type=int, help='shapex') | ||
parser.add_argument('shapey', type=int, help='shapey') | ||
parser.add_argument('--has_header', dest='has_header', default=False, help='set True if point file has header') | ||
parser.add_argument('--swap_xy', dest='swap_xy', default=False, help='Swap X and Y coordinates') | ||
parser.add_argument('--binary', dest='binary', default=False, help='Produce binary image') | ||
|
||
original_shape = skimage.io.imread(args.org_file.name, plugin='tifffile').shape | ||
args = parser.parse_args() | ||
|
||
points2label(args.label_file.name, original_shape, args.out_file.name, args.has_header, args.is_tsv) | ||
rasterize( | ||
args.point_file.name, | ||
args.out_file, | ||
(args.shapey, args.shapex), | ||
has_header=args.has_header, | ||
swap_xy=args.swap_xy, | ||
fg_value=0xffff if args.binary else None, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
11.7555970149 10.4048507463 | ||
15 14 | ||
19 2 | ||
5 4 | ||
5 5 | ||
5 6 | ||
5 7 | ||
5 8 | ||
5 9 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
frame pos_x pos_y scale radius intensity | ||
1 85 32 1.33 3.77 18807.73 | ||
1 190 25 1.78 5.03 24581.44 | ||
1 137 26 1.44 4.09 19037.59 | ||
1 63 42 1.44 4.09 22390.80 | ||
1 107 44 1.33 3.77 23429.96 | ||
1 61 27 1.56 4.40 18052.18 | ||
1 158 39 1.44 4.09 18377.02 | ||
1 190 14 1.33 3.77 18548.86 | ||
1 182 33 1.78 5.03 26467.79 | ||
1 39 39 1.44 4.09 14782.43 | ||
1 169 26 1.33 3.77 14203.41 | ||
1 61 54 1.33 3.77 23248.06 | ||
1 95 52 1.33 3.77 21480.71 | ||
1 23 60 1.89 5.34 25203.43 | ||
1 84 24 1.56 4.40 16630.57 | ||
1 121 47 1.67 4.71 15459.11 | ||
1 66 49 1.11 3.14 23858.07 | ||
1 115 36 2.00 5.66 16389.10 | ||
1 55 51 1.33 3.77 23548.90 | ||
1 130 72 1.67 4.71 15769.02 | ||
1 117 23 1.33 3.77 16763.14 | ||
1 45 52 1.56 4.40 22877.61 | ||
1 36 71 1.56 4.40 20780.96 | ||
1 78 17 1.33 3.77 16844.51 | ||
1 101 38 1.56 4.40 21376.59 | ||
1 147 31 1.78 5.03 16597.14 | ||
1 163 55 2.00 5.66 18301.54 | ||
1 164 23 1.33 3.77 17073.82 | ||
1 150 24 1.56 4.40 15440.02 | ||
1 151 67 1.78 5.03 18419.96 | ||
1 26 53 2.00 5.66 20586.01 | ||
1 79 62 1.33 3.77 15232.88 | ||
1 69 17 1.11 3.14 15601.83 | ||
1 83 52 1.33 3.77 18315.00 | ||
1 16 54 2.00 5.66 22140.66 | ||
1 166 61 1.78 5.03 18488.78 | ||
1 163 43 1.44 4.09 16925.49 | ||
1 130 53 1.78 5.03 15101.96 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
pos_x pos_y radius label | ||
20 20 20 1 | ||
50 50 40 1 | ||
150 50 40 2 |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
../../macros/tests.xml |