From 7ee8562c0c06d6b06a20286a26a6ea6cd10e9deb Mon Sep 17 00:00:00 2001 From: Jamie Mac Date: Thu, 25 Apr 2024 17:00:29 +0100 Subject: [PATCH] Getting DelphinID working --- dependency-reduced-pom.xml | 26 +-- .../bearingLoc/PairBearingLocaliser.java | 2 +- .../animalSpot/StandardModelPane.java | 4 +- .../delphinID/DelphinIDWorker.java | 14 ++ .../delphinID/Whistles2Image.java | 121 ++++++++++++++ .../layoutFX/DLSettingsPane.java | 2 +- .../segmenter/SegmenterDetectionGroup.java | 15 +- .../alarm/WMAlarmParameters.java | 9 +- .../dataSelector/WMDDataSelector.java | 17 +- .../dataSelector/WMDSelectPaneFX.java | 151 ++++++++++++++++++ 10 files changed, 331 insertions(+), 30 deletions(-) create mode 100644 src/rawDeepLearningClassifier/dlClassification/delphinID/Whistles2Image.java create mode 100644 src/whistlesAndMoans/dataSelector/WMDSelectPaneFX.java diff --git a/dependency-reduced-pom.xml b/dependency-reduced-pom.xml index ceb2311d..d6c2ea8e 100644 --- a/dependency-reduced-pom.xml +++ b/dependency-reduced-pom.xml @@ -4,7 +4,7 @@ org.pamguard Pamguard Pamguard - 2.02.11b + 2.02.11c Pamguard using Maven to control dependencies www.pamguard.org @@ -18,6 +18,7 @@ src + META-INF/*.SF,META-INF/*.DSA,META-INF/*.RSA **/*.java jars/*.* @@ -92,16 +93,6 @@ - - - *:* - - META-INF/*.SF - META-INF/*.DSA - META-INF/*.RSA - - - @@ -109,6 +100,16 @@ + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + @@ -191,5 +192,8 @@ 11 UTF-8 21 + 2.4.0-b180830.0438 + 2.4.0-b180830.0438 + 2.4.0-b180830.0359 diff --git a/src/Localiser/algorithms/timeDelayLocalisers/bearingLoc/PairBearingLocaliser.java b/src/Localiser/algorithms/timeDelayLocalisers/bearingLoc/PairBearingLocaliser.java index d6908eca..59c166fd 100644 --- a/src/Localiser/algorithms/timeDelayLocalisers/bearingLoc/PairBearingLocaliser.java +++ b/src/Localiser/algorithms/timeDelayLocalisers/bearingLoc/PairBearingLocaliser.java @@ -214,7 +214,7 @@ public class PairBearingLocaliser implements BearingLocaliser { private boolean resetArray(long timeMillis){ if (this.timeMillis!=timeMillis && currentArray.getHydrophoneLocator().isChangeable()){ - System.out.println("Reset PairBearingLocaliser"); +// System.out.println("Reset PairBearingLocaliser"); prepare(this.arrayElements, timeMillis, this.timingError); return true; } diff --git a/src/rawDeepLearningClassifier/dlClassification/animalSpot/StandardModelPane.java b/src/rawDeepLearningClassifier/dlClassification/animalSpot/StandardModelPane.java index 0cde1e66..21e9a8c1 100644 --- a/src/rawDeepLearningClassifier/dlClassification/animalSpot/StandardModelPane.java +++ b/src/rawDeepLearningClassifier/dlClassification/animalSpot/StandardModelPane.java @@ -178,7 +178,9 @@ public abstract class StandardModelPane extends SettingsPane{ // TODO Auto-generated method stub } + + + @Override + public float[][][] dataUnits2ModelInput(ArrayList dataUnits, float sampleRate, int iChan){ + //Our data units are groups of whistles. + + + + + return null; + } diff --git a/src/rawDeepLearningClassifier/dlClassification/delphinID/Whistles2Image.java b/src/rawDeepLearningClassifier/dlClassification/delphinID/Whistles2Image.java new file mode 100644 index 00000000..a4f39ff3 --- /dev/null +++ b/src/rawDeepLearningClassifier/dlClassification/delphinID/Whistles2Image.java @@ -0,0 +1,121 @@ +package rawDeepLearningClassifier.dlClassification.delphinID; + +import org.jamdev.jdl4pam.transforms.FreqTransform; +import org.jamdev.jpamutils.spectrogram.SpecTransform; + +import javafx.scene.canvas.Canvas; +import javafx.scene.image.WritableImage; +import javafx.scene.paint.Color; +import rawDeepLearningClassifier.segmenter.SegmenterDetectionGroup; + +/** + * Transform whistles to an image. + * + * Here we extend the FreqTransform class because it contains lots of image + * transforms that are useful once the whistles have been converted into an + * image. + * + * @author Jamie Macaulay + * + */ +public class Whistles2Image extends FreqTransform { + + /** + * Create an image transform from a whistleGroup. + * @param whistleGroup + * @param params + */ + public Whistles2Image(SegmenterDetectionGroup whistleGroup, Number[] params) { + super(null, params); + double[] freqLimits = new double[] {params[0].doubleValue(), params[1].doubleValue()}; + double[] size = new double[] {params[2].doubleValue(), params[3].doubleValue()}; + + SpecTransform specTransform = whistleGroupToImage( whistleGroup, freqLimits, size); + + this.setSpecTransfrom(specTransform); + this.setFreqlims(freqLimits); + + } + + + /** + * Convert a group of whistles + * @param whistleGroup - the whistle groups + * @param freqLimits - the frequency limits + * @return the spectrogram transform. + */ + private SpecTransform whistleGroupToImage(SegmenterDetectionGroup whistleGroup, double[] freqLimits, double[] size) { + + SpecTransform specTransform = new SpecTransform(); + + /* + * All time-frequency points are saved as a scatterplot with x-axis spanning 0-4 + * seconds in time and y-axis spanning 0-20 kHz in frequency. - Matplotlib was + * used to produce plot (matplotlib.pyplot.scatter) (Point size set at 5 and all + * other values kept at default, including figure size which is saved as 6.4 x + * 4.8 inches as default, axes removed before saving using plt.axes(‘off’)) + **/ + + double[][] points = whistContours2Points(whistleGroup); + + Canvas canvas = makeScatterImage(points, size, new double[]{0, whistleGroup.getDurationInMilliseconds()}, freqLimits, 5.); + + WritableImage image = canvas.getGraphicsContext2D().getCanvas().snapshot(null, null); + + double[][] imaged = new double[(int) size[0]][(int) size[1]]; + + Color color; + for (int i=0; i{ //only show the data selector box for detec tion data. if (sourcePane.getSource() == null) this.dataSelectorPane.setVisible(false); - if (sourcePane.getSource().getDataSelectCreator() instanceof NullDataSelectorCreator) { + else if (sourcePane.getSource().getDataSelectCreator() instanceof NullDataSelectorCreator) { //^bit messy but cannot think of a better way to do it. this.dataSelectorPane.setVisible(false); } diff --git a/src/rawDeepLearningClassifier/segmenter/SegmenterDetectionGroup.java b/src/rawDeepLearningClassifier/segmenter/SegmenterDetectionGroup.java index ed6adaf8..1a00c4a3 100644 --- a/src/rawDeepLearningClassifier/segmenter/SegmenterDetectionGroup.java +++ b/src/rawDeepLearningClassifier/segmenter/SegmenterDetectionGroup.java @@ -4,14 +4,21 @@ import Localiser.detectionGroupLocaliser.GroupDetection; import PamguardMVC.PamDataUnit; /** - * A group of detection which are within a particular segment. This is used to pass detection groups straight to - * - * - * * @author Jamie Macaulay + * A group of detection which are within a particular segment. This is used to pass detection groups straight to a classifier. + * @author Jamie Macaulay * */ public class SegmenterDetectionGroup extends GroupDetection { + /** + * Constructor for a group of detections within a detection. Note that some + * longer detections (e.g. whistles) may have sections outside the segment. + * + * @param timeMilliseconds - this is the start of the SEGMENT - Note that the + * @param channelBitmap - channels of all detections + * @param startSample - the stratSample of the SEGMENT. + * @param duration - the duration of the SEGMENT. + */ public SegmenterDetectionGroup(long timeMilliseconds, int channelBitmap, long startSample, long duration) { super(timeMilliseconds, channelBitmap, startSample, duration); // TODO Auto-generated constructor stub diff --git a/src/whistlesAndMoans/alarm/WMAlarmParameters.java b/src/whistlesAndMoans/alarm/WMAlarmParameters.java index 1978d507..46a480ff 100644 --- a/src/whistlesAndMoans/alarm/WMAlarmParameters.java +++ b/src/whistlesAndMoans/alarm/WMAlarmParameters.java @@ -11,10 +11,11 @@ public class WMAlarmParameters extends DataSelectParams implements Cloneable, Se public static final long serialVersionUID = 1L; - public double minFreq, maxFreq; - public double minAmplitude; - public double minLengthMillis; - public boolean superDetOnly; + public double minFreq = 0.; + public double maxFreq = 30000.; + public double minAmplitude = 90.; + public double minLengthMillis = 0.0; + public boolean superDetOnly = false; @Override public WMAlarmParameters clone() { diff --git a/src/whistlesAndMoans/dataSelector/WMDDataSelector.java b/src/whistlesAndMoans/dataSelector/WMDDataSelector.java index 7838b2d6..34ec0027 100644 --- a/src/whistlesAndMoans/dataSelector/WMDDataSelector.java +++ b/src/whistlesAndMoans/dataSelector/WMDDataSelector.java @@ -1,15 +1,9 @@ package whistlesAndMoans.dataSelector; -import java.io.Serializable; - -import alarm.AlarmParameters; import pamViewFX.fxSettingsPanes.DynamicSettingsPane; import whistlesAndMoans.ConnectedRegionDataUnit; import whistlesAndMoans.WhistleMoanControl; import whistlesAndMoans.alarm.WMAlarmParameters; -import PamController.PamControlledUnitSettings; -import PamController.PamSettingManager; -import PamController.PamSettings; import PamView.dialog.PamDialogPanel; import PamguardMVC.PamDataBlock; import PamguardMVC.PamDataUnit; @@ -24,6 +18,11 @@ public class WMDDataSelector extends DataSelector { private WMAlarmParameters wmAlarmParameters = new WMAlarmParameters(); + /** + * JavaFX pane. + */ + private WMDSelectPaneFX wmdSelectPaneFX; + public WMDDataSelector(WhistleMoanControl wmControl, PamDataBlock pamDataBlock, String selectorName, boolean allowScores) { super(pamDataBlock, selectorName, allowScores); @@ -94,8 +93,10 @@ public class WMDDataSelector extends DataSelector { @Override public DynamicSettingsPane getDialogPaneFX() { - // TODO Auto-generated method stub - return null; + if (wmdSelectPaneFX == null) { + wmdSelectPaneFX = new WMDSelectPaneFX(this); + } + return wmdSelectPaneFX; } } diff --git a/src/whistlesAndMoans/dataSelector/WMDSelectPaneFX.java b/src/whistlesAndMoans/dataSelector/WMDSelectPaneFX.java new file mode 100644 index 00000000..41818234 --- /dev/null +++ b/src/whistlesAndMoans/dataSelector/WMDSelectPaneFX.java @@ -0,0 +1,151 @@ +package whistlesAndMoans.dataSelector; + +import javafx.scene.Node; +import javafx.scene.control.Label; +import javafx.scene.control.Spinner; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.Pane; +import pamViewFX.fxNodes.PamGridPane; +import pamViewFX.fxNodes.PamVBox; +import pamViewFX.fxNodes.utilityPanes.PamToggleSwitch; +import pamViewFX.fxSettingsPanes.DynamicSettingsPane; +import whistlesAndMoans.alarm.WMAlarmParameters; + +/** + * JavaFX settings pane for the whsitle and moan detector data selector. + * + * @author Jamie Macaulay + * + */ +public class WMDSelectPaneFX extends DynamicSettingsPane { + + private Pane mainPane; + + private WMDDataSelector wmdDataSelector; + + private Spinner minFreq; + + private Spinner maxFreq; + + private Spinner minAmplitude; + + private Spinner minLength; + + private PamToggleSwitch superDetOnly; + + public WMDSelectPaneFX(WMDDataSelector wmdDataSelector) { + super(wmdDataSelector); + this.wmdDataSelector = wmdDataSelector; + // TODO Auto-generated constructor stub + mainPane = createPane(); + } + + + private Pane createPane() { + + PamVBox mainPane = new PamVBox(); + mainPane.setSpacing(5.); + + PamGridPane gridPane = new PamGridPane(); + gridPane.setHgap(5.); + gridPane.setVgap(5.); + + int row = 0; + int column = 0; + + minFreq = new Spinner(0.,Double.MAX_VALUE, 100., 100.); + minFreq.setEditable(true); + + gridPane.add(new Label("Min. frequency"), column, row); + column++; + gridPane.add(minFreq, column, row); + column++; + gridPane.add(new Label("Hz"), column, row); + + maxFreq = new Spinner(0.,Double.MAX_VALUE, 30000., 100.); + maxFreq.setEditable(true); + + row++; + column=0; + gridPane.add(new Label("Max. frequency"), column, row); + gridPane.add(maxFreq, ++column, row); + gridPane.add(new Label("Hz"), ++column, row); + + minAmplitude = new Spinner(0.,1000., 90., 1.); + minAmplitude.setEditable(true); + + row++; + column=0; + gridPane.add(new Label("Min. amplitude"), column, row); + gridPane.add(minAmplitude, ++column, row); + gridPane.add(new Label("dB"), ++column, row); + + minLength = new Spinner(0.,Double.MAX_VALUE, 0., 1.); + minLength.setEditable(true); + + row++; + column=0; + gridPane.add(new Label("Min. length"), column, row); + gridPane.add(minLength, ++column, row); + gridPane.add(new Label("milliseconds"), ++column, row); + + row++; + column=0; + superDetOnly = new PamToggleSwitch("Only whistles with super-detections"); + gridPane.add(superDetOnly, column, row); + GridPane.setColumnSpan(superDetOnly, 3); + + mainPane.getChildren().add(gridPane); + + return mainPane; + } + + @Override + public Boolean getParams(Boolean currParams) { + + WMAlarmParameters wmAlarmParameters = wmdDataSelector.getWmAlarmParameters().clone(); + try { + wmAlarmParameters.minFreq = minFreq.getValue(); + wmAlarmParameters.maxFreq = maxFreq.getValue(); + wmAlarmParameters.minAmplitude = minAmplitude.getValue(); + wmAlarmParameters.minLengthMillis = minLength.getValue(); + wmAlarmParameters.superDetOnly = superDetOnly.isSelected(); + } + catch (NumberFormatException e) { + return false; + } + wmdDataSelector.setWmAlarmParameters(wmAlarmParameters); + return true; + } + + @Override + public void setParams(Boolean input) { + + WMAlarmParameters wmAlarmParameters = wmdDataSelector.getWmAlarmParameters(); + + minFreq.getValueFactory().setValue(wmAlarmParameters.minFreq); + maxFreq.getValueFactory().setValue(wmAlarmParameters.maxFreq); + minAmplitude.getValueFactory().setValue(wmAlarmParameters.minAmplitude); + minLength.getValueFactory().setValue(wmAlarmParameters.minLengthMillis); + + superDetOnly.setSelected(wmAlarmParameters.superDetOnly); + + } + + @Override + public String getName() { + return "WMD Data Selector"; + } + + @Override + public Node getContentNode() { + return mainPane; + } + + @Override + public void paneInitialized() { + // TODO Auto-generated method stub + + } + +}