From 68953d12fbe59d87d1c5cc41ca0c75ee074a1719 Mon Sep 17 00:00:00 2001 From: Jamie Mac Date: Wed, 7 Feb 2024 12:39:13 +0000 Subject: [PATCH] Updates to FPOD and PAMGuardFX --- .settings/org.eclipse.core.resources.prefs | 4 + pom.xml | 22 +- src/Array/Hydrophone.java | 2 +- src/Array/layoutFX/ArrayGUIFX.java | 3 + src/Array/layoutFX/ArraySettingsPane.java | 5 +- src/Array/layoutFX/HydrophonesPane.java | 5 +- src/PamUtils/PamArrayUtils.java | 18 + src/cpod/CPODClick.java | 80 ++-- src/cpod/CPODControl.java | 3 +- src/cpod/CPODControl2.java | 6 +- src/cpod/CPODDataGramProvider.java | 12 +- src/cpod/CPODImporter.java | 32 +- src/cpod/CPODLoader.java | 1 + src/cpod/FPODReader.java | 133 +++++- src/cpod/dataPlotFX/CPODPlotInfoFX.java | 117 ++++-- .../MLExport/MLExportOverlayMenu.java | 32 +- .../RExport/RExportOverlayMenu.java | 48 ++- .../fxNodes/utilityPanes/SettingsDialog.java | 3 +- src/rawDeepLearningClassifier/DLControl.java | 8 +- .../dlClassification/DLClassifyProcess.java | 1 + .../StandardClassifierModel.java | 2 +- .../animalSpot/StandardAdvModelPane.java | 2 +- .../animalSpot/StandardModelPane.java | 39 +- .../animalSpot/StandardModelParams.java | 1 + .../archiveModel/ArchiveModelClassifier.java | 30 +- .../archiveModel/ArchiveModelPane.java | 13 +- .../archiveModel/ArchiveModelUI.java | 35 +- .../archiveModel/ArchiveModelWorker.java | 394 +++++++++--------- .../archiveModel/SimpleArchiveModel.java | 39 ++ .../ketos/KetosClassifier2.java | 66 +++ .../ketos/KetosModelPane.java | 10 +- .../dlClassification/ketos/KetosWorker.java | 8 +- .../dlClassification/ketos/KetosWorker2.java | 37 ++ .../koogu/KooguClassifier.java | 18 +- .../koogu/KooguModelWorker.java | 25 ++ .../layoutFX/DLModelSelectPane.java | 6 +- .../layoutFX/DLSettingsPane.java | 3 - .../dlTransfroms/DLTransformsPane.java | 2 +- 38 files changed, 890 insertions(+), 375 deletions(-) create mode 100644 src/rawDeepLearningClassifier/dlClassification/archiveModel/SimpleArchiveModel.java create mode 100644 src/rawDeepLearningClassifier/dlClassification/ketos/KetosClassifier2.java create mode 100644 src/rawDeepLearningClassifier/dlClassification/ketos/KetosWorker2.java create mode 100644 src/rawDeepLearningClassifier/dlClassification/koogu/KooguModelWorker.java diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs index ad634f29..9f84592c 100644 --- a/.settings/org.eclipse.core.resources.prefs +++ b/.settings/org.eclipse.core.resources.prefs @@ -1,2 +1,6 @@ eclipse.preferences.version=1 encoding//src/rawDeepLearningClassifer/segmenter/SegmenterProcess.java=UTF-8 +encoding//src/test=ISO-8859-1 +encoding//src/test/resources=ISO-8859-1 +encoding/=ISO-8859-1 +encoding/src=ISO-8859-1 diff --git a/pom.xml b/pom.xml index 3457d06c..a113e184 100644 --- a/pom.xml +++ b/pom.xml @@ -476,25 +476,23 @@ org.kordamp.ikonli ikonli-javafx - 12.2.0 + 12.3.1 - - - org.kordamp.ikonli ikonli-materialdesign2-pack - 12.2.0 + 12.3.1 - + + + + org.kordamp.ikonli + ikonli-fileicons-pack + 12.3.1 + + net.sf.geographiclib diff --git a/src/Array/Hydrophone.java b/src/Array/Hydrophone.java index a79351c9..4cd073d4 100644 --- a/src/Array/Hydrophone.java +++ b/src/Array/Hydrophone.java @@ -315,7 +315,7 @@ public class Hydrophone implements Serializable, Cloneable, ManagedParameters { // need to explicity create a new copy of the double[3] coordinate // and the double[2] bandwidth Hydrophone h = (Hydrophone) super.clone(); - h.setBandwidth(Arrays.copyOf(getBandwidth(), h.getBandwidth().length)); + h.setBandwidth(getBandwidth() == null ? null : Arrays.copyOf(getBandwidth(), h.getBandwidth().length)); h.setCoordinate(Arrays.copyOf(getCoordinates(), 3)); h.setCoordinateErrors(Arrays.copyOf(getCoordinateErrors(), 3)); h.checkDepthInversion(); diff --git a/src/Array/layoutFX/ArrayGUIFX.java b/src/Array/layoutFX/ArrayGUIFX.java index 0715ee4d..c718f5e0 100644 --- a/src/Array/layoutFX/ArrayGUIFX.java +++ b/src/Array/layoutFX/ArrayGUIFX.java @@ -38,7 +38,10 @@ public class ArrayGUIFX extends PamControlledGUIFX { @Override public void updateParams() { + System.out.println("The current array is "+ arrayManager.getCurrentArray()); + PamArray newParams=arraySettingsPane.getParams(arrayManager.getCurrentArray()); + if (newParams!=null) arrayManager.setCurrentArray(newParams); //setup the controlled unit. arrayManager.setupControlledUnit(); diff --git a/src/Array/layoutFX/ArraySettingsPane.java b/src/Array/layoutFX/ArraySettingsPane.java index 8d71b30c..edee9bc5 100644 --- a/src/Array/layoutFX/ArraySettingsPane.java +++ b/src/Array/layoutFX/ArraySettingsPane.java @@ -346,7 +346,10 @@ public class ArraySettingsPane extends SettingsPane{ @Override - public PamArray getParams(PamArray currParams) { + public PamArray getParams(PamArray currParams) { + + if (currParams==null) currParams = this.currentArray; + currParams = streamerPane.getParams(currParams); currParams = hydrophonePane.getParams(currParams); currParams.setHydrophoneInterpolation(hydrophonePane.getHydrophoneInterp()); diff --git a/src/Array/layoutFX/HydrophonesPane.java b/src/Array/layoutFX/HydrophonesPane.java index 2c365605..4d574fa4 100644 --- a/src/Array/layoutFX/HydrophonesPane.java +++ b/src/Array/layoutFX/HydrophonesPane.java @@ -309,8 +309,9 @@ public class HydrophonesPane extends PamBorderPane { } private HydrophoneProperty createDefaultHydrophoneProperty(int id) { - return new HydrophoneProperty(new Hydrophone(id, defaultx, defaulty,defaultz, defaultxErr, defaultyErr, defaultzErr, defaulttype, defaultsensitivity, - null, 0. )); + Hydrophone hydrophone = new Hydrophone(id, defaultx, defaulty,defaultz, defaultxErr, defaultyErr, defaultzErr, defaulttype, defaultsensitivity, + null, 0. ); + return new HydrophoneProperty(hydrophone); } diff --git a/src/PamUtils/PamArrayUtils.java b/src/PamUtils/PamArrayUtils.java index e0c9111c..e80b0ca4 100644 --- a/src/PamUtils/PamArrayUtils.java +++ b/src/PamUtils/PamArrayUtils.java @@ -682,6 +682,7 @@ public class PamArrayUtils { * @return the summation of all the elements in the array. */ public static double sum(double[][] array2) { + if (array2==null) System.out.println("null"); double sum=0; double[] array; for (int i=0; i implements AcousticDataUnit { @@ -21,6 +21,7 @@ public class CPODClick extends PamDataUnit implement private long iciSamples; private short[] rawData; + /** * The amplitude in dB. */ @@ -44,6 +45,7 @@ public class CPODClick extends PamDataUnit implement short slope = shortData[8]; CPODClick cpodClick = new CPODClick(baseData.getTimeMilliseconds(), baseData.getStartSample(), nCyc, bw, kHz, endF, spl, slope, shortData); +// cpodClick.setDurationInMilliseconds(baseData.getMillisecondDuration()); return cpodClick; } @@ -55,6 +57,7 @@ public class CPODClick extends PamDataUnit implement * @param shortData * @return */ + @Deprecated public static CPODClick makeClick(CPODControl cpodControl, long minuteMillis, short[] shortData) { int t = shortData[0]<<16 | @@ -76,33 +79,25 @@ public class CPODClick extends PamDataUnit implement short endF = shortData[6]; short spl = shortData[7]; short slope = shortData[8]; + CPODClick cpodClick = new CPODClick(tMillis, fileSamples, nCyc, bw, kHz, endF, spl, slope, shortData); + +// //estimate the duration in millis - not accurate but gives an idea. +// double duration = (nCyc/(double) kHz); +// cpodClick.setDurationInMilliseconds(duration); + return cpodClick; } /** - * Create a CPOD click. This is usually called whenever the CPOD click is imported from a CSV file. - * - * @param minuteMillis The time in milliseconds of the minute block preceding the - * current click. - * @param shortData - * @return + * Make a FPOD click. This called whenever click has been imported from a FP1 or FP3 file + * @param tMillis - the time in milliseconds datenum. + * @param fileSamples - the number of samples into the file the CPOD click is at - this is calculated from CPODClickDataBlock.CPOD_SR + * @param shortData - the raw data from the CPOD click. This can be 8 bytes or 30 bytes if a click train clcik + * @return a CPODClick object. */ - public static CPODClick makeClick(CPODControl2 cpodControl, long minuteMillis, short[] shortData) { - - int t = shortData[0]<<16 | - shortData[1]<<8 | - shortData[2]; // 5 microsec intervals ! - long tMillis = minuteMillis + t/200; + public static CPODClick makeFPODClick(long tMillis, long fileSamples, short[] shortData) { - // now a bit of time stretching. Need to get the start time and see how - // different this is, then it's a linear stretch. - tMillis = cpodControl.stretchClicktime(tMillis); - - - // do a sample number within the file as 5us intervals - long fileSamples = t + minuteMillis * 200; -// int micros = t%200; short nCyc = shortData[3]; short bw = shortData[4]; short kHz = shortData[5]; @@ -110,11 +105,42 @@ public class CPODClick extends PamDataUnit implement short spl = shortData[7]; short slope = shortData[8]; CPODClick cpodClick = new CPODClick(tMillis, fileSamples, nCyc, bw, kHz, endF, spl, slope, shortData); + + + + return cpodClick; + } + + /** + * Make a CPOD click. This called whenever click has been imported from a CP1 or CP3 file + * @param tMillis - the time in milliseconds datenum. + * @param fileSamples - the number of samples into the file the CPOD click is at - this is calculated from CPODClickDataBlock.CPOD_SR + * @param shortData - the raw data from the CPOD click. This can be 8 bytes or 40 bytes if a click train clcik + * @return a CPODClick object. + */ + public static CPODClick makeCPODClick(long tMillis, long fileSamples, short[] shortData) { + + short nCyc = shortData[3]; + short bw = shortData[4]; + short kHz = shortData[5]; + short endF = shortData[6]; + short spl = shortData[7]; + short slope = shortData[8]; + CPODClick cpodClick = new CPODClick(tMillis, fileSamples, nCyc, bw, kHz, endF, spl, slope, shortData); + +// //estimate the duration in millis - not accurate but gives an idea. + double duration = (nCyc/(double) kHz); + cpodClick.setDurationInMilliseconds(duration); + + + //TODO + //add classification info. + return cpodClick; } /** - * Constructor for a CPOD click. + * Constructor for a CPOD click. This adds all basic information that is required for a CPOD or FPOD click * @param tMillis - the time in millis. * @param fileSamples - the file samples * @param nCyc - the number of cycles @@ -135,13 +161,14 @@ public class CPODClick extends PamDataUnit implement this.spl = spl; this.slope = slope; double[] f = new double[2]; - f[0] = Math.min(kHz, endF)*1000; - f[1] = Math.max(kHz, endF)*1000; + + f[0] = (kHz - bw/2.)*1000.; + f[1] = (kHz + bw/2.)*1000.; + setFrequency(f); - //estimate the duration in millis - not accurate but gives an idea. double duration = (nCyc/(double) kHz); - this.setDurationInMilliseconds(duration); + setDurationInMilliseconds(duration); if (shortData!=null) { //only CPOD @@ -260,6 +287,7 @@ public class CPODClick extends PamDataUnit implement } return amplitudedB; } + /* (non-Javadoc) * @see PamDetection.AcousticDataUnit#getSummaryString() diff --git a/src/cpod/CPODControl.java b/src/cpod/CPODControl.java index 201184aa..58eec388 100644 --- a/src/cpod/CPODControl.java +++ b/src/cpod/CPODControl.java @@ -30,7 +30,8 @@ import PamguardMVC.dataOffline.OfflineDataLoadInfo; * @author Doug Gillespie * @author Jamie Macaulay * - */ + */ +@Deprecated public class CPODControl extends OfflineFileControl implements PamSettings { private CPODClickDataBlock cp1DataBlock, cp3DataBlock; diff --git a/src/cpod/CPODControl2.java b/src/cpod/CPODControl2.java index 83ee7726..dedb53cb 100644 --- a/src/cpod/CPODControl2.java +++ b/src/cpod/CPODControl2.java @@ -27,7 +27,7 @@ import pamViewFX.fxNodes.pamDialogFX.PamDialogFX2AWT; /** * CPOD control. Loads and manages CPOD and FPOD data into - * PAMGaurd. + *PAMGaurd. *

* Note that this module (CPODControl) originally used a folder of CP1 files as it's file store but * this version now converts CP1/CP3 etc. into binary files instead in order to integrate into PAMGuard's @@ -38,8 +38,6 @@ import pamViewFX.fxNodes.pamDialogFX.PamDialogFX2AWT; */ public class CPODControl2 extends PamControlledUnit implements PamSettings { - private static final float CPOD_SAMPLE_RATE = 200000; - private CPODClickDataBlock cp1DataBlock, cp3DataBlock; /** @@ -111,7 +109,7 @@ public class CPODControl2 extends PamControlledUnit implements PamSettings { cp3DataBlock.setOverlayDraw(new PamDetectionOverlayGraphics(cp3DataBlock, new PamSymbol())); PamSettingManager.getInstance().registerSettings(this); - cpodProcess.setSampleRate(CPOD_SAMPLE_RATE, false); + cpodProcess.setSampleRate(CPODClickDataBlock.CPOD_SR, false); cpodImporter = new CPODImporter(this); diff --git a/src/cpod/CPODDataGramProvider.java b/src/cpod/CPODDataGramProvider.java index 8c3dc2ce..6e2395b2 100644 --- a/src/cpod/CPODDataGramProvider.java +++ b/src/cpod/CPODDataGramProvider.java @@ -24,7 +24,17 @@ public class CPODDataGramProvider implements DatagramProvider { @Override public int addDatagramData(PamDataUnit dataUnit, float[] dataGramLine) { CPODClick cpodClick = (CPODClick) dataUnit; - dataGramLine[cpodClick.getkHz()] ++; + + int minKhz = cpodClick.getkHz()- cpodClick.getBw()/2; + int maxkHz = cpodClick.getkHz()- cpodClick.getBw()/2; + //each datagram line is a 1kHz bin + for (int i=0; i=minKhz && i<=maxkHz) { + dataGramLine[i] ++; + } + } + +// dataGramLine[cpodClick.getkHz()] ++; return 1; } diff --git a/src/cpod/CPODImporter.java b/src/cpod/CPODImporter.java index f4a04110..9702b6d4 100644 --- a/src/cpod/CPODImporter.java +++ b/src/cpod/CPODImporter.java @@ -17,6 +17,7 @@ import java.util.concurrent.Executors; import org.apache.commons.io.FilenameUtils; import PamController.PamController; +import PamUtils.PamArrayUtils; import PamUtils.PamCalendar; import PamView.dialog.warn.WarnOnce; import binaryFileStorage.BinaryDataSource; @@ -251,12 +252,22 @@ public class CPODImporter { data[7]=spl; data[8]=slope; - + //these are the basic data CPODClick cpodClick = new CPODClick(fpoDdata.getTimeMillis(), fileSamples, nCyc, bw, kHz, endF, spl, slope, data); + + if (fpoDdata.HasWave) { + int[] waveform = FPODReader.makeResampledWaveform(fpoDdata); + System.out.println("FPOD click waveform: " + kHz); + PamArrayUtils.printArray(waveform); + } + +// cpodClick.setDurationInMilliseconds((fpoDdata.duration*5.)/1000.); - + //does the click have a waveform? + //TODO + return cpodClick; } @@ -345,10 +356,25 @@ public class CPODImporter { private CPODClick processClick(int nMinutes, short[] shortData) { + + long minuteMillis = fileStart + nMinutes * 60000L; + int t = shortData[0]<<16 | + shortData[1]<<8 | + shortData[2]; // 5 microsec intervals ! + long tMillis = minuteMillis + t/200; + + // now a bit of time stretching. Need to get the start time and see how + // different this is, then it's a linear stretch. + tMillis = cpodControl.stretchClicktime(tMillis); + + + // do a sample number within the file as 5us intervals + long fileSamples = t + minuteMillis * 200; + /* * */ - return CPODClick.makeClick(cpodControl, fileStart + nMinutes * 60000L, shortData); + return CPODClick.makeCPODClick(tMillis, fileSamples, shortData); } diff --git a/src/cpod/CPODLoader.java b/src/cpod/CPODLoader.java index 73d4dbfb..2c26315c 100644 --- a/src/cpod/CPODLoader.java +++ b/src/cpod/CPODLoader.java @@ -17,6 +17,7 @@ import fileOfflineData.OfflineFileMapPoint; * @author Doug Gillespie * */ +@Deprecated public class CPODLoader { private CPODControl cpodControl; diff --git a/src/cpod/FPODReader.java b/src/cpod/FPODReader.java index 99f3cafd..bcfff3f7 100644 --- a/src/cpod/FPODReader.java +++ b/src/cpod/FPODReader.java @@ -9,17 +9,38 @@ import java.util.ArrayList; /** - * Functions for importing FPOD files. Noe this class is independent of any PAMGuard functionality. + * Functions for importing FPOD files. + *

+ * Note this class should be independent of any PAMGuard functionality. + *

+ * Although some anming has changed a lot of the variable names are consistent with Pascal code + * used in FPOD.exe software from whihc this is absed. * * @author Jamie Macaulay */ public class FPODReader { + /** + * Look up array to convert byte values to linear sound level + */ private static int[] LinearPkValsArr; + /** + * Look up array to convert byte values to linear sound level if using extended amps. + */ private static int[][] ClippedPkArr; + - + /** + * Look up sine array fro reconstructing waveforms. + */ + private static double[] SineArr = new double[2000]; + + /** + * Look up sine array for converting IPI (inter-pulse-interval) to kHz values + */ + private static int[] IPItoKHZ = new int[257]; + /** * Length of the FPOD header in bytes. */ @@ -37,6 +58,7 @@ public class FPODReader { */ private static final int FP3_FPOD_DATA_LEN = 32; + /** * Import an FPOD file. * @param cpFile - the FP1 file. @@ -48,6 +70,7 @@ public class FPODReader { public static int importFile(File cpFile, ArrayList fpodData, int from, int maxNum ) throws IOException { populateRawToRealPkArrays(); + populateIPIArray(); BufferedInputStream bis = null; int bytesRead; @@ -175,7 +198,8 @@ public class FPODReader { fpodClick.EndIPI = bufPosN[15] & 254 + 1; // + 1 on all IPIs because counts from the POD start at } - fpodClick.duration = ((bufPosN[13] & 240) << 4 | bufPosN[14]); + //the duration is in 5us units. + fpodClick.duration = ((bufPosN[13] & 240)*16 + toUnsigned(bufPosN[14])); ///rm...can't exactly explain this but it's translated from FPOD Pascal code - calculates bandwidth int ampDfSum = Math.abs(fpodClick.Pkminus1Extnd - fpodClick.MaxPkRaw); @@ -233,7 +257,7 @@ public class FPODReader { if (nClicks%100000==0) { - System.out.println("Pod data: " + nClicks + " " +fpodClick.getTimeMillis() + " " +fpodClick.dataString()); + System.out.println("Pod data: " + nClicks + " " +fpodClick.getTimeMillis() + " " +fpodClick.dataString() + " " +toUnsigned(bufPosN[13]) + " " + toUnsigned(bufPosN[14])); } @@ -377,7 +401,24 @@ public class FPODReader { * @return the kHz value */ public static int IPItoKhz(int IPI) { - return 4000/IPI; + return IPItoKHZ[IPI]; + } + + /** + * Ppulate the IPI array + */ + public static void populateIPIArray() { + + for (int count = 0; count < 16; count++) { + IPItoKHZ[count] = 255; + } + + for (int count = 16; count < 256; count++) { + IPItoKHZ[count] = Math.round(4000 / count); + } + + IPItoKHZ[64] = 63; // Smoothes an uncomfortable step here + IPItoKHZ[256] = 1; // An 'indicative' value } @@ -883,7 +924,7 @@ public class FPODReader { /** * Holds FPOD wav data. Note this is not actually wav data - * but the amplitue and inter pule interval of successive peaks + * but the amplitude and inter pulse interval of successive peaks * in the waveform. */ public static class FPODWavData { @@ -1068,14 +1109,92 @@ public class FPODReader { } + + + public static void BuildSineArray() { + + final double constPiFrac = Math.PI / 1000; + double S; + for (int count = 0; count < 2000; count++) { + S = Math.sin(constPiFrac * count); + SineArr[count] = S; + } + } + + /** + * Reconstructs sinusoidal waveform from the peaks which have been sampled at 4MHz + * + * @param click - FPOD click with waveform information. + */ + public static int[] makeResampledWaveform(FPODdata click) { + + if (SineArr==null) { + BuildSineArray(); + } + + int[] MhzSampledArr = new int[23]; + + int count, cyc, SinePtsPerUs, SinePtr, FirstClkCyc, IPIsum, NewIPIx, OldIPIx; + + // MhzSampledArr initialization (assuming it's an array) + + // Read back from end of WavIPIarr to find start of continuous sound data + int RawStartPtr = 21; + + + while (RawStartPtr > 0 && click.getWavData().getWavValsIPI()[RawStartPtr] < 255) { + click.getWavData().getWavValsSPL()[RawStartPtr] = (short) LinearPkValsArr[click.getWavData().getWavValsSPL()[RawStartPtr]]; + RawStartPtr--; + } + RawStartPtr = Math.min(21, RawStartPtr + 1); + FirstClkCyc = 21 - click.Ncyc; + + // Construct each cycle in MhzSampledArr + SinePtr = 0; + int MHzArrPtr = 0; + int MaxSPLval = 0; + IPIsum = 0; + + cyc = RawStartPtr; + + do { + // Populate MhzSampledArr + SinePtsPerUs = Math.round(4000 / click.getWavData().getWavValsIPI()[cyc]); + do { + MhzSampledArr[MHzArrPtr] = (int) Math.round(SineArr[SinePtr] * click.getWavData().getWavValsSPL()[cyc]); + MHzArrPtr++; + SinePtr += SinePtsPerUs; + } while (SinePtr <= 1999 && MHzArrPtr < MhzSampledArr.length); + + if (MHzArrPtr >= MhzSampledArr.length) { + break; // Fix: extend this array if needed + } + SinePtr -= 2000; + if (cyc == FirstClkCyc) { + int StartOfClickHighRes = MHzArrPtr; + } + IPIsum += click.getWavData().getWavValsIPI()[cyc]; + cyc++; + } while (cyc < 22); + + // Bring line up to zero + if (MHzArrPtr < MhzSampledArr.length) { + MhzSampledArr[MHzArrPtr] = 0; + } + + return MhzSampledArr; + } + /** * Test the program * @param args */ public static void main(String[] args) { - String filePath = "/Users/au671271/Library/CloudStorage/GoogleDrive-macster110@gmail.com/My Drive/PAMGuard_dev/CPOD/FPOD_NunBank/0866 NunBankB 2023 06 27 FPOD_6480 file0.FP1"; +// String filePath = "/Users/au671271/Library/CloudStorage/GoogleDrive-macster110@gmail.com/My Drive/PAMGuard_dev/CPOD/FPOD_NunBank/0866 NunBankB 2023 06 27 FPOD_6480 file0.FP1"; + String filePath = "D:\\My Drive\\PAMGuard_dev\\CPOD\\FPOD_NunBank\\0866 NunBankB 2023 06 27 FPOD_6480 file0.FP1"; + File fpfile = new File(filePath); ArrayList fpodData = new ArrayList(); diff --git a/src/cpod/dataPlotFX/CPODPlotInfoFX.java b/src/cpod/dataPlotFX/CPODPlotInfoFX.java index a9446a5b..63a0c0c6 100644 --- a/src/cpod/dataPlotFX/CPODPlotInfoFX.java +++ b/src/cpod/dataPlotFX/CPODPlotInfoFX.java @@ -3,6 +3,7 @@ package cpod.dataPlotFX; import java.awt.geom.Path2D; import PamController.PamControlledUnit; +import PamUtils.PamArrayUtils; import PamUtils.PamUtils; import PamView.HoverData; import PamView.GeneralProjector.ParameterType; @@ -124,45 +125,98 @@ public class CPODPlotInfoFX extends GenericDataPlotInfo { public Polygon drawDataUnit(int plotNumber, PamDataUnit pamDataUnit, GraphicsContext g, double scrollStart, TDProjectorFX tdProjector, int type) { // if (getScaleInfoIndex()==getScaleInfos().indexOf(frequencyInfo)) drawClickFFT( plotNumber, pamDataUnit,g , scrollStart, tdProjector, type); - //System.out.println("ClickPlotInfo: Draw data unit: " + pamDataUnit.getUID()); //draw special data units. Path2D path2D = null; ParameterType paramType = getCurrentScaleInfo().getDataType(); - - // if (getScaleInfoIndex()==getScaleInfos().indexOf(stemScaleInfo)) - if (getCurrentScaleInfo().getDataType() == ParameterType.AMPLITUDE_STEM){ - //draw on a stem plot. + + switch (getCurrentScaleInfo().getDataType()) { + + case AMPLITUDE_STEM: + case NCYCLES: + case AMPLITUDE_LIN: + case BANDWIDTH: + case FREQUENCY: path2D = drawStemClick( plotNumber, pamDataUnit,g , scrollStart, tdProjector, type, paramType); + break; + default: + return super.drawDataUnit(plotNumber, pamDataUnit, g, scrollStart, tdProjector, type); } - else if (getCurrentScaleInfo().getDataType() == ParameterType.NCYCLES){ - //draw CPOD cycles. - path2D = drawStemClick( plotNumber, pamDataUnit,g , scrollStart, tdProjector, type, paramType); - - } - - else if (getCurrentScaleInfo().getDataType() == ParameterType.AMPLITUDE_LIN){ - //draw cpod SPL. - path2D = drawStemClick( plotNumber, pamDataUnit,g , scrollStart, tdProjector, type, paramType); - } - - else if (getCurrentScaleInfo().getDataType() == ParameterType.BANDWIDTH){ - //draw cpod SPL. - path2D = drawStemClick( plotNumber, pamDataUnit,g , scrollStart, tdProjector, type, paramType); - } - - else return super.drawDataUnit(plotNumber, pamDataUnit, g, scrollStart, tdProjector, type); - //add to hover list if special data units. if (path2D!=null && type!=TDSymbolChooserFX.HIGHLIGHT_SYMBOL && type!=TDSymbolChooserFX.HIGHLIGHT_SYMBOL_MARKED ){ tdProjector.addHoverData(new HoverData(path2D, pamDataUnit, 0, plotNumber)); return null; } - return null; } + + /** + * Draw a frequency line + * @param plotNumber + * @param pamDataUnit + * @param g + * @param scrollStart + * @param tdProjector + * @param type + * @return + */ + @Override + public Polygon drawFrequencyData(int plotNumber, PamDataUnit pamDataUnit, GraphicsContext g, double scrollStart, + TDProjectorFX tdProjector, int type) { + + + g.setLineDashes(null); + g.setLineWidth(2); + + double[] f = pamDataUnit.getFrequency(); + if (f == null) { + return null; + } + if (f.length == 1) { + System.out.println("CPODPlot: Single frequency measure in data unit " + pamDataUnit.toString()); + } + + // draw a frequency box. + double y0 = tdProjector.getYPix(f[0]); + double y1 = tdProjector.getYPix(f[1]); + double x0 = tdProjector.getTimePix(pamDataUnit.getTimeMilliseconds()-scrollStart); + double x1 = tdProjector.getTimePix(pamDataUnit.getEndTimeInMilliseconds()-scrollStart); + + + System.out.println("CPODPlotInfoFX: Draw freq data unit: x: " + x0 + " y " + " y1: " + y1 + " to " + y0 + " cpod_data " + ((CPODClick) pamDataUnit).getBw()); + PamArrayUtils.printArray(f); + + g.setStroke(getSymbolChooser().getPamSymbol(pamDataUnit, type).getLineColor()); + + Color fillCol = getSymbolChooser().getPamSymbol(pamDataUnit, type).getFillColor(); + g.setFill(Color.color(fillCol.getRed(), fillCol.getGreen(), fillCol.getBlue(), 0.4)); //add alpha + + g.strokeLine(x0, y0, x0, y1); + + + //create the polygon. + + + + Path2D path2D= new Path2D.Double(0,1); + + // if (Math.abs(x1-x0)>50) { + // + // System.out.println("Generic Data Plot: " + "x0: " + x0 + " x1: " + x1 + " y1: " + y1 + " y: " + y0); + // } + + path2D.moveTo(x0, y0); + path2D.lineTo(x0, y1); + + + tdProjector.addHoverData(new HoverData(path2D, pamDataUnit, 0, plotNumber)); + + + return null; + } + /** * Specific ways to plot CPOD data as NYCLES, AMPLITUDE_LIN and AMPLITUDE_STEM. * @param plotNumber - the plot on which the FFT is drawing. @@ -219,17 +273,26 @@ public class CPODPlotInfoFX extends GenericDataPlotInfo { y1=tdProjector.getYPix(1); x2=tC; y2= tdProjector.getYPix(pamDataUnit.getAmplitudeDB()); - - break; - + case AMPLITUDE_LIN: + double spl = ((CPODClick) pamDataUnit).getSpl()/255.0; x1=tC; y1=tdProjector.getYPix(-spl); x2=tC; y2= tdProjector.getYPix(spl); break; + + case FREQUENCY: + + double[] freq = pamDataUnit.getFrequency(); + x1=tC; + y1=tdProjector.getYPix(freq[0]); + x2=tC; + y2= tdProjector.getYPix(freq[1]); + break; + case NCYCLES: case BANDWIDTH: double nycl = ((CPODClick) pamDataUnit).getnCyc(); diff --git a/src/dataPlotsFX/overlaymark/menuOptions/MLExport/MLExportOverlayMenu.java b/src/dataPlotsFX/overlaymark/menuOptions/MLExport/MLExportOverlayMenu.java index fe435567..272bbaf3 100644 --- a/src/dataPlotsFX/overlaymark/menuOptions/MLExport/MLExportOverlayMenu.java +++ b/src/dataPlotsFX/overlaymark/menuOptions/MLExport/MLExportOverlayMenu.java @@ -8,6 +8,8 @@ import javafx.scene.control.Labeled; import javafx.scene.control.Tooltip; import javafx.scene.image.ImageView; import javafx.scene.paint.Color; +import javafx.scene.text.Text; +import pamViewFX.fxGlyphs.PamGlyphDude; import pamViewFX.fxGlyphs.PamSVGIcon; import pamViewFX.fxNodes.PamButton; import pamViewFX.fxNodes.pamDialogFX.PamDialogFX; @@ -70,9 +72,8 @@ public class MLExportOverlayMenu extends ExportOverlayMenu { private PamButton createButton() { PamButton button = new PamButton(""); - if (svgsprite==null) { - try { - +// if (svgsprite==null) { +// try { // // // load the svg file // InputStream svgFile = @@ -84,20 +85,21 @@ public class MLExportOverlayMenu extends ExportOverlayMenu { // // button.setGraphic(svgImage); - PamSVGIcon svgIconMaker = new PamSVGIcon(); +// PamSVGIcon svgIconMaker = new PamSVGIcon(); +// svgsprite = svgIconMaker.create(getClass().getResource("/Resources/matlab_icon2.svg").toURI().toURL(), Color.WHITE, 1); +//// "-fx-fill: white; -fx-stroke-width: 2;"); +// svgsprite.setFitHeight(standardIconSize+7); +// svgsprite.setFitWidth(standardIconSize+7); + + Text matlabIcon=PamGlyphDude.createPamIcon("file-matlab", standardIconSize+7); - - svgsprite = svgIconMaker.create(getClass().getResource("/Resources/matlab_icon2.svg").toURI().toURL(), Color.WHITE, 1); -// "-fx-fill: white; -fx-stroke-width: 2;"); - svgsprite.setFitHeight(standardIconSize+7); - svgsprite.setFitWidth(standardIconSize+7); - button.setGraphic(svgsprite.getSpriteNode()); + button.setGraphic(matlabIcon); - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } +// } catch (Exception e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } +// } return button; } diff --git a/src/dataPlotsFX/overlaymark/menuOptions/RExport/RExportOverlayMenu.java b/src/dataPlotsFX/overlaymark/menuOptions/RExport/RExportOverlayMenu.java index 3d2d9802..2226f9f9 100644 --- a/src/dataPlotsFX/overlaymark/menuOptions/RExport/RExportOverlayMenu.java +++ b/src/dataPlotsFX/overlaymark/menuOptions/RExport/RExportOverlayMenu.java @@ -22,6 +22,8 @@ import javafx.scene.control.Tooltip; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.paint.Color; +import javafx.scene.text.Text; +import pamViewFX.fxGlyphs.PamGlyphDude; import pamViewFX.fxGlyphs.PamSVGIcon; import pamViewFX.fxNodes.PamButton; import pamViewFX.fxNodes.pamDialogFX.PamDialogFX; @@ -65,29 +67,31 @@ public class RExportOverlayMenu extends ExportOverlayMenu { // return button; PamButton button = new PamButton(); + Text matlabIcon=PamGlyphDude.createPamIcon("file-r", standardIconSize+7); + button.setGraphic(matlabIcon); - PamSVGIcon svgsprite; - try { - -// System.out.println("START SVG load R"); - - PamSVGIcon svgIconMaker = new PamSVGIcon(); - - svgsprite = svgIconMaker.create(getClass().getResource("/Resources/r-project.svg").toURI().toURL(), Color.WHITE, 1); - -// svgsprite = PamSVGIcon.create(new File(getClass().getResource("/Resources/r-project.svg").toURI()), -// "-fx-fill: white; -fx-stroke-width: 2;"); - svgsprite.setFitHeight(standardIconSize+7); - svgsprite.setFitWidth(standardIconSize+7); - button.setGraphic(svgsprite.getSpriteNode()); - -// System.out.println("END SVG load R"); - - - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } +// PamSVGIcon svgsprite; +// try { +// +//// System.out.println("START SVG load R"); +// +// PamSVGIcon svgIconMaker = new PamSVGIcon(); +// +// svgsprite = svgIconMaker.create(getClass().getResource("/Resources/r-project.svg").toURI().toURL(), Color.WHITE, 1); +// +//// svgsprite = PamSVGIcon.create(new File(getClass().getResource("/Resources/r-project.svg").toURI()), +//// "-fx-fill: white; -fx-stroke-width: 2;"); +// svgsprite.setFitHeight(standardIconSize+7); +// svgsprite.setFitWidth(standardIconSize+7); +// button.setGraphic(svgsprite.getSpriteNode()); +// +//// System.out.println("END SVG load R"); +// +// +// } catch (Exception e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } return button; } diff --git a/src/pamViewFX/fxNodes/utilityPanes/SettingsDialog.java b/src/pamViewFX/fxNodes/utilityPanes/SettingsDialog.java index eee2c9e5..8802763d 100644 --- a/src/pamViewFX/fxNodes/utilityPanes/SettingsDialog.java +++ b/src/pamViewFX/fxNodes/utilityPanes/SettingsDialog.java @@ -4,6 +4,7 @@ import javafx.stage.Stage; import javafx.stage.StageStyle; import pamViewFX.PamGuiManagerFX; import pamViewFX.fxNodes.pamDialogFX.PamDialogFX; +import pamViewFX.fxStyles.PamStylesManagerFX; import PamController.PamController; import PamController.SettingsPane; @@ -21,11 +22,11 @@ public class SettingsDialog extends PamDialogFX{ public SettingsDialog(SettingsPane settingsPane){ super(PamGuiManagerFX.getInstance().getPrimaryStage() /*TODO - add stage*/, settingsPane.getName(), StageStyle.DECORATED); + this.getDialogPane().getStylesheets().add(PamStylesManagerFX.getPamStylesManagerFX().getCurStyle().getDialogCSS()); this.setResizable(true); this.settingsPane=settingsPane; this.setContent(settingsPane.getContentNode()); // this.getDialogPane().getStylesheets().add(PamController.getInstance().getGuiManagerFX().getPamSettingsCSS()); - this.getDialogPane().getStylesheets().add(PamController.getInstance().getGuiManagerFX().getPamDialogCSS()); Stage stage = (Stage) this.getDialogPane().getScene().getWindow(); stage.toFront(); diff --git a/src/rawDeepLearningClassifier/DLControl.java b/src/rawDeepLearningClassifier/DLControl.java index 602ab676..4ea85db9 100644 --- a/src/rawDeepLearningClassifier/DLControl.java +++ b/src/rawDeepLearningClassifier/DLControl.java @@ -36,9 +36,8 @@ import rawDeepLearningClassifier.dlClassification.DLClassifyProcess; import rawDeepLearningClassifier.dlClassification.animalSpot.SoundSpotClassifier; import rawDeepLearningClassifier.dlClassification.archiveModel.ZipModelClassifier; import rawDeepLearningClassifier.dlClassification.genericModel.GenericDLClassifier; -import rawDeepLearningClassifier.dlClassification.ketos.KetosClassifier; +import rawDeepLearningClassifier.dlClassification.ketos.KetosClassifier2; import rawDeepLearningClassifier.dlClassification.koogu.KooguClassifier; -import rawDeepLearningClassifier.layoutFX.DLModelSelectPane; import rawDeepLearningClassifier.layoutFX.DLSidePanelSwing; import rawDeepLearningClassifier.layoutFX.DLSymbolManager; import rawDeepLearningClassifier.layoutFX.PredictionSymbolManager; @@ -255,7 +254,7 @@ public class DLControl extends PamControlledUnit implements PamSettings { /***** Add new deep learning models here ****/ dlModels.add(new SoundSpotClassifier(this)); - dlModels.add(new KetosClassifier(this)); + dlModels.add(new KetosClassifier2(this)); dlModels.add(new KooguClassifier(this)); dlModels.add(new ZipModelClassifier(this)); //it is important the Generic Model is last because we need to check @@ -408,7 +407,6 @@ public class DLControl extends PamControlledUnit implements PamSettings { settingsPane = new DLSettingsPane(this); } - System.out.println("Get DL raw settings pane..."); return settingsPane; } @@ -423,8 +421,6 @@ public class DLControl extends PamControlledUnit implements PamSettings { * @param parentFrame - the frame. */ public void showSettingsDialog(Frame parentFrame) { - System.out.println("Get DL raw settings pane BAD..."); - if (settingsDialog == null || parentFrame != settingsDialog.getOwner()) { SettingsPane setPane = (SettingsPane) getSettingsPane(); setPane.setParams(this.rawDLParmas); diff --git a/src/rawDeepLearningClassifier/dlClassification/DLClassifyProcess.java b/src/rawDeepLearningClassifier/dlClassification/DLClassifyProcess.java index d2b79841..ac331438 100644 --- a/src/rawDeepLearningClassifier/dlClassification/DLClassifyProcess.java +++ b/src/rawDeepLearningClassifier/dlClassification/DLClassifyProcess.java @@ -533,6 +533,7 @@ public class DLClassifyProcess extends PamInstantProcess { @Override public void pamStart() { // TODO Auto-generated method stub + System.out.println("PREP MODEL:"); this.dlControl.getDLModel().prepModel(); } diff --git a/src/rawDeepLearningClassifier/dlClassification/StandardClassifierModel.java b/src/rawDeepLearningClassifier/dlClassification/StandardClassifierModel.java index 8a73cd1f..8bde670a 100644 --- a/src/rawDeepLearningClassifier/dlClassification/StandardClassifierModel.java +++ b/src/rawDeepLearningClassifier/dlClassification/StandardClassifierModel.java @@ -100,7 +100,7 @@ public abstract class StandardClassifierModel implements DLClassiferModel, PamSe @Override public void prepModel() { - //System.out.println("PrepModel! !!!"); +// System.out.println("STANDARD CLASSIFIER MODEL PREP MODEL! !!!"); StandardModelParams oldParams = getDLParams().clone(); getDLWorker().prepModel(getDLParams(), dlControl); diff --git a/src/rawDeepLearningClassifier/dlClassification/animalSpot/StandardAdvModelPane.java b/src/rawDeepLearningClassifier/dlClassification/animalSpot/StandardAdvModelPane.java index 01e25524..1842dada 100644 --- a/src/rawDeepLearningClassifier/dlClassification/animalSpot/StandardAdvModelPane.java +++ b/src/rawDeepLearningClassifier/dlClassification/animalSpot/StandardAdvModelPane.java @@ -121,7 +121,7 @@ public class StandardAdvModelPane extends SettingsPane { @Override public void setParams(StandardModelParams params) { - //System.out.println("Set advanced pane params: " + params.useDefaultTransfroms); +// System.out.println("Set advanced pane params: " + params.dlTransfroms.size()); if (params.dlTransfroms==null) { mainPane.setTop(null); mainPane.setCenter(new Label("A model must be loaded before \n " diff --git a/src/rawDeepLearningClassifier/dlClassification/animalSpot/StandardModelPane.java b/src/rawDeepLearningClassifier/dlClassification/animalSpot/StandardModelPane.java index 32168da8..ae51ea25 100644 --- a/src/rawDeepLearningClassifier/dlClassification/animalSpot/StandardModelPane.java +++ b/src/rawDeepLearningClassifier/dlClassification/animalSpot/StandardModelPane.java @@ -6,6 +6,7 @@ import org.controlsfx.control.PopOver; import org.controlsfx.control.ToggleSwitch; import PamController.SettingsPane; +import PamUtils.PamArrayUtils; import PamView.dialog.warn.WarnOnce; import javafx.geometry.Insets; import javafx.geometry.Pos; @@ -143,6 +144,10 @@ public abstract class StandardModelPane extends SettingsPane{ defaultSegmentLenChanged(); + //only set the hop if the user physically changes the toggle switch. This is not included in defaultSegmentLenChanged + //becuase defaultSegmentLenChanged can be called from elsewhere + int defaultsamples = getDefaultSamples(); + dlClassifierModel.getDLControl().getSettingsPane().getHopLenSpinner().getValueFactory().setValue((int) defaultsamples/2); }); usedefaultSeg.setPadding(new Insets(0,0,0,0)); //there is an issue with the toggle switch which means that it has dead space to the left if @@ -212,13 +217,13 @@ public abstract class StandardModelPane extends SettingsPane getDLWorker() { - return getKetosWorker(); + return getModelWorker(); } @@ -100,7 +109,7 @@ public abstract class ArchiveModelClassifier extends StandardClassifierModel { * Get the KetosWorker. this handles loading and running the Ketos model. * @return the Ketos worker. */ - public ArchiveModelWorker getKetosWorker() { + public ArchiveModelWorker getModelWorker() { if (archiveModelWorker==null) { archiveModelWorker= new ArchiveModelWorker(); } @@ -123,7 +132,7 @@ public abstract class ArchiveModelClassifier extends StandardClassifierModel { @Override public Serializable getSettingsReference() { if (standardDLParams==null) { - standardDLParams = new StandardModelParams(); + standardDLParams = makeParams(); } ArrayList dlTransformParams = DLClassiferModel.getDLTransformParams(standardDLParams.dlTransfroms); @@ -153,9 +162,18 @@ public abstract class ArchiveModelClassifier extends StandardClassifierModel { .makeDLTransforms((ArrayList) standardDLParams.dlTransfromParams); } } else - standardDLParams = new StandardModelParams(); + standardDLParams = makeParams(); return true; } + + /** + * Create the parameters class for the model. This can be overridden for bespoke parameters. + *classes. + * @return a new parameters class object. + */ + public StandardModelParams makeParams() { + return new StandardModelParams(); + } @Override public boolean isModelType(URI uri) { diff --git a/src/rawDeepLearningClassifier/dlClassification/archiveModel/ArchiveModelPane.java b/src/rawDeepLearningClassifier/dlClassification/archiveModel/ArchiveModelPane.java index 46ed7a60..1f493e92 100644 --- a/src/rawDeepLearningClassifier/dlClassification/archiveModel/ArchiveModelPane.java +++ b/src/rawDeepLearningClassifier/dlClassification/archiveModel/ArchiveModelPane.java @@ -18,6 +18,8 @@ public class ArchiveModelPane extends StandardModelPane { @Override public void newModelSelected(File file) { + + //the model has to set some of the parameters for the UI . //A ketos model contains information on the transforms, duration and the class names. this.setCurrentSelectedFile(file); @@ -27,7 +29,7 @@ public class ArchiveModelPane extends StandardModelPane { } - StandardModelParams params = getParams(getParamsClone()); + StandardModelParams params = getParamsClone(); // if (params.dlTransfromParams!=null) { @@ -44,20 +46,17 @@ public class ArchiveModelPane extends StandardModelPane { * model or to use the existing transforms in the settings. */ archiveModelClassifier.getDLWorker().prepModel(params, archiveModelClassifier.getDLControl()); - //get the model transforms calculated from the model by SoundSpoyWorker and apply them to our temporary params clone. -// System.out.println("Ketos transforms 1: " + this.ketosClassifier.getKetosWorker().getModelTransforms()); + + //get the model transforms calculated from the model by the worker and apply them to our temporary params clone. getParamsClone().dlTransfroms = this.archiveModelClassifier.getDLWorker().getModelTransforms(); // if (getParamsClone().defaultSegmentLen!=null) { // usedefaultSeg.setSelected(true); // } - -// System.out.println("Ketos: new model selected " + getParamsClone().dlTransfroms.size()); + ///set the advanced pane parameters. getAdvSettingsPane().setParams(getParamsClone()); - - } } diff --git a/src/rawDeepLearningClassifier/dlClassification/archiveModel/ArchiveModelUI.java b/src/rawDeepLearningClassifier/dlClassification/archiveModel/ArchiveModelUI.java index 4b454268..7bb2a59b 100644 --- a/src/rawDeepLearningClassifier/dlClassification/archiveModel/ArchiveModelUI.java +++ b/src/rawDeepLearningClassifier/dlClassification/archiveModel/ArchiveModelUI.java @@ -12,12 +12,12 @@ import rawDeepLearningClassifier.dlClassification.animalSpot.StandardModelParams import rawDeepLearningClassifier.layoutFX.DLCLassiferModelUI; public class ArchiveModelUI implements DLCLassiferModelUI { - + /** * Pane containing controls to set up the OrcaSPot classifier. */ private StandardModelPane standardSettingsPane; - + /** * The sound spot classifier. */ @@ -27,22 +27,19 @@ public class ArchiveModelUI implements DLCLassiferModelUI { * The extension filter. */ private ArrayList extensionFilters; - + /** * SondSpot classifier. * @param soundSpotClassifier */ public ArchiveModelUI(ArchiveModelClassifier archiveClassifier) { this.archiveModel=archiveClassifier; - - extensionFilters = new ArrayList(); - - String[] fileExt = archiveModel.getFileExtensions(); - - for (int i=0; i(); +// +// String[] fileExt = archiveModel.getFileExtensions(); +// +// extensionFilters.add(new ExtensionFilter(archiveClassifier.getName(), fileExt)); } @@ -60,25 +57,29 @@ public class ArchiveModelUI implements DLCLassiferModelUI { archiveModel.setDLParams(params); } - + @Override public void setParams() { -// System.out.println("Set model params: " + genericModelClassifier.getGenericDLParams().dlTransfromParams.size()); + // System.out.println("Set model params: " + genericModelClassifier.getGenericDLParams().dlTransfromParams.size()); getSettingsPane().setParams(archiveModel.getDLParams()); } - + @Override public JPanel getSidePanel() { //no side pane for Ketos just now. return null; } - + @Override public List getModelFileExtensions() { + if (extensionFilters == null) { + extensionFilters = new ArrayList(); + extensionFilters.add(new ExtensionFilter(archiveModel.getName(), archiveModel.getFileExtensions())); + } return extensionFilters; } - + } \ No newline at end of file diff --git a/src/rawDeepLearningClassifier/dlClassification/archiveModel/ArchiveModelWorker.java b/src/rawDeepLearningClassifier/dlClassification/archiveModel/ArchiveModelWorker.java index 83f7ae3c..d5f17acf 100644 --- a/src/rawDeepLearningClassifier/dlClassification/archiveModel/ArchiveModelWorker.java +++ b/src/rawDeepLearningClassifier/dlClassification/archiveModel/ArchiveModelWorker.java @@ -1,12 +1,12 @@ package rawDeepLearningClassifier.dlClassification.archiveModel; import java.io.File; +import java.io.IOException; import java.nio.file.Paths; import java.util.ArrayList; import org.jamdev.jdl4pam.ArchiveModel; import org.jamdev.jdl4pam.genericmodel.GenericModelParams; -import org.jamdev.jdl4pam.ketos.KetosModel; import org.jamdev.jdl4pam.transforms.DLTransform; import org.jamdev.jdl4pam.transforms.DLTransformsFactory; import org.jamdev.jdl4pam.transforms.jsonfile.DLTransformParser2; @@ -14,224 +14,240 @@ import org.jamdev.jdl4pam.transforms.jsonfile.DLTransformsParser; import org.json.JSONObject; import PamView.dialog.warn.WarnOnce; +import ai.djl.MalformedModelException; import rawDeepLearningClassifier.DLControl; import rawDeepLearningClassifier.dlClassification.animalSpot.StandardModelParams; import rawDeepLearningClassifier.dlClassification.genericModel.DLModelWorker; import rawDeepLearningClassifier.dlClassification.genericModel.GenericPrediction; +/** + * + * Runs a Ketos deep learning model and performs feature extraction. + *

+ * + * @author Jamie Macaulay + * + */ +public class ArchiveModelWorker extends DLModelWorker { + + /** - * - * Runs a Ketos deep learning model and performs feature extraction. - *

- * - * @author Jamie Macaulay - * + * The ketos model */ - public class ArchiveModelWorker extends DLModelWorker { + private ArchiveModel dlModel; + + /** + * Thelast loaded model path., + */ + private String currentPath; - /** - * The ketos model - */ - private ArchiveModel dlModel; - - /** - * Thelast loaded model path., - */ - private String currentPath; + /** + * SoundSpotWorker constructor. + */ + public ArchiveModelWorker() { + this.setEnableSoftMax(false); + } + + /** + * Prepare the model + */ + public void prepModel(StandardModelParams dlParams, DLControl dlControl) { + //ClassLoader origCL = Thread.currentThread().getContextClassLoader(); + try { + + // get the plugin class loader and set it as the context class loader + // NOTE THAT THIS IS REQUIRED TO MAKE THIS MODULE RUN AS A PLUGIN WHEN THE CLASS FILES + // ARE BUNDLED INTO A FATJAR, HOWEVER THIS WILL STOP THE PLUGIN FROM RUNNING AS A SEPARATE + // PROJECT IN ECLIPSE. So while testing the code and debugging, make sure the + // if (DLControl.PLUGIN_BUILD) { + // PluginClassloader newCL = PamModel.getPamModel().getClassLoader(); + // Thread.currentThread().setContextClassLoader(newCL); + // } + //first open the model and get the correct parameters. + //21/11/2022 - Added a null and filename check here to stop the mdoel reloading everytime PAMGuard hits a new file or + //is stopped or started - this was causing a memory leak. + if (dlModel==null || currentPath ==null || !Paths.get(currentPath).equals(Paths.get(dlParams.modelPath))) { - /** - * SoundSpotWorker constructor. - */ - public ArchiveModelWorker() { - this.setEnableSoftMax(false); + //TODO + // if (ketosModel!=null && ketosModel.getModel()!=null) { + // ketosModel.getModel().close(); + // } + + //System.out.println(Paths.get(genericParams.modelPath)); + this.currentPath = dlParams.modelPath; + dlModel = loadModel(currentPath); + //System.out.println("LOAD A NEW MODEL: "); + //System.out.println(genericModel.getModel().getModelPath().getFileName()); + } + } + catch (Exception e) { + e.printStackTrace(); + //WarnOnce.showWarning(null, "Model Load Error", "There was an error loading the model file.", WarnOnce.OK_OPTION); } - /** - * Prepare the model - */ - public void prepModel(StandardModelParams dlParams, DLControl dlControl) { - //ClassLoader origCL = Thread.currentThread().getContextClassLoader(); - try { + try { - // get the plugin class loader and set it as the context class loader - // NOTE THAT THIS IS REQUIRED TO MAKE THIS MODULE RUN AS A PLUGIN WHEN THE CLASS FILES - // ARE BUNDLED INTO A FATJAR, HOWEVER THIS WILL STOP THE PLUGIN FROM RUNNING AS A SEPARATE - // PROJECT IN ECLIPSE. So while testing the code and debugging, make sure the -// if (DLControl.PLUGIN_BUILD) { -// PluginClassloader newCL = PamModel.getPamModel().getClassLoader(); -// Thread.currentThread().setContextClassLoader(newCL); -// } - //first open the model and get the correct parameters. - //21/11/2022 - Added a null and filename check here to stop the mdoel reloading everytime PAMGuard hits a new file or - //is stopped or started - this was causing a memory leak. - if (dlModel==null || currentPath ==null || !Paths.get(currentPath).equals(Paths.get(dlParams.modelPath))) { - - - //TODO -// if (ketosModel!=null && ketosModel.getModel()!=null) { -// ketosModel.getModel().close(); -// } + //read the JSON string from the the file. + String jsonString = DLTransformsParser.readJSONString(new File(dlModel.getAudioReprFile())); - //System.out.println(Paths.get(genericParams.modelPath)); - this.currentPath = dlParams.modelPath; - dlModel = new ArchiveModel(new File(dlParams.modelPath)); - //System.out.println("LOAD A NEW MODEL: "); - //System.out.println(genericModel.getModel().getModelPath().getFileName()); - } - } - catch (Exception e) { - e.printStackTrace(); - //WarnOnce.showWarning(null, "Model Load Error", "There was an error loading the model file.", WarnOnce.OK_OPTION); + //convert the JSON string to a parameters object. + GenericModelParams modelParams = makeModelParams( jsonString); + + //important to add this for Ketos models because the JSON string does not necessarily contain and output shape. + //System.out.println("----Default output shape: " + ketosParams.defaultOutputShape + " " + ketosModel.getOutShape()); + if (modelParams.defaultOutputShape==null) { + modelParams.defaultOutputShape = dlModel.getOutShape(); } - try { - - //read the JSON string from the the file. - String jsonString = DLTransformsParser.readJSONString(new File(dlModel.getAudioReprFile())); - - //convert the JSON string to a parameters object. - GenericModelParams modelParams = makeModelParams( jsonString); - - //important to add this for Ketos models because the JSON string does not necessarily contain and output shape. - //System.out.println("----Default output shape: " + ketosParams.defaultOutputShape + " " + ketosModel.getOutShape()); - if (modelParams.defaultOutputShape==null) { - modelParams.defaultOutputShape = dlModel.getOutShape(); - } - - //HACK there seems to be some sort of bug in ketos where the params input shape is correct but the model input shape is wrong. - if (dlModel.getInputShape()==null || !dlModel.getInputShape().equals(modelParams.defaultInputShape)) { - WarnOnce.showWarning("Model shape", "The model shape does not match the model metadata. \n Metadata shape will be used used.", WarnOnce.OK_OPTION); - dlModel.setInputShape(modelParams.defaultInputShape); - } - - -// ///HACK here for now to fix an issue with dB and Ketos transforms having zero length somehow... -// for (int i=0; i transforms = DLTransformsFactory.makeDLTransforms(modelParams.dlTransforms); - - ///HACK here for now to fix an issue with dB and Ketos transforms having zero length somehow... - for (int i=0; i transforms = DLTransformsFactory.makeDLTransforms(modelParams.dlTransforms); + +// ///HACK here for now to fix an issue with dB and Ketos transforms having zero length somehow... +// for (int i=0; i + * Ketos uses TensorFlow models and packages them inside a zipped .ktpb file + * which contains a JSON file for the transforms and a .pb model. Users can + * select a .ktpb file - PAMGaurd will decompress it, find the JSON file, set up + * the transforms and load the model. + *

+ * Details on Meridians framework can be found at https://meridian.cs.dal.ca/2015/04/12/ketos/ + *

+ * KetosClassifier2 is a more abstracted version of KetosClassifer which inherits most functionality from ArchiveModel + * @author Jamie Macaulay + * + */ +public class KetosClassifier2 extends ArchiveModelClassifier { + + public static String MODEL_NAME = "Ketos"; + + /** + * The file extensions + */ + private String[] fileExtensions = new String[] {"*.ktpb"}; + + + private KetosWorker2 ketosWorker; + + public KetosClassifier2(DLControl dlControl) { + super(dlControl); + } + + @Override + public String[] getFileExtensions() { + return fileExtensions; + } + + @Override + public String getName() { + return MODEL_NAME; + } + + @Override + public ArchiveModelWorker getModelWorker() { + if (ketosWorker==null) { + ketosWorker= new KetosWorker2(); + } + return ketosWorker; + } + + /** + * Create the parameters class for the model. This can be overridden for bespoke parameters. + *classes. + * @return a new parameters class object. + */ + public StandardModelParams makeParams() { + return new KetosDLParams(); + } + + +} diff --git a/src/rawDeepLearningClassifier/dlClassification/ketos/KetosModelPane.java b/src/rawDeepLearningClassifier/dlClassification/ketos/KetosModelPane.java index 829bb183..bd0b8f2b 100644 --- a/src/rawDeepLearningClassifier/dlClassification/ketos/KetosModelPane.java +++ b/src/rawDeepLearningClassifier/dlClassification/ketos/KetosModelPane.java @@ -38,7 +38,7 @@ public class KetosModelPane extends StandardModelPane { this.setParamsClone(new KetosDLParams()); } - + //set the current paramters for the clone StandardModelParams params = getParams(getParamsClone()); @@ -59,17 +59,17 @@ public class KetosModelPane extends StandardModelPane { //get the model transforms calculated from the model by SoundSpoyWorker and apply them to our temporary params clone. // System.out.println("Ketos transforms 1: " + this.ketosClassifier.getKetosWorker().getModelTransforms()); getParamsClone().dlTransfroms = this.ketosClassifier.getKetosWorker().getModelTransforms(); - + // if (getParamsClone().defaultSegmentLen!=null) { // usedefaultSeg.setSelected(true); // } + +// System.out.println("---------------------------- "); +// System.out.println("KETOS: new model selected " +getParamsClone().dlTransfromParams.size() + " \n " + getParamsClone()); -// System.out.println("Ketos: new model selected " + getParamsClone().dlTransfroms.size()); ///set the advanced pane parameters. getAdvSettingsPane().setParams(getParamsClone()); - - } } diff --git a/src/rawDeepLearningClassifier/dlClassification/ketos/KetosWorker.java b/src/rawDeepLearningClassifier/dlClassification/ketos/KetosWorker.java index f283fde9..3a937c1b 100644 --- a/src/rawDeepLearningClassifier/dlClassification/ketos/KetosWorker.java +++ b/src/rawDeepLearningClassifier/dlClassification/ketos/KetosWorker.java @@ -123,7 +123,7 @@ public class KetosWorker extends DLModelWorker { //only load new transforms if defaults are selected if (getModelTransforms()==null || ketosDLParams.dlTransfroms==null || ketosDLParams.useDefaultTransfroms) { - System.out.println(" " + transforms); + //System.out.println(" " + transforms); //System.out.println("SET MODEL TRANSFORMS: " + ketosDLParams.dlTransfroms + " " + ketosDLParams.useDefaultTransfroms); //only set the transforms if they are null - otherwise handled elsewhere. @@ -152,7 +152,13 @@ public class KetosWorker extends DLModelWorker { if (ketosParams.classNames!=null) { ketosDLParams.classNames = dlControl.getClassNameManager().makeClassNames(ketosParams.classNames); + ketosDLParams.numClasses = ketosDLParams.classNames.length; } + else { + //set the number of class names from the default output shape + ketosDLParams.numClasses = (int) ketosParams.defaultOutputShape.get(1); + } + // if (dlParams.classNames!=null) { // for (int i = 0; i extensionFilters = new ArrayList(); for (DLClassiferModel dlModel: dlControl.getDLModels()) { + //System.out.println("Model: " + dlModel.getModelUI()); + if (dlModel.getModelUI()!=null) { for (ExtensionFilter extFilter: dlModel.getModelUI().getModelFileExtensions()){ + //System.out.println("Extensions: " + extFilter.getExtensions()); extensionFilters.addAll(extFilter.getExtensions()); } } diff --git a/src/rawDeepLearningClassifier/layoutFX/DLSettingsPane.java b/src/rawDeepLearningClassifier/layoutFX/DLSettingsPane.java index fc87d89c..ba4cfa80 100644 --- a/src/rawDeepLearningClassifier/layoutFX/DLSettingsPane.java +++ b/src/rawDeepLearningClassifier/layoutFX/DLSettingsPane.java @@ -367,9 +367,6 @@ public class DLSettingsPane extends SettingsPane{ */ protected void setClassifierPane() { //set the classifier Pane.class - - System.out.println("Set CLASSIFIER PANE: " + modelSelectPane.currentClassifierModel); - if (modelSelectPane.currentClassifierModel!=null && modelSelectPane.currentClassifierModel.getModelUI()!=null) { classifierPane.setCenter(modelSelectPane.currentClassifierModel.getModelUI().getSettingsPane().getContentNode()); diff --git a/src/rawDeepLearningClassifier/layoutFX/dlTransfroms/DLTransformsPane.java b/src/rawDeepLearningClassifier/layoutFX/dlTransfroms/DLTransformsPane.java index 5ca5e1b4..9ea8a36f 100644 --- a/src/rawDeepLearningClassifier/layoutFX/dlTransfroms/DLTransformsPane.java +++ b/src/rawDeepLearningClassifier/layoutFX/dlTransfroms/DLTransformsPane.java @@ -166,7 +166,7 @@ public class DLTransformsPane extends PamBorderPane { transformPane = DataTransformPaneFactory.getSettingsPane(dlTransforms.get(i)); - System.out.println("Set DL transfroms: " + dlTransforms.get(i).getDLTransformType() + " " + ((SimpleTransform) dlTransforms.get(i)).getParams()); + //System.out.println("Set DL transfroms: " + dlTransforms.get(i).getDLTransformType() + " " + ((SimpleTransform) dlTransforms.get(i)).getParams()); //there must be a transform pane or else this will break.