Skip to content

Commit

Permalink
Add Segmentation Overay
Browse files Browse the repository at this point in the history
  • Loading branch information
MinsuSeo-FAU committed Apr 10, 2024
1 parent 2bd2916 commit 833210b
Show file tree
Hide file tree
Showing 5 changed files with 269 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ class FakeBroadcastChannel {
close() { }
}




class EXACTBrowserSync {

constructor(source_image, viewer, exact_registration_sync) {
Expand Down Expand Up @@ -77,10 +74,46 @@ class EXACTBrowserSync {
this.getChannelObject("GetImageInformation").onmessage =
this.sendImageInformation.bind(this);

$("#sync_browser_image").on("change",this.createRegistration.bind(this));
$("#sync_browser_image").on("change",this.imageHandlerSelection.bind(this));
}

imageHandlerSelection(event) {

let backgroundColor = $("select#sync_browser_image option:selected").css("background-color");

if (backgroundColor == "rgb(0, 0, 255)") {
this.createOverlayOpacity(event);
}
else {
this.createRegistration(event);
}
}

createOverlayOpacity(event) {
var selectElement = document.getElementById('sync_browser_image');
var selectedOption = selectElement.options[selectElement.selectedIndex];

var selectedImageId = selectedOption.getAttribute('data-image_id');
var selectedImageName = selectedOption.label;

this.openTabImageInformations[selectedImageId] = selectedImageName;

if (this.registration !== undefined) {
this.registration.destroy();
}

var imageInfo = new Map();

imageInfo.set('target_image_id', this.source_image.id);
imageInfo.set('target_image_name', this.source_image.name);
imageInfo.set('source_image_id', selectedImageId);
imageInfo.set('source_image_name', selectedImageName);

this.registration = new EXACTOverlayOpacityHandler(this.viewer, imageInfo, this);
}

createRegistration(event) {

let registration_pair = this.exact_registration_sync.registeredImagePairs[$( "select#sync_browser_image").val()];

if(registration_pair === undefined || registration_pair.target_image.id !== this.source_image.id) {
Expand Down Expand Up @@ -127,6 +160,28 @@ class EXACTBrowserSync {
</option>`);
}

// set all segmentation pairs at UI
var imageListDiv = document.getElementById('image_list');
var imageLinks = imageListDiv.getElementsByTagName('a');

for (var i = 0; i < imageLinks.length; i++) {
var imageName = imageLinks[i].textContent.trim();
imageName = imageName.replace(/\s/g, '');
imageName = imageName.replace(/\n/g, '');
var imageId = imageLinks[i].getAttribute('data-image_id');
console.log('Image Name: ' + imageName + ', Image ID: ' + imageId);

var name1 = this.source_image.name.split('.').slice(0, -1).join('.');
var name2 = imageName.split('.').slice(0, -1).join('.');

if (name1 === name2 && this.source_image.name !== imageName) {
image_list.append(`<option style="background-color: blue"
data-image_id=${imageId}>
${imageName}
</option>`);
}
}

if($('#sync_browser_image > option').length >= 1) {
$("#sync_browser_image").trigger("change");
}
Expand Down
186 changes: 186 additions & 0 deletions exact/exact/annotations/static/annotations/js/exact-overlay-opacity.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
class EXACTOverlayOpacityHandler {

constructor(viewer,image_info, browser_sync) {
this.image_info = image_info;
this.browser_sync = browser_sync;
this.viewer = viewer;
this.background_viewer = undefined;

var t_mat = [[1, 0, 0], [0, 1, 0], [0, 0, 1]];

this.updateHomographyUI(t_mat);

$("#OverlayRegImage-enabled").click(this.enableOverlayRegImageSlider.bind(this));
$('#registration00').change(this.syncViewBackgroundForeground.bind(this));
$('#registration11').change(this.syncViewBackgroundForeground.bind(this));
}

enableOverlayRegImageSlider(event) {

if ($("#OverlayRegImage-enabled").prop("checked")) {
const options = {
id: "openseadragon_background",
prefixUrl: $("#image_list").data( "static-file" ) +"images/",
showNavigator: false,
tileSources: [this.viewer.tileSources[0]
.replace(`images/image/${this.image_info.get("target_image_id")}`,
`images/image/${this.image_info.get("source_image_id")}`)],
showNavigator: false,
animationTime: 0.5,
blendTime: 0.1,
constrainDuringPan: true,
maxZoomPixelRatio: 8,
minZoomLevel: 0.1,
zoomPerScroll: 1.1,
timeout: 120000,
sequenceMode: false,
showReferenceStrip: false,
};

this.background_viewer = OpenSeadragon(options);

this.background_viewer.addHandler("open", function (event) {
this.userData.calcInitialScaleFactor();
var opacity = 50;
this.userData.viewer.raiseEvent('updateOverlayImageSlider', { opacity });
this.userData.syncViewBackgroundForeground();
}, this);

} else {
if (this.background_viewer !== undefined) {
this.background_viewer.destroy();

this.background_viewer = undefined;
}
}

}

syncViewBackgroundForeground () {

if (this.background_viewer !== undefined) {
var t_mat = [[1, 0, 0], [0, 1, 0], [0, 0, 1]];
t_mat[0][0] = parseFloat($('#registration00').val());
t_mat[0][1] = parseFloat($('#registration01').val());
t_mat[0][2] = parseFloat($('#registration02').val());

t_mat[1][0] = parseFloat($('#registration10').val());
t_mat[1][1] = parseFloat($('#registration11').val());
t_mat[1][2] = parseFloat($('#registration12').val());

var inv_t_mat = this.inverse([[t_mat[0][0], t_mat[0][1], t_mat[0][2]], [t_mat[1][0], t_mat[1][1], t_mat[1][2]]]);

var inv_mpp_x_scale = inv_t_mat[0][0];
var inv_mpp_y_scale = inv_t_mat[1][1];

var bounds = this.viewer.viewport.getBounds(true);
var imageRect = this.viewer.viewport.viewportToImageRectangle(bounds);

var [xmin_trans, ymin_trans] = this.transformAffineInv(imageRect.x, imageRect.y);

const vpRect = this.background_viewer.viewport.imageToViewportRectangle(new OpenSeadragon.Rect(
xmin_trans,
ymin_trans,
imageRect.width * inv_mpp_x_scale,
imageRect.height * inv_mpp_y_scale,
0
));

this.background_viewer.viewport.fitBoundsWithConstraints(vpRect);
}
}

calcInitialScaleFactor() {
if (this.background_viewer !== undefined) {
var t_mat = [[1, 0, 0], [0, 1, 0], [0, 0, 1]];

var x1 = this.background_viewer.viewport._contentSize.x;
var y1 = this.background_viewer.viewport._contentSize.y;

var x2 = this.viewer.viewport._contentSize.x;
var y2 = this.viewer.viewport._contentSize.y;

t_mat[0][0] = (x2/x1).toFixed(5);
t_mat[1][1] = (y2/y1).toFixed(5);

this.updateHomographyUI(t_mat);
}
}

transformAffineInv(x, y) {
var t_mat = [[1, 0, 0], [0, 1, 0]];

t_mat[0][0] = parseFloat($('#registration00').val());
t_mat[0][1] = parseFloat($('#registration01').val());
t_mat[0][2] = parseFloat($('#registration02').val());

t_mat[1][0] = parseFloat($('#registration10').val());
t_mat[1][1] = parseFloat($('#registration11').val());
t_mat[1][2] = parseFloat($('#registration12').val());

var inv_t_mat = this.inverse([[t_mat[0][0], t_mat[0][1], t_mat[0][2]], [t_mat[1][0], t_mat[1][1], t_mat[1][2]]]);

var t_00 = inv_t_mat[0][0];
var t_10 = inv_t_mat[1][0];

var t_01 = inv_t_mat[0][1];
var t_11 = inv_t_mat[1][1];

var t_02 = inv_t_mat[0][2];
var t_12 = inv_t_mat[1][2];

var new_x = Math.round(t_00 * x + t_01 * y + t_02);
var new_y = Math.round(t_10 * x + t_11 * y + t_12);

return [new_x, new_y];
}

updateHomographyUI(matrinx) {
$('#registration00').val(matrinx[0][0]);
$('#registration01').val(matrinx[0][1]);
$('#registration02').val(matrinx[0][2]);

$('#registration10').val(matrinx[1][0]);
$('#registration11').val(matrinx[1][1]);
$('#registration12').val(matrinx[1][2]);

$('#registration20').val(matrinx[2][0]);
$('#registration21').val(matrinx[2][1]);
$('#registration22').val(matrinx[2][2]);
}

inverse(matrix) {
var a = matrix[0][0], b = matrix[1][0], c = matrix[0][1], d = matrix[1][1], e = matrix[0][2], f = matrix[1][2];

const denom = a * d - b * c;

return [[d / denom, c / -denom, (d * e - c * f) / -denom], [b / -denom, a / denom, (b * e - a * f) / denom]];
}

destroy() {

if (this.background_viewer !== undefined) {
this.background_viewer.destroy();

$("#OverlayRegImage-enabled").prop("checked", false )
}

$('#overlaySlider').off("input");

$('#registration00').val(0);
$('#registration01').val(0);
$('#registration02').val(0);

$('#registration10').val(0);
$('#registration11').val(0);
$('#registration12').val(0);

$('#registration20').val(0);
$('#registration21').val(0);
$('#registration22').val(0);

$("#update_browser_sync_images_btn").off("click");
$("#OverlayRegImage-enabled").off("click");
$(document).off('keyup');
}
}
3 changes: 2 additions & 1 deletion exact/exact/annotations/templates/annotations/annotate.html
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
<script type="text/javascript" src="{% static 'annotations/js/show-annotation-properties.js' %}"></script>
<script type="text/javascript" src="{% static 'annotations/js/exact-browser-sync.js' %}"></script>
<script type="text/javascript" src="{% static 'annotations/js/exact-quad-tree.js' %}"></script>
<script type="text/javascript" src="{% static 'annotations/js/exact-overlay-opacity.js' %}"></script>
<script type="text/javascript" src="{% static 'annotations/js/annotations.js' %}"></script>

<script type="text/javascript" src="{% static 'annotations/js/bootstrap-slider.min.js' %}"></script>
Expand Down Expand Up @@ -701,7 +702,7 @@ <h5 id="active_image_name">{{ selected_image.name }}</h5>
<td>
<input id="OverlayRegImage-enabled" type="checkbox" />
</td>

<td>
</td>
</tr>
Expand Down
22 changes: 21 additions & 1 deletion exact/exact/images/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
from tifffile import TiffFile, TiffFileError

from exact.users.models import Team
import h5py

logger = logging.getLogger('django')

Expand Down Expand Up @@ -380,14 +381,33 @@ def save_file(self, path:Path):
vi = pyvips.Image.new_from_file(str(old_path))
vi.tiffsave(str(path), tile=True, compression='lzw', bigtiff=True, pyramid=True, tile_width=256, tile_height=256)
self.filename = path.name

elif path.suffix.lower().endswith(".hdf5") :
with h5py.File(str(path), 'r') as hf:
data = hf["segmentation"]
ndarray_data = np.array(data)

scaled_image_data = (ndarray_data * (255 / len(np.unique(ndarray_data)))).astype(np.uint8)
colored_image = cv2.applyColorMap(scaled_image_data, cv2.COLORMAP_VIRIDIS)
colored_image = cv2.cvtColor(colored_image, cv2.COLOR_BGR2RGB)

vi = pyvips.Image.new_from_array(colored_image)
path = Path(path).with_suffix('.tiff')
vi.tiffsave(str(path), tile=True, compression='lzw', bigtiff=True, pyramid=True, tile_width=256, tile_height=256)
self.filename = path.name

else:
path = Path(path).with_suffix('.tiff')

vi = pyvips.Image.new_from_file(str(old_path))
vi.tiffsave(str(path), tile=True, compression='lzw', bigtiff=True, pyramid=True, tile_width=256, tile_height=256)
self.filename = path.name

osr = OpenSlide(self.path())
osr = OpenSlide(str(path))

if not Path(self.path()).suffix.lower().endswith(".hdf5") :
osr = OpenSlide(self.path())

self.width, self.height = osr.level_dimensions[0]
try:
mpp_x = osr.properties[openslide.PROPERTY_NAME_MPP_X]
Expand Down
2 changes: 1 addition & 1 deletion exact/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

confusable-homoglyphs==3.2.0
drf-flex-fields==1.0.2
Django==3.2.11
django-appconf==1.0.5
django-extensions==3.2.3
django-filter==23.2
Expand Down Expand Up @@ -41,3 +40,4 @@ qt-wsi-registration>=0.0.6
EXCAT-Sync>=0.0.38
pyyaml>=6.0.1
aicsimageio==4.11.0
h5py==3.10.0

0 comments on commit 833210b

Please sign in to comment.