io.github.mianalysis.mia.module.objects.measure.miscellaneous.ReplaceMeasurementValue Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mia-modules Show documentation
Show all versions of mia-modules Show documentation
ModularImageAnalysis (MIA) is an ImageJ plugin which provides a modular framework for assembling image and object analysis workflows. Detected objects can be transformed, filtered, measured and related. Analysis workflows are batch-enabled by default, allowing easy processing of high-content datasets.
package io.github.mianalysis.mia.module.objects.measure.miscellaneous;
import org.scijava.Priority;
import org.scijava.plugin.Plugin;
import io.github.mianalysis.mia.module.Categories;
import io.github.mianalysis.mia.module.Category;
import io.github.mianalysis.mia.module.Module;
import io.github.mianalysis.mia.module.Modules;
import io.github.mianalysis.mia.module.objects.filter.AbstractNumericObjectFilter;
import io.github.mianalysis.mia.object.Measurement;
import io.github.mianalysis.mia.object.Obj;
import io.github.mianalysis.mia.object.Objs;
import io.github.mianalysis.mia.object.Workspace;
import io.github.mianalysis.mia.object.parameters.ChoiceP;
import io.github.mianalysis.mia.object.parameters.InputObjectsP;
import io.github.mianalysis.mia.object.parameters.ObjectMeasurementP;
import io.github.mianalysis.mia.object.parameters.Parameters;
import io.github.mianalysis.mia.object.parameters.SeparatorP;
import io.github.mianalysis.mia.object.parameters.text.DoubleP;
import io.github.mianalysis.mia.object.refs.collections.ImageMeasurementRefs;
import io.github.mianalysis.mia.object.refs.collections.MetadataRefs;
import io.github.mianalysis.mia.object.refs.collections.ObjMeasurementRefs;
import io.github.mianalysis.mia.object.refs.collections.ObjMetadataRefs;
import io.github.mianalysis.mia.object.refs.collections.ParentChildRefs;
import io.github.mianalysis.mia.object.refs.collections.PartnerRefs;
import io.github.mianalysis.mia.object.system.Status;
/**
* Replaces measurement values matching specific criteria with different values. This can be used to replace instances of NaN (not a number) values with numeric values or to replace all measurement values failing a numeric test (e.g. less than) with, for example, NaN.
Note: "NaN" stands for "Not a Number" and can arise from certain calculations (e.g. division of 0 by 0) or if a measurement couldn't be made (e.g. fitting an ellipse to an object with too few coordinates).
*/
@Plugin(type = Module.class, priority=Priority.LOW, visible=true)
public class ReplaceMeasurementValue extends Module {
/**
*
*/
public static final String INPUT_SEPARATOR = "Object/measurement input";
/**
* Objects from the workspace for which specific measurement values will be replaced. Any object measurements with values matching the specified criteria will be replaced by another specified value.
*/
public static final String INPUT_OBJECTS = "Input objects";
/**
* Measurement associated with the input objects. Any object measurements with values matching the specified criteria will be replaced by another specified value.
*/
public static final String MEASUREMENT = "Measurement";
/**
*
*/
public static final String REPLACEMENT_SEPARATOR = "Measurement replacement";
/**
* Controls under what condition the input object measurement (specified by "Measurement") will be replaced by the specified value. Note: "NaN" stands for "Not a Number" and can arise from certain calculations (e.g. division of 0 by 0) or if a measurement couldn't be made (e.g. fitting an ellipse to an object with too few coordinates). Choices are: Is NaN, Is not NaN, Less than, Less than or equal to, Equal to, Greater than or equal to, Greater than, Not equal to.
*/
public static final String REPLACEMENT_CONDITION = "Replacement condition";
/**
* If "Replacement condition" is set to a numeric condition (e.g. less than), this value will be used as the threshold against which the measurement value will be tested.
*/
public static final String REFERENCE_VALUE = "Reference value";
/**
* Controls what type of value any measurements identified for replacement will be replaced by:
- "NaN (not a number)" Measurement values will be replaced by NaN (not a number).
- "Number" Measurement values will be replaced by the numeric value specified by "Replacement value".
- "Negative infinity" Measurement values will be replaced by the specific "negative infinity" value.
- "Positive infinity" Measurement values will be replaced by the specific "positive infinity" value.
*/
public static final String REPLACEMENT_VALUE_TYPE = "Replacement value type";
/**
* Value to replace identified measurements with if "Replacement value type" is set to "Number" mode.
*/
public static final String REPLACEMENT_VALUE = "Replacement value";
public interface ReplacementConditions {
String IS_INFINITE = "Is infinite";
String IS_NOT_INFINITE = "Is not infinite";
String IS_NAN = "Is NaN";
String IS_NOT_NAN = "Is not NaN";
String LESS_THAN = "Less than";
String LESS_THAN_OR_EQUAL_TO = "Less than or equal to";
String EQUAL_TO = "Equal to";
String GREATER_THAN_OR_EQUAL_TO = "Greater than or equal to";
String GREATER_THAN = "Greater than";
String NOT_EQUAL_TO = "Not equal to";
String[] ALL = new String[] { IS_NAN, IS_NOT_NAN, LESS_THAN, LESS_THAN_OR_EQUAL_TO, EQUAL_TO,
GREATER_THAN_OR_EQUAL_TO, GREATER_THAN, NOT_EQUAL_TO };
}
public interface ReplacementValueTypes {
String NUMBER = "Number";
String NAN = "NaN (not a number)";
String NEGATIVE_INFINITY = "Negative infinity";
String POSITIVE_INFINITY = "Positive infinity";
String[] ALL = new String[] { NUMBER, NAN, NEGATIVE_INFINITY, POSITIVE_INFINITY };
}
public ReplaceMeasurementValue(Modules modules) {
super("Replace measurement value", modules);
}
@Override
public Category getCategory() {
return Categories.OBJECTS_MEASURE_MISCELLANEOUS;
}
@Override
public String getVersionNumber() {
return "1.0.0";
}
@Override
public String getDescription() {
return "Replaces measurement values matching specific criteria with different values. This can be used to replace instances of NaN (not a number) values with numeric values or to replace all measurement values failing a numeric test (e.g. less than) with, for example, NaN.
Note: \"NaN\" stands for \"Not a Number\" and can arise from certain calculations (e.g. division of 0 by 0) or if a measurement couldn't be made (e.g. fitting an ellipse to an object with too few coordinates).";
}
@Override
protected Status process(Workspace workspace) {
String inputObjectsName = parameters.getValue(INPUT_OBJECTS,workspace);
Objs inputObjects = workspace.getObjects(inputObjectsName);
String measurementName = parameters.getValue(MEASUREMENT,workspace);
String replacementCondition = parameters.getValue(REPLACEMENT_CONDITION,workspace);
double referenceValue = parameters.getValue(REFERENCE_VALUE,workspace);
String replacementValueType = parameters.getValue(REPLACEMENT_VALUE_TYPE,workspace);
double replacementValue = parameters.getValue(REPLACEMENT_VALUE,workspace);
for (Obj inputObject : inputObjects.values()) {
Measurement measurement = inputObject.getMeasurement(measurementName);
if (measurement == null)
continue;
double currentValue = measurement.getValue();
boolean replace = false;
switch (replacementCondition) {
case ReplacementConditions.IS_INFINITE:
replace = Double.isInfinite(currentValue);
break;
case ReplacementConditions.IS_NOT_INFINITE:
replace = !Double.isInfinite(currentValue);
break;
case ReplacementConditions.IS_NAN:
replace = Double.isNaN(currentValue);
break;
case ReplacementConditions.IS_NOT_NAN:
replace = !Double.isNaN(currentValue);
break;
case ReplacementConditions.EQUAL_TO:
case ReplacementConditions.GREATER_THAN:
case ReplacementConditions.GREATER_THAN_OR_EQUAL_TO:
case ReplacementConditions.LESS_THAN:
case ReplacementConditions.LESS_THAN_OR_EQUAL_TO:
case ReplacementConditions.NOT_EQUAL_TO:
replace = AbstractNumericObjectFilter.testFilter(currentValue, referenceValue,
replacementCondition);
break;
}
if (replace) {
switch (replacementValueType) {
case ReplacementValueTypes.NUMBER:
measurement.setValue(replacementValue);
break;
case ReplacementValueTypes.NAN:
measurement.setValue(Double.NaN);
break;
case ReplacementValueTypes.NEGATIVE_INFINITY:
measurement.setValue(Double.NEGATIVE_INFINITY);
break;
case ReplacementValueTypes.POSITIVE_INFINITY:
measurement.setValue(Double.POSITIVE_INFINITY);
break;
}
}
}
if (showOutput) inputObjects.showMeasurements(this, modules);
return Status.PASS;
}
@Override
protected void initialiseParameters() {
parameters.add(new SeparatorP(INPUT_SEPARATOR, this));
parameters.add(new InputObjectsP(INPUT_OBJECTS, this));
parameters.add(new ObjectMeasurementP(MEASUREMENT, this));
parameters.add(new SeparatorP(REPLACEMENT_SEPARATOR, this));
parameters
.add(new ChoiceP(REPLACEMENT_CONDITION, this, ReplacementConditions.IS_NAN, ReplacementConditions.ALL));
parameters.add(new DoubleP(REFERENCE_VALUE, this, 0d));
parameters.add(
new ChoiceP(REPLACEMENT_VALUE_TYPE, this, ReplacementValueTypes.NUMBER, ReplacementValueTypes.ALL));
parameters.add(new DoubleP(REPLACEMENT_VALUE, this, 0));
addParameterDescriptions();
}
@Override
public Parameters updateAndGetParameters() {
Workspace workspace = null;
String inputObjectsName = parameters.getValue(INPUT_OBJECTS,workspace);
Parameters returnedParams = new Parameters();
returnedParams.add(parameters.get(INPUT_SEPARATOR));
returnedParams.add(parameters.get(INPUT_OBJECTS));
returnedParams.add(parameters.get(MEASUREMENT));
returnedParams.add(parameters.get(REPLACEMENT_SEPARATOR));
returnedParams.add(parameters.get(REPLACEMENT_CONDITION));
switch ((String) parameters.getValue(REPLACEMENT_CONDITION,workspace)) {
case ReplacementConditions.EQUAL_TO:
case ReplacementConditions.GREATER_THAN:
case ReplacementConditions.GREATER_THAN_OR_EQUAL_TO:
case ReplacementConditions.LESS_THAN:
case ReplacementConditions.LESS_THAN_OR_EQUAL_TO:
case ReplacementConditions.NOT_EQUAL_TO:
returnedParams.add(parameters.get(REFERENCE_VALUE));
break;
}
returnedParams.add(parameters.get(REPLACEMENT_VALUE_TYPE));
switch ((String) parameters.getValue(REPLACEMENT_VALUE_TYPE,workspace)) {
case ReplacementValueTypes.NUMBER:
returnedParams.add(parameters.get(REPLACEMENT_VALUE));
break;
}
ObjectMeasurementP measurementParameter = parameters.getParameter(MEASUREMENT);
measurementParameter.setObjectName(inputObjectsName);
return returnedParams;
}
@Override
public ImageMeasurementRefs updateAndGetImageMeasurementRefs() {
return null;
}
@Override
public ObjMeasurementRefs updateAndGetObjectMeasurementRefs() {
return null;
}
@Override
public ObjMetadataRefs updateAndGetObjectMetadataRefs() {
return null;
}
@Override
public MetadataRefs updateAndGetMetadataReferences() {
return null;
}
@Override
public ParentChildRefs updateAndGetParentChildRefs() {
return null;
}
@Override
public PartnerRefs updateAndGetPartnerRefs() {
return null;
}
@Override
public boolean verify() {
return true;
}
void addParameterDescriptions() {
parameters.get(INPUT_OBJECTS).setDescription("Objects from the workspace for which specific measurement values will be replaced. Any object measurements with values matching the specified criteria will be replaced by another specified value.");
parameters.get(MEASUREMENT).setDescription("Measurement associated with the input objects. Any object measurements with values matching the specified criteria will be replaced by another specified value.");
parameters.get(REPLACEMENT_CONDITION).setDescription("Controls under what condition the input object measurement (specified by \""+MEASUREMENT+"\") will be replaced by the specified value. Note: \"NaN\" stands for \"Not a Number\" and can arise from certain calculations (e.g. division of 0 by 0) or if a measurement couldn't be made (e.g. fitting an ellipse to an object with too few coordinates). Choices are: "+ String.join(", ", ReplacementConditions.ALL)+".");
parameters.get(REFERENCE_VALUE).setDescription("If \""+REPLACEMENT_CONDITION+"\" is set to a numeric condition (e.g. less than), this value will be used as the threshold against which the measurement value will be tested.");
parameters.get(REPLACEMENT_VALUE_TYPE).setDescription("Controls what type of value any measurements identified for replacement will be replaced by:
"
+"- \""+ReplacementValueTypes.NAN+"\" Measurement values will be replaced by NaN (not a number).
"
+"- \""+ReplacementValueTypes.NUMBER+"\" Measurement values will be replaced by the numeric value specified by \""+REPLACEMENT_VALUE+"\".
"
+"- \""+ReplacementValueTypes.NEGATIVE_INFINITY+"\" Measurement values will be replaced by the specific \"negative infinity\" value.
"
+"- \""+ReplacementValueTypes.POSITIVE_INFINITY+"\" Measurement values will be replaced by the specific \"positive infinity\" value.
");
parameters.get(REPLACEMENT_VALUE).setDescription("Value to replace identified measurements with if \""+REPLACEMENT_VALUE_TYPE+"\" is set to \""+ReplacementValueTypes.NUMBER+"\" mode.");
}
}