-
Notifications
You must be signed in to change notification settings - Fork 35
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
Add optional OMERO rendering metadata #160
Merged
chris-allan
merged 11 commits into
glencoesoftware:master
from
melissalinkert:omero-metadata
Sep 28, 2022
Merged
Changes from 10 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
8d4e6bc
Add optional OMERO rendering metadata
melissalinkert a9e555e
Fix color formatting
melissalinkert ec67911
Aggregate min/max values from all readers
melissalinkert 8ab3ceb
Add color picking logic and unit tests
melissalinkert 6693198
Fix a few small issues with OMERO rendering metadata
melissalinkert 1729af5
Move name from `omero` to `multiscale`
melissalinkert 515ae8a
Update channel names to mirror logic in OMERO's ChannelProcessor
melissalinkert 259cd98
Fix min/max so that Infinity/-Infinity won't be used
melissalinkert ad227de
Change `--no-omero` option to `--no-minmax`
melissalinkert e444287
Make sure MetadataStore references are resolved before checking filte…
melissalinkert 41be21d
Merge branch 'master' of github.com:glencoesoftware/bioformats2raw in…
melissalinkert File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
180 changes: 180 additions & 0 deletions
180
src/main/java/com/glencoesoftware/bioformats2raw/Colors.java
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,180 @@ | ||
/** | ||
* Copyright (c) 2022 Glencoe Software, Inc. All rights reserved. | ||
* | ||
* This software is distributed under the terms described by the LICENSE.txt | ||
* file you can find at the root of the distribution bundle. If the file is | ||
* missing please request a copy by contacting info@glencoesoftware.com | ||
*/ | ||
package com.glencoesoftware.bioformats2raw; | ||
|
||
import java.util.List; | ||
|
||
import loci.formats.ome.OMEXMLMetadata; | ||
|
||
import ome.units.UNITS; | ||
import ome.units.quantity.Length; | ||
import ome.units.unit.Unit; | ||
import ome.xml.meta.OMEXMLMetadataRoot; | ||
import ome.xml.model.Channel; | ||
import ome.xml.model.Filter; | ||
import ome.xml.model.FilterSet; | ||
import ome.xml.model.Image; | ||
import ome.xml.model.LightPath; | ||
import ome.xml.model.TransmittanceRange; | ||
import ome.xml.model.primitives.Color; | ||
|
||
/** | ||
* Helper methods for choosing channel colors. | ||
*/ | ||
public class Colors { | ||
|
||
private static final double BLUE_TO_GREEN = 500.0; | ||
private static final double GREEN_TO_RED = 560.0; | ||
private static final double RANGE = 15.0; | ||
|
||
/** | ||
* Determine which color to use for the given channel. | ||
* If a channel color is already set, that will be returned. | ||
* If a channel emission wavelength is set, that will be used | ||
* to determine the color; red, green, or blue based on the | ||
* wavelength in nm. | ||
* If filter metadata is populated, the first filter with | ||
* CutIn and/or CutOut wavelengths will be used to determine | ||
* the color. | ||
* Otherwise, the channel index is used to pick red, green, or blue. | ||
* | ||
* @param meta OME-XML object with acquisition metadata | ||
* @param series Bio-Formats series/OME-XML Image index | ||
* @param c channel index | ||
* @return channel color | ||
*/ | ||
public static Color getColor(OMEXMLMetadata meta, int series, int c) { | ||
Color color = meta.getChannelColor(series, c); | ||
if (color != null) { | ||
return color; | ||
} | ||
|
||
Length emWave = meta.getChannelEmissionWavelength(series, c); | ||
if (emWave != null) { | ||
return colorFromWavelength(emWave); | ||
} | ||
|
||
OMEXMLMetadataRoot root = (OMEXMLMetadataRoot) meta.getRoot(); | ||
Image img = root.getImage(series); | ||
Channel channel = img.getPixels().getChannel(c); | ||
LightPath path = channel.getLightPath(); | ||
FilterSet filterSet = channel.getLinkedFilterSet(); | ||
|
||
Length valueFilter = null; | ||
|
||
// look at LightPath.EmissionFilterRef | ||
|
||
if (path != null) { | ||
List<Filter> emFilters = path.copyLinkedEmissionFilterList(); | ||
valueFilter = handleFilters(emFilters, true); | ||
} | ||
|
||
// look at FilterSet.EmissionFilterRef | ||
|
||
if (valueFilter == null && filterSet != null) { | ||
List<Filter> emFilters = filterSet.copyLinkedEmissionFilterList(); | ||
valueFilter = handleFilters(emFilters, true); | ||
} | ||
|
||
// look at LightSourceSettings.Laser.Wavelength and return if present | ||
// but EmissionFilterRef not present | ||
|
||
Length exWave = meta.getChannelExcitationWavelength(series, c); | ||
if (exWave != null) { | ||
return colorFromWavelength(exWave); | ||
} | ||
|
||
// look at LightPath.ExcitationFilterRef | ||
|
||
if (valueFilter == null && path != null) { | ||
List<Filter> exFilters = path.copyLinkedExcitationFilterList(); | ||
valueFilter = handleFilters(exFilters, false); | ||
} | ||
|
||
// look at FilterSet.ExcitationFilterRef | ||
|
||
if (valueFilter == null && filterSet != null) { | ||
List<Filter> exFilters = filterSet.copyLinkedExcitationFilterList(); | ||
valueFilter = handleFilters(exFilters, false); | ||
} | ||
|
||
// if any filter ref has a valid value, return the first one found | ||
|
||
if (valueFilter != null) { | ||
return colorFromWavelength(valueFilter); | ||
} | ||
|
||
// return red, green, or blue depending on the channel index | ||
int baseColor = 0xff; | ||
int shift = (3 - (c % 3)) * 8; | ||
baseColor = baseColor << shift; | ||
return new Color(baseColor + 0xff); | ||
} | ||
|
||
private static Length handleFilters(List<Filter> filters, boolean emission) { | ||
for (Filter f : filters) { | ||
Length v = getValueFromFilter(f, emission); | ||
if (v != null) { | ||
return v; | ||
} | ||
} | ||
return null; | ||
} | ||
|
||
private static Length getValueFromFilter(Filter filter, boolean emission) { | ||
if (filter == null) { | ||
return null; | ||
} | ||
TransmittanceRange transmittance = filter.getTransmittanceRange(); | ||
if (transmittance == null) { | ||
return null; | ||
} | ||
Length cutIn = transmittance.getCutIn(); | ||
|
||
if (emission) { | ||
if (cutIn == null) { | ||
return null; | ||
} | ||
return new Length(cutIn.value().doubleValue() + RANGE, cutIn.unit()); | ||
} | ||
Length cutOut = transmittance.getCutOut(); | ||
if (cutOut == null) { | ||
return null; | ||
} | ||
double cutOutValue = cutOut.value().doubleValue(); | ||
if (cutIn == null || cutIn.value().doubleValue() == 0) { | ||
cutIn = new Length(cutOutValue - 2 * RANGE, cutOut.unit()); | ||
} | ||
Unit<Length> unit = cutOut.unit(); | ||
Length v = | ||
new Length(cutIn.value(unit).doubleValue() + cutOutValue / 2, unit); | ||
if (v.value().doubleValue() < 0) { | ||
return new Length(0, unit); | ||
} | ||
return v; | ||
} | ||
|
||
private static Color colorFromWavelength(Length wave) { | ||
if (wave == null) { | ||
return null; | ||
} | ||
|
||
double nm = wave.value(UNITS.NM).doubleValue(); | ||
|
||
if (nm < BLUE_TO_GREEN) { | ||
return new Color(0, 0, 255, 255); | ||
} | ||
else if (nm < GREEN_TO_RED) { | ||
return new Color(0, 255, 0, 255); | ||
} | ||
return new Color(255, 0, 0, 255); | ||
} | ||
|
||
|
||
|
||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Outside the scope of this PR, assuming this is the same logic as the one implemented in the server components, it would make sense to capture the migration of this logic to Bio-Formats e.g. as a
FormatTools
helper or similar. If a new Bio-Formats release included this backwards-compatible API addition, downstream components could be updated to consume it.