-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Image segmentation view improvement #1131
Image segmentation view improvement #1131
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -6,6 +6,8 @@ | |||
import matplotlib as mpl | |||
import numpy as np | |||
import PIL.Image | |||
import json | |||
import skfmm |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lukeyeager usually prefers seeing non-standard package imports below (line 14)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gheinrich, this seems PEP8 compliant (https://www.python.org/dev/peps/pep-0008/#imports) in the third party block.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just move json
up above import os
if self.class_labels: | ||
text = "%s (%s)" % (text, self.class_labels[int(c)]) | ||
legend.append({'image': image, 'text': text}) | ||
legend = self.get_legend_for(self.found_classes) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we're not using the legend anymore in the header template, correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct. Great catch.
|
||
# remember the classes we found | ||
found_classes = np.unique(data) | ||
found_classes = np.unique(class_data) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we still need self.found_classes
below? Now that we have one legend per image I think this can go away.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Damn, you're good.
|
||
zeros = np.zeros(class_data.shape) | ||
# Assuming that class 0 is the background | ||
mask = np.greater(class_data, zeros) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you have to create the zeros
array? I think you can use np.greater
to compare against a scalar:
>>> x=np.array([0,1,2,0,4])
>>> mask=np.greater(x,0)
>>> mask
array([False, True, True, False, True], dtype=bool)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice!
fill_data[:, :, 3] = mask * 255 | ||
|
||
# Black mask of non-segmented pixels | ||
mask_data = np.zeros(fill_data.shape, dtype='uint8') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you need this line? I think the below one is enough (?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The np.zeros create RGBA data. the line below sets the A component. Is there some pythonic trickery that I'm missing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
my mistake, sorry.
# Assuming that class 0 is the background. | ||
line_mask = np.zeros(class_data.shape, dtype=bool) | ||
for c in (x for x in found_classes if x != 0): | ||
c_mask = np.equal(class_data, zeros + c) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can also do without zeros
here:
>>> x=np.array([0,1,1,2])
>>> np.equal(x,1)
array([False, True, True, False], dtype=bool)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
# Find the signed distance from the zero contour | ||
distance = skfmm.distance(c_mask.astype('float32') - 0.5) | ||
# Accumulate the mask for all classes | ||
line_mask |= c_mask & np.less(distance, zeros + 3) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
neat!
@@ -38,7 +38,7 @@ def __init__(self, model, images, epoch, layers, resize=True, **kwargs): | |||
|
|||
@override | |||
def __getstate__(self): | |||
fields_to_save = ['_id', '_name'] | |||
fields_to_save = ['_id', '_name', 'status_history'] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you explain this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not for this commit. I needed for something a while back, which I no longer recall. Removing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
very nice!
a057b1a
to
ee5f90c
Compare
ee5f90c
to
a9284ab
Compare
|
||
# add the outlines to the input image | ||
for x in xrange(3): | ||
input_data[:, :, x] = (input_data[:, :, x] * (1 - line_mask) + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this doesn't work if input_data
is a grayscale image (with shape e.g. [256,256]
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also, this should be done within the if len(found_classes)>1
otherwise line_mask
is uninitialized
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gheinrich, did you try this with a (256, 256)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jmancewicz yes, this was an image from the Sunnybrook dataset (with channel conversion = 'none')
fill_data[:, :, x] * line_mask) | ||
|
||
# Input image with outlines | ||
input_image = PIL.Image.fromarray(input_data) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does this work if input_data.dtype!='uint8'
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, but that's in an upcoming PR.
…w-improvement Image segmentation view improvement
Changed the imageSegmentation view extension so that rather than displaying the segmentation image,
![screen shot 2016-10-01 at 10 21 28 am](https://cloud.githubusercontent.com/assets/13259615/19015828/dd890932-87c0-11e6-9be7-ea145f835b6f.png)
The segmentation image overlays the input image with a solid outline around each class.
![screen shot 2016-10-01 at 10 21 07 am](https://cloud.githubusercontent.com/assets/13259615/19015833/f3497554-87c0-11e6-9138-df89e248833a.png)
The opacity of the segmented regions and the opacity of the mask of the non-segmented regions are adjustable.
![screen shot 2016-10-01 at 10 18 27 am](https://cloud.githubusercontent.com/assets/13259615/19015845/2587ad88-87c1-11e6-840c-c19b5386f9d7.png)
![screen shot 2016-10-01 at 10 18 45 am](https://cloud.githubusercontent.com/assets/13259615/19015849/2cd84e08-87c1-11e6-93e1-9ebf07373983.png)
I've removed the color to class legend from the header and put a legend or relevant classes beneath each image. When the pointer is over a segmented region, the corresponding class in the legend is highlighted.