This commit is contained in:
Douglas Gillespie 2025-03-12 12:59:40 +00:00
commit ccc59c7b79
38 changed files with 930 additions and 139 deletions

View File

@ -383,7 +383,7 @@ PAMGuardBeta_ViewerMode.exe):</p>
<p class=MsoNormal><em><span style='font-family:"Calibri",sans-serif'>&nbsp;</span></em></p>
<h2><em><span style='font-size:12.0pt;font-family:"Cambria",serif;font-style:
normal'><a href="#_Version_2.02.16_February">Latest Version 2.02.16 February
normal'><a href="#_Version_2.02.16_February">Latest Version 2.02.16 March
2025&nbsp;</a></span></em></h2>
<h2><em><span style='font-size:12.0pt;font-family:"Cambria",serif;font-style:
@ -434,7 +434,7 @@ name="_Latest_Version_2.02.07"></a><a name="_Latest_Version_2.02.08"></a><a
name="_Version_2.02.09_June"></a><a name="_Version_2.02.10_January"></a><a
name="_Version_2.02.11_April"></a><a name="_Version_2.02.14_October"></a><a
name="_2.02.15_December_2014"></a><a name="_Version_2.02.16_February"></a>Version
2.02.16 February 2025</h1>
2.02.16 March 2025</h1>
<h2>New Features</h2>
@ -444,6 +444,11 @@ name="_2.02.15_December_2014"></a><a name="_Version_2.02.16_February"></a>Versio
2 and Nilus 3.2. PAMGuard is no longer compatible with 3.1, the pre-release
version. </p>
<p class=MsoNormal>Added Tethys functionality for the following modules:
Whistle Classifier, Detection Group Localiser, Rocca, Click Train Detector, GPL
Detector. IF the Detection Group Localiser is used with Logger Form
annotations, species codes can be taken from the logger form. </p>
<p class=MsoNormal>Made export of data (Calibrations, Deployments, Detections,
and Localisations) available as offline tasks. This is not useful when
running Tethys on a single dataset, since all tasks can be easily performed
@ -462,6 +467,14 @@ data to Tethys. </p>
<p class=MsoNormal>Multiple management changes to support batch processing of
offline tasks. Compatible with batch processor 2.0. </p>
<p class=MsoNormal>Added clip display for Deep Learning module.</p>
<p class=MsoNormal>Added optional display of impulse response function to IIR
Filter design dialog in place of the pole-zero diagram. </p>
<p class=MsoNormal>Added ROCCA graphics, so ROCCA output can be displayed on
the spectrogram display. </p>
<h2>Bug Fixes</h2>
<p class=MsoNormal>Issue 190. Array Files exported from array manager were not
@ -481,7 +494,7 @@ time, meaning you got an invalid file path. This has been fixed. </p>
channel list from acquisition module and automatically removes channels that
were selected in the FFT module, but are not available from the acquisition. </p>
<p class=MsoNormal>Dealt with issue in Tethys module looking up IT IS species
<p class=MsoNormal>Dealt with issue in Tethys module looking up ITIS species
codes where the progress dialog would not close. </p>
<p class=MsoNormal>Project Information abstract field was not saving /
@ -793,8 +806,8 @@ processing.</span></p>
<h2><span lang=EN-US>New Features</span></h2>
<p class=MsoNormal><span lang=EN-US>New sound type for simulated sounds which
generates random chirps between around 200 and 800Hz, roughly the frequency you'd
expect sound from higher frequency baleen whales, such as humpbacks, to
generates random chirps between around 200 and 800Hz, roughly the frequency
you'd expect sound from higher frequency baleen whales, such as humpbacks, to
vocalise at. &nbsp;&nbsp;</span></p>
<p class=MsoNormal><span lang=EN-US>Hiding tool tips. A menu item to
@ -857,8 +870,8 @@ classifier was being trimmed. </span></p>
<p class=MsoNormal><b><span lang=EN-US>Documentation</span></b></p>
<p class=MsoNormal><span lang=EN-US>Comprehensive help file including description
of the algorithm, screen grabs and examples.</span></p>
<p class=MsoNormal><span lang=EN-US>Comprehensive help file including
description of the algorithm, screen grabs and examples.</span></p>
<p class=MsoNormal><span lang=EN-US>Bug fixes</span></p>
@ -992,8 +1005,8 @@ href="http://www.PAMGuard.org/downloads.php?cat_id=3">here</a>.</p>
<p class=MsoNormal><b><span lang=EN-US>Detection Group Localiser</span></b><span
lang=EN-US> </span></p>
<p class=MsoNormal>This module has been renamed &quot;Detection Grouper&quot;, so
as to avoid confusion with the Group 3D localizer. This is because the
<p class=MsoNormal>This module has been renamed &quot;Detection Grouper&quot;,
so as to avoid confusion with the Group 3D localizer. This is because the
Detection Grouper is more for organizing data into groups to be localized than
it is for doing localization.</p>
@ -1137,10 +1150,11 @@ name="_Latest_Beta_Version_2.01.05"></a><span lang=EN-US>&nbsp;</span></p>
<h1><span lang=EN-US>Version 2.01.05 October 2020</span></h1>
<p class=MsoNormal><b>If you are upgrading from a PAMGuard core release (1.15.xx),
PAMGuard Version 2 contains major updates. You should read and understand the
notes listed for <a href="#_Latest_Beta_Version_2.00.10">Beta Version 2.00.10</a>
before proceeding with installation and use of this version.</b></p>
<p class=MsoNormal><b>If you are upgrading from a PAMGuard core release
(1.15.xx), PAMGuard Version 2 contains major updates. You should read and
understand the notes listed for <a href="#_Latest_Beta_Version_2.00.10">Beta
Version 2.00.10</a> before proceeding with installation and use of this
version.</b></p>
<p class=MsoNormal>This version of PAMGuard has been bundled with Java 13
(release 13.0.1). PSFX files generated in previous beta releases (2.xx.xx)
@ -1706,8 +1720,8 @@ lang=EN-US style='font-size:7.0pt;font-family:"Times New Roman",serif'>&nbsp;&nb
<p class=MsoListParagraph style='text-indent:-18.0pt'><span lang=EN-US>7. </span><span
lang=EN-US style='font-size:7.0pt;font-family:"Times New Roman",serif'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span>Bug 420. The Click Classifier set was not getting updated properly in Viewer
mode.</p>
</span>Bug 420. The Click Classifier set was not getting updated properly in
Viewer mode.</p>
<p class=MsoListParagraph style='text-indent:-18.0pt'><span lang=EN-US>8. </span><span
lang=EN-US style='font-size:7.0pt;font-family:"Times New Roman",serif'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@ -2018,9 +2032,9 @@ see new options in main menu.</p>
<p class=MsoListParagraph style='text-indent:-18.0pt'><span lang=EN-US>2. </span><span
lang=EN-US style='font-size:7.0pt;font-family:"Times New Roman",serif'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span
lang=EN-US> </span>Added Matched Template Click Classifier. Classifies clicks based
on an ideal template to match and a template to reject. An example of this is
to classify beaked whale clicks in an environment with dolphin clicks.</p>
lang=EN-US> </span>Added Matched Template Click Classifier. Classifies clicks
based on an ideal template to match and a template to reject. An example of
this is to classify beaked whale clicks in an environment with dolphin clicks.</p>
<p class=MsoListParagraph style='text-indent:-18.0pt'><span lang=EN-US>3. </span><span
lang=EN-US style='font-size:7.0pt;font-family:"Times New Roman",serif'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
@ -2614,9 +2628,9 @@ dependencies)</span></p>
<p class=MsoNormal><b><span lang=EN-US>Other Changes</span></b></p>
<p class=MsoNormal><span lang=EN-US>The installer has been updated to handle both
64 bit and 32 bit installations. PAMGuard psf files are now registered in the
Windows Registry, so double-clicking on a psf file should run PAMGuard in
<p class=MsoNormal><span lang=EN-US>The installer has been updated to handle
both 64 bit and 32 bit installations. PAMGuard psf files are now registered in
the Windows Registry, so double-clicking on a psf file should run PAMGuard in
normal mode (as opposed to Viewer or Mixed modes). Note that the Windows
Registry can only hold a single executable reference for psf files; therefore,
for users with multiple installations of PAMGuard, double-clicking on a psf
@ -2768,10 +2782,10 @@ the online help. Users of the Click Detector will notice the following changes:<
<p class=MsoListParagraph style='text-indent:-18.0pt'><span lang=EN-US>1.</span><span
lang=EN-US style='font-size:7.0pt;font-family:"Times New Roman",serif'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span><span lang=EN-US>There is now a choice of least squares and Simplex based
algorithms for real-time animal tracking. The improved algorithms also provide
better error information both for display on the map and for storage in the
database. </span></p>
</span><span lang=EN-US>There is now a choice of least squares and Simplex
based algorithms for real-time animal tracking. The improved algorithms also
provide better error information both for display on the map and for storage in
the database. </span></p>
<p class=MsoListParagraph style='text-indent:-18.0pt'><span lang=EN-US>2.</span><span
lang=EN-US style='font-size:7.0pt;font-family:"Times New Roman",serif'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@ -2812,8 +2826,8 @@ the future. </span></p>
<p class=MsoNormal><i>Logger Form Design</i></p>
<p class=MsoNormal>A GUI driven system for designing Logger forms has been
released. Currently, this feature has no online help, but is reasonably intuitive
<p class=MsoNormal>A GUI driven system for designing Logger forms has been released.
Currently, this feature has no online help, but is reasonably intuitive
compared to the old method of typing directly into the database. </p>
<p class=MsoNormal><i><span lang=EN-US>Improved Number handling</span></i></p>
@ -3534,8 +3548,8 @@ module. </p>
<p class=MsoNormal><i>Sound Recorder Module</i></p>
<p class=MsoNormal>Now supports writing 8 and 24 bit as well as 16 bit files.
Also writes data to dated sub folders, starting a new folder each day (UTC). Also
provides additional information on disk space on the main display panel.
Also writes data to dated sub folders, starting a new folder each day (UTC).
Also provides additional information on disk space on the main display panel.
Millisecond time is also now included in the output file names. </p>
<p class=MsoNormal><i>Datagram Options</i></p>
@ -3597,8 +3611,8 @@ whistle.</p>
<li class=MsoNormal style='margin-bottom:0cm'>Airgun display. If this was
included in the PAMGuard model before the GPS module it would hang
PAMGuard. This has been rectified. </li>
<li class=MsoNormal style='margin-bottom:0cm'>Fixed occasional exceptions in the
sound output modules when playing back from files. </li>
<li class=MsoNormal style='margin-bottom:0cm'>Fixed occasional exceptions in
the sound output modules when playing back from files. </li>
<li class=MsoNormal style='margin-bottom:0cm'>Fixed exceptions in spectrogram
user interface. </li>
<li class=MsoNormal style='margin-bottom:0cm'>Fixed National Instruments sound
@ -3680,8 +3694,8 @@ other data sources for the PAMGuard viewer. </p>
storage to the database offline for any module having both binary and database
storage. </p>
<p class=MsoNormal style='margin-left:36.0pt'>Can create a blank MS Access database
(2007 and later *.accdb formats only).</p>
<p class=MsoNormal style='margin-left:36.0pt'>Can create a blank MS Access
database (2007 and later *.accdb formats only).</p>
<p class=MsoNormal style='margin-left:36.0pt'>Can open MS Access from within
PAMGuard to make it easier to view database content. </p>
@ -3764,8 +3778,8 @@ margin-left:36.0pt'>&nbsp;</p>
<p class=MsoListParagraph style='margin-left:54.0pt;text-indent:-18.0pt'><i>Ishmael
Detection Modules</i></p>
<p class=MsoListParagraph style='margin-left:54.0pt;text-indent:-18.0pt'>We
have implemented database storage for output of these modules. </p>
<p class=MsoListParagraph style='margin-left:54.0pt;text-indent:-18.0pt'>We have
implemented database storage for output of these modules. </p>
<p class=MsoNormal><b>Bug fixes</b></p>
@ -3947,9 +3961,9 @@ length. </p>
<p class=MsoListParagraph style='text-indent:-18.0pt'><span style='font-family:
Symbol'>'</span><span style='font-size:7.0pt;font-family:"Times New Roman",serif'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span>The filter module can now also generate finite Impulse Response (FIR)
filters. Note however, that FIR filters may require considerably more execution
time than IIR filters. </p>
</span>The filter module can now also generate finite Impulse Response (FIR) filters.
Note however, that FIR filters may require considerably more execution time
than IIR filters. </p>
<p class=MsoListParagraph style='text-indent:-18.0pt'><span style='font-family:
Symbol'>'</span><span style='font-size:7.0pt;font-family:"Times New Roman",serif'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@ -4000,10 +4014,10 @@ source, even if that data source is loaded after the FFT module is created.</p>
<p class=MsoNormal>1. Binary storage module. </p>
<p class=MsoNormal>Performs a parallel role to the PAMGAURD database but uses binary
files in a proprietary format which is considerably more efficient for data of
unknown length such as whistle contours or small clips of click waveform. This
feature is currently implemented in the following modules:</p>
<p class=MsoNormal>Performs a parallel role to the PAMGAURD database but uses
binary files in a proprietary format which is considerably more efficient for
data of unknown length such as whistle contours or small clips of click
waveform. This feature is currently implemented in the following modules:</p>
<p class=MsoListParagraph style='text-indent:-18.0pt'><span style='font-family:
Symbol'>'</span><span style='font-size:7.0pt;font-family:"Times New Roman",serif'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@ -4087,9 +4101,9 @@ and recording sounds to the default directory.&nbsp; </p>
<p class=MsoNormal><b>Channel numbering</b></p>
<p class=MsoNormal>A new internal channel numbering scheme for ASIO sound cards
was released on 8 March in Alpha version 1.8.02. These changes have now been promoted
to this Beta release 1.9.00. These changes were described in an email to
PAMGuard User, the text of which is repeated here:</p>
was released on 8 March in Alpha version 1.8.02. These changes have now been
promoted to this Beta release 1.9.00. These changes were described in an email
to PAMGuard User, the text of which is repeated here:</p>
<p class=MsoNormal>Within PAMGuard, there have been constant problems with
lookup tables relating hardware channel numbers to internal channel numbers.
@ -4212,8 +4226,8 @@ column was setting to zero. This is now fixed</p>
<p class=MsoNormal>Ishmael Detectors</p>
<p class=MsoNormal>Better rendering of detection boxes on spectrogram display
and more meaningful names in spectrogram display menu.</p>
<p class=MsoNormal>Better rendering of detection boxes on spectrogram display and
more meaningful names in spectrogram display menu.</p>
<p class=MsoNormal>Sound acquisition</p>
@ -4286,9 +4300,9 @@ Symbol'>'</span><span style='font-size:7.0pt;font-family:"Times New Roman",serif
<p class=MsoListParagraph style='text-indent:-18.0pt'><span style='font-family:
Symbol'>'</span><span style='font-size:7.0pt;font-family:"Times New Roman",serif'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span>False buffer overflows at low sample rates stopped (size of data in
individual data blocks had been increased at low sample rates, but when this
exceeded 3s a false buffer overflow would occur).</p>
</span>False buffer overflows at low sample rates stopped (size of data in individual
data blocks had been increased at low sample rates, but when this exceeded 3s a
false buffer overflow would occur).</p>
<p class=MsoNormal>&nbsp;</p>
@ -4325,8 +4339,8 @@ will be displayed if you select them with the mouse.</p>
<p class=MsoListParagraph style='text-indent:-18.0pt'><span style='font-family:
Symbol'>'</span><span style='font-size:7.0pt;font-family:"Times New Roman",serif'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span>New click classifier methods, which include extraction of frequency sweep
parameters. (Please note that this click is not yet documented. The old
</span>New click classifier methods, which include extraction of frequency
sweep parameters. (Please note that this click is not yet documented. The old
classifier is still available). </p>
<p class=MsoListParagraph style='text-indent:-18.0pt'><span style='font-family:
@ -4462,8 +4476,8 @@ them before proceeding with installation.</p>
<p class=MsoListParagraph style='text-indent:-18.0pt'><span style='font-family:
Symbol'>'</span><span style='font-size:7.0pt;font-family:"Times New Roman",serif'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span>Installer now setting permissions on some of the default settings files
so that under Vista they can still be written to without needed to be an
</span>Installer now setting permissions on some of the default settings files so
that under Vista they can still be written to without needed to be an
Administrator</p>
<p class=MsoListParagraph style='text-indent:-18.0pt'><span style='font-family:
@ -4536,10 +4550,10 @@ help pages</p>
<p class=MsoNormal><b>Bug Fixes</b></p>
<p class=MsoNormal>Memory leak caused by Night / Day colour manager now fixed. This
would cause memory leaks when multiple files were being analysed off-line and
would eventually crash PAMGuard. The way that colours are managed in PAMGuard
has been rewritten.&nbsp; </p>
<p class=MsoNormal>Memory leak caused by Night / Day colour manager now fixed.
This would cause memory leaks when multiple files were being analysed off-line
and would eventually crash PAMGuard. The way that colours are managed in
PAMGuard has been rewritten.&nbsp; </p>
<p class=MsoNormal>Some issues with Swing fixed that might have been causing
hang ups on startup especially on Macs/Linux machines</p>
@ -4610,8 +4624,8 @@ file)</p>
<p class=MsoNormal><b>Changes</b></p>
<p class=MsoNormal>The User Input module (for text entry of information by the user)
has been moved from the Displays sub menu of the Add Modules menu, to
<p class=MsoNormal>The User Input module (for text entry of information by the
user) has been moved from the Displays sub menu of the Add Modules menu, to
Utilities. This will not affect how existing settings files are loaded. </p>
<p class=MsoNormal><b>Multi-screen environments.</b></p>

View File

@ -704,9 +704,13 @@ public class PamDetectionOverlayGraphics extends PanelOverlayDraw {
double[] frequency = pamDetection.getFrequency();
Coordinate3d topLeft = generalProjector.getCoord3d(pamDetection.getTimeMilliseconds(),
frequency[1], 0);
double dur = 0;
Double duration = pamDetection.getDurationInMilliseconds();
if (duration != null) {
dur = duration;
}
Coordinate3d botRight = generalProjector.getCoord3d(pamDetection.getTimeMilliseconds() +
pamDetection.getDurationInMilliseconds(),
frequency[0], 0);
dur, frequency[0], 0);
if (botRight.x < topLeft.x){
botRight.x = g.getClipBounds().width;

View File

@ -303,6 +303,10 @@ abstract public class PamProcess implements PamObserver, ProcessAnnotator {
* one. Otherwise Pamguard tends to get stuck in a loop of model change
* notifications and setting of data blocks.
*/
boolean instant = (this instanceof PamInstantProcess);
if (instant) {
reThread = false;
}
if (parentDataBlock == newParentDataBlock) {
return;
}
@ -312,7 +316,12 @@ abstract public class PamProcess implements PamObserver, ProcessAnnotator {
}
parentDataBlock = newParentDataBlock;
if (parentDataBlock != null) {
parentDataBlock.addObserver(this, PamModel.getPamModel().isMultiThread() & reThread);
if (instant) {
parentDataBlock.addInstantObserver(this);
}
else {
parentDataBlock.addObserver(this, PamModel.getPamModel().isMultiThread() & reThread);
}
// acousticDataSource = AcousticDataUnit.class.isAssignableFrom(parentDataBlock.getUnitClass());
// parentProcess = parentDataBlock.getParentProcess();
PamProcess pp = parentDataBlock.getParentProcess();

View File

@ -2973,7 +2973,7 @@ InternalFrameListener, DisplayPanelContainer, SpectrogramParametersUser, PamSett
}
int wantedMap = 1<<spectrogramParameters.channelList[panelId];
int dataChanMap = dataUnit.getSequenceBitmap();
if ((wantedMap & dataChanMap) == 0) {
if (dataChanMap != 0 && (wantedMap & dataChanMap) == 0) {
continue;
}
if (dataSelector != null && dataSelector.scoreData(dataUnit) <= 0) {

View File

@ -31,7 +31,7 @@ public class CentralAnnotationsList {
singleInstance.addAnnotationType(new SNRAnnotationType());
singleInstance.addAnnotationType(new SPLAnnotationType());
singleInstance.addAnnotationType(new TMAnnotationType());
singleInstance.addAnnotationType(new UserFormAnnotationType());
singleInstance.addAnnotationType(new UserFormAnnotationType(null));
singleInstance.addAnnotationType(new WavAnnotationType());
}
}

View File

@ -1,7 +1,5 @@
package annotation;
import org.w3c.dom.Element;
import PamView.symbol.PamSymbolChooser;
import PamView.symbol.modifier.SymbolModifier;
import PamguardMVC.PamDataBlock;
@ -13,6 +11,7 @@ import annotation.handler.AnnotationOptions;
import annotation.xml.AnnotationXMLWriter;
import annotation.xml.SQLXMLWriter;
import generalDatabase.SQLLoggingAddon;
import tethys.species.DataBlockSpeciesManager;
/**
* Something that can tell us a little more about
@ -230,5 +229,13 @@ public abstract class DataAnnotationType<TDataAnnotation extends DataAnnotation<
this.targetDataBlock = targetDataBlock;
}
/**
* Annotations may have a species manager. Most won't.
* @return
*/
public DataBlockSpeciesManager getDataBlockSpeciesManager() {
return null;
}
}

View File

@ -17,7 +17,7 @@ public class ManualAnnotationHandler extends OneStopAnnotationHandler {
@Override
public void createAnnotationTypes() {
addAnnotationType(new StringAnnotationType("Text Annotation", 80));
addAnnotationType(new UserFormAnnotationType());
addAnnotationType(new UserFormAnnotationType(getPamDataBlock()));
// now try to add their parameters.
AnnotationChoices annotationChoices = getAnnotationChoices();
if (annotationChoices == null) {

View File

@ -4,6 +4,7 @@ import PamController.PamController;
import PamView.symbol.AnnotationSymbolChooser;
import PamView.symbol.PamSymbolChooser;
import PamView.symbol.modifier.SymbolModifier;
import PamguardMVC.PamDataBlock;
import annotation.AnnotationDialogPanel;
import annotation.AnnotationSettingsPanel;
import annotation.DataAnnotationType;
@ -11,6 +12,7 @@ import annotation.binary.AnnotationBinaryHandler;
import annotation.dataselect.AnnotationDataSelCreator;
import annotation.handler.AnnotationOptions;
import annotation.userforms.datasel.UserFormDataSelCreator;
import annotation.userforms.species.FormsAnnotationSpeciesManager;
import annotation.xml.AnnotationXMLWriter;
import annotation.xml.SQLXMLWriter;
import generalDatabase.DBControlUnit;
@ -18,6 +20,7 @@ import generalDatabase.SQLLoggingAddon;
import loggerForms.FormDescription;
import loggerForms.FormsControl;
import loggerForms.LoggerForm;
import tethys.species.DataBlockSpeciesManager;
public class UserFormAnnotationType extends DataAnnotationType<UserFormAnnotation<?>> {
@ -39,11 +42,18 @@ public class UserFormAnnotationType extends DataAnnotationType<UserFormAnnotatio
private UserFormBinaryHandler userFormBinaryHandler;
private UserFormDataSelCreator userFormDataSelCreator;
private FormsAnnotationSpeciesManager formsAnnotationSpeciesManager;
/**
*
*/
public UserFormAnnotationType() {
this(null);
}
public UserFormAnnotationType(PamDataBlock pamDataBlock) {
super();
setTargetDataBlock(pamDataBlock);
userFormAnnotationOptions = new UserFormAnnotationOptions(getAnnotationName());
userFormSQLAddon = new UserFormSQLAddon(this);
@ -231,4 +241,12 @@ public class UserFormAnnotationType extends DataAnnotationType<UserFormAnnotatio
// TODO Auto-generated method stub
return new SQLXMLWriter<>(this);
}
@Override
public DataBlockSpeciesManager getDataBlockSpeciesManager() {
if (formsAnnotationSpeciesManager == null) {
formsAnnotationSpeciesManager = new FormsAnnotationSpeciesManager(this, getTargetDataBlock());
}
return formsAnnotationSpeciesManager;
}
}

View File

@ -0,0 +1,145 @@
package annotation.userforms.species;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Vector;
import PamController.PamControlledUnitSettings;
import PamController.PamSettingManager;
import PamController.PamSettings;
import PamView.dialog.PamDialogPanel;
import PamguardMVC.PamDataBlock;
import PamguardMVC.PamDataUnit;
import annotation.userforms.UserFormAnnotation;
import annotation.userforms.UserFormAnnotationType;
import generalDatabase.lookupTables.LookupItem;
import generalDatabase.lookupTables.LookupList;
import loggerForms.controlDescriptions.CdLookup;
import loggerForms.controlDescriptions.ControlTypes;
import loggerForms.controlDescriptions.InputControlDescription;
import tethys.species.DataBlockSpeciesCodes;
import tethys.species.DataBlockSpeciesManager;
import tethys.species.SpeciesManagerObserver;
public class FormsAnnotationSpeciesManager extends DataBlockSpeciesManager implements PamSettings {
private UserFormAnnotationType userFormAnnotationType;
private FormsSpeciesSettings speciesSettings = new FormsSpeciesSettings();
private FormsAnnotationSpeciesCodes speciesCodes;
public FormsAnnotationSpeciesManager(UserFormAnnotationType userFormAnnotationType, PamDataBlock dataBlock) {
super(dataBlock);
this.userFormAnnotationType = userFormAnnotationType;
this.speciesCodes = new FormsAnnotationSpeciesCodes();
PamSettingManager.getInstance().registerSettings(this);
}
@Override
public DataBlockSpeciesCodes getSpeciesCodes() {
return speciesCodes;
}
@Override
public String getSpeciesCode(PamDataUnit dataUnit) {
UserFormAnnotation annot = (UserFormAnnotation) dataUnit.findDataAnnotation(userFormAnnotationType.getAnnotationClass());
if (annot == null) {
return null;
}
// now find the control with the right name.
Object data[] = annot.getLoggerFormData();
int ind = getLoggerItemIndex();
if (ind < 0 || ind > data.length) {
return null;
}
Object dat = data[ind];
if (dat == null) {
return null;
}
return dat.toString();
}
private int getLoggerItemIndex() {
int ctrlInd = userFormAnnotationType.getFormDescription().findInputControlByName(speciesSettings.selectedControl);
return ctrlInd;
}
public class FormsAnnotationSpeciesCodes extends DataBlockSpeciesCodes {
public FormsAnnotationSpeciesCodes() {
super(null);
// TODO Auto-generated constructor stub
}
@Override
public ArrayList<String> getSpeciesNames() {
int ctrlInd = userFormAnnotationType.getFormDescription().findInputControlByName(speciesSettings.selectedControl);
ArrayList<InputControlDescription> ipControls = userFormAnnotationType.getFormDescription().getInputControlDescriptions();
if (ctrlInd < 0 || ctrlInd >= ipControls.size()) {
return null;
}
InputControlDescription ipCD = ipControls.get(ctrlInd);
if (ipCD.getEType() != ControlTypes.LOOKUP) {
return null;
}
CdLookup lutCtrl = (CdLookup) ipCD;
LookupList lutList = lutCtrl.getLookupList();
Vector<LookupItem> lutItems = lutList.getList();
ArrayList<String> names = new ArrayList<>();
for (int i = 0; i < lutItems.size(); i++) {
names.add(lutItems.get(i).getCode());
}
return names;
}
}
@Override
public PamDialogPanel getDialogPanel(SpeciesManagerObserver speciesManagerObserver) {
return new FormsSpeciesOptionsPanel(this, speciesManagerObserver);
}
@Override
public String getUnitName() {
return userFormAnnotationType.getTargetDataBlock().getLongDataName();
}
@Override
public String getUnitType() {
return "Forms Annotion Species Settings";
}
@Override
public Serializable getSettingsReference() {
return speciesSettings;
}
@Override
public long getSettingsVersion() {
return FormsSpeciesSettings.serialVersionUID;
}
@Override
public boolean restoreSettings(PamControlledUnitSettings pamControlledUnitSettings) {
speciesSettings = (FormsSpeciesSettings) pamControlledUnitSettings.getSettings();
return true;
}
/**
* @return the userFormAnnotationType
*/
public UserFormAnnotationType getUserFormAnnotationType() {
return userFormAnnotationType;
}
/**
* @return the speciesSettings
*/
public FormsSpeciesSettings getSpeciesSettings() {
return speciesSettings;
}
}

View File

@ -0,0 +1,95 @@
package annotation.userforms.species;
import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import PamView.dialog.PamDialogPanel;
import PamView.dialog.PamGridBagContraints;
import annotation.userforms.UserFormAnnotationType;
import loggerForms.controlDescriptions.ControlTypes;
import loggerForms.controlDescriptions.InputControlDescription;
import tethys.species.SpeciesManagerObserver;
public class FormsSpeciesOptionsPanel implements PamDialogPanel {
private UserFormAnnotationType userFormAnnotationType;
private FormsAnnotationSpeciesManager formsAnnotationSpeciesManager;
private JPanel mainPanel;
private JComboBox<String> lookups;
private SpeciesManagerObserver speciesManagerObserver;
private static final String tip = "User Forms annotation species selection options. Select any LOOKUP type control as species";
public FormsSpeciesOptionsPanel(FormsAnnotationSpeciesManager formsAnnotationSpeciesManager, SpeciesManagerObserver speciesManagerObserver) {
this.formsAnnotationSpeciesManager = formsAnnotationSpeciesManager;
this.userFormAnnotationType = formsAnnotationSpeciesManager.getUserFormAnnotationType();
this.speciesManagerObserver = speciesManagerObserver;
mainPanel = new JPanel(new GridBagLayout());
GridBagConstraints c = new PamGridBagContraints();
JLabel label;
mainPanel.add(label = new JLabel("User form control for species ", JLabel.RIGHT), c);
lookups = new JComboBox<>();
lookups.setToolTipText("Select a drop down list that you use for species identity");
c.gridx++;
mainPanel.add(lookups, c);
// fill with names of controls that are lookups.
lookups.addItem("--no selection--");
ArrayList<InputControlDescription> ipControls = userFormAnnotationType.getFormDescription().getInputControlDescriptions();
for (InputControlDescription aCtrl : ipControls) {
if (aCtrl.getEType() != ControlTypes.LOOKUP) {
continue;
}
lookups.addItem(aCtrl.getTitle());
}
label.setToolTipText(tip);
lookups.setToolTipText(tip);
setParams();
}
protected void selectionChanged() {
getParams();
if (speciesManagerObserver != null) {
speciesManagerObserver.update();
}
}
@Override
public JComponent getDialogComponent() {
return mainPanel;
}
@Override
public void setParams() {
String sel = formsAnnotationSpeciesManager.getSpeciesSettings().selectedControl;
if (sel != null) {
lookups.setSelectedItem(sel);
}
lookups.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
selectionChanged();
}
});
}
@Override
public boolean getParams() {
String item = (String) lookups.getSelectedItem();
formsAnnotationSpeciesManager.getSpeciesSettings().selectedControl = item;
return (item != null);
}
}

View File

@ -0,0 +1,25 @@
package annotation.userforms.species;
import java.io.Serializable;
public class FormsSpeciesSettings implements Cloneable, Serializable{
public static final long serialVersionUID = 1L;
/**
* Control used for species selection - will be a dropdown.
*/
public String selectedControl;
@Override
protected FormsSpeciesSettings clone() {
try {
return (FormsSpeciesSettings) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
}

View File

@ -70,7 +70,7 @@ public class SpectrogramAnnotationModule extends MarkModule implements PamSettin
annotationHandler.addAnnotationType(splAnnotationType =new SPLAnnotationType());
annotationHandler.addAnnotationType(stringAnnotationType = new StringAnnotationType("Note", 50));
annotationHandler.addAnnotationType(labelAnnotationType = new StringAnnotationType("Label", 50));
annotationHandler.addAnnotationType(new UserFormAnnotationType());
annotationHandler.addAnnotationType(new UserFormAnnotationType(getAnnotationProcess().getMarkDataBlock()));
// spectrogramMarkObserver = new SpecMarkObserver();
// SpectrogramMarkObservers.addSpectrogramMarkObserver(spectrogramMarkObserver);

View File

@ -24,6 +24,8 @@ import annotation.DataAnnotationType;
import detectiongrouplocaliser.dialogs.DetectionGroupDialog;
import detectiongrouplocaliser.dialogs.DetectionGroupTableProvider;
import detectiongrouplocaliser.dialogs.DisplayOptionsHandler;
import detectiongrouplocaliser.tethys.DetectionGroupSpeciesManager;
import tethys.species.DataBlockSpeciesManager;
import userDisplay.UserDisplayControl;
/**
@ -46,6 +48,8 @@ public class DetectionGroupControl extends PamControlledUnit implements PamSetti
private DisplayOptionsHandler displayOptionsHandler;
private DetectionGroupSpeciesManager detectionGroupSpeciesManager;
public DetectionGroupControl(String unitName) {
super(unitType, unitName);
this.detectionGroupProcess = new DetectionGroupProcess(this);
@ -186,4 +190,25 @@ public class DetectionGroupControl extends PamControlledUnit implements PamSetti
}
return null;
}
public DataBlockSpeciesManager<DetectionGroupDataUnit> getDataBlockSpeciesManager() {
DetectionGroupDataBlock dataBlock = detectionGroupProcess.getDetectionGroupDataBlock();
if (detectionGroupSpeciesManager == null) {
detectionGroupSpeciesManager = new DetectionGroupSpeciesManager(dataBlock);
}
// see if any of the annotations have a species manager and use that by preference.
GroupAnnotationHandler annHandler = detectionGroupProcess.getAnnotationHandler();
if (annHandler == null) {
return detectionGroupSpeciesManager;
}
List<DataAnnotationType<?>> usedAnnotations = annHandler.getUsedAnnotationTypes();
for (DataAnnotationType<?> aType : usedAnnotations) {
DataBlockSpeciesManager sppManager = aType.getDataBlockSpeciesManager();
if (sppManager != null) {
return sppManager;
}
}
return detectionGroupSpeciesManager;
}
}

View File

@ -17,8 +17,6 @@ public class DetectionGroupDataBlock extends SuperDetDataBlock<DetectionGroupDat
private DetectionGroupTethysProvider detectionGroupTethysProvider;
private DetectionGroupSpeciesManager detectionGroupSpeciesManager;
private DetectionGroupControl detectionGroupControl;
public DetectionGroupDataBlock(String dataName, DetectionGroupControl detectionGroupControl, DetectionGroupProcess detectionGroupProcess) {
@ -119,10 +117,7 @@ public class DetectionGroupDataBlock extends SuperDetDataBlock<DetectionGroupDat
@Override
public DataBlockSpeciesManager<DetectionGroupDataUnit> getDatablockSpeciesManager() {
if (detectionGroupSpeciesManager == null) {
detectionGroupSpeciesManager = new DetectionGroupSpeciesManager(this);
}
return detectionGroupSpeciesManager;
return detectionGroupControl.getDataBlockSpeciesManager();
}
}

View File

@ -17,7 +17,7 @@ public class GroupAnnotationHandler extends AnnotationChoiceHandler {
super(pamDataBlock);
this.detectionGroupControl = detectionGroupControl;
addAnnotationType(new StringAnnotationType("Text Annotation", 80));
addAnnotationType(new UserFormAnnotationType());
addAnnotationType(new UserFormAnnotationType(pamDataBlock));
addAnnotationType(new TMAnnotationType());
}

View File

@ -21,6 +21,12 @@ web site, it is highly likely that whistles of a given species will vary between
regions and sub species and may also evolve over time. The Whistle Classifier therefore
allows you to train it using your own samples of whistles from known species.</p>
<p>The workings of the classifier are described in the paper
Douglas Gillespie, Marjolaine Caillat, Jonathan Gordon, Paul White; Automatic detection and classification of odontocete whistles.
J. Acoust. Soc. Am. 1 September 2013; 134 (3): 24272437. <a href="https://doi.org/10.1121/1.4816555">DOI 10.1121/1.4816555</a> </p>
<p>Trained classifier models from the paper, which can be imported into your own PAMGuard configuration are
available at <a href="https://www.pamguard.org/whistleclassifier.html">www.pamguard.org/whistleclassifier.html</a>.
<h3>Creating a Whistle Classifier</h3>
<p>From the <strong><em>File>Add modules>Detectors</em></strong>

View File

@ -15,7 +15,7 @@ public class MapGroupAnnotationHandler extends AnnotationChoiceHandler {
super(pamDataBlock);
this.mapGroupLocaliserControl = mapGroupLocaliserControl;
addAnnotationType(new StringAnnotationType("Text Annotation", 80));
addAnnotationType(new UserFormAnnotationType());
addAnnotationType(new UserFormAnnotationType(mapGroupLocaliserControl.getMarkGroupProcess().getMarkGroupDataBlock()));
}
@Override

View File

@ -241,4 +241,11 @@ public class MarkGroupProcess extends PamProcess implements OverlayMarkObserver
return null;
}
/**
* @return the markGroupDataBlock
*/
public MarkGroupDataBlock getMarkGroupDataBlock() {
return markGroupDataBlock;
}
}

View File

@ -57,7 +57,7 @@ public class PrintScreenControl extends PamControlledUnit implements PamSettings
annotationHandler = new PrintScreenAnnotationChoiceHandler(this, printScreenDataBlock);
printScreenDataBlock.setAnnotationHandler(annotationHandler);
printScreenDataBlock.addDataAnnotationType(new StringAnnotationType("Comment", 50));
printScreenDataBlock.addDataAnnotationType(new UserFormAnnotationType());
printScreenDataBlock.addDataAnnotationType(new UserFormAnnotationType(printScreenDataBlock));
PamSettingManager.getInstance().registerSettings(this);
}

View File

@ -26,6 +26,11 @@ import PamguardMVC.dataSelector.DataSelector;
import ai.djl.engine.Engine;
import annotation.handler.AnnotationHandler;
import clickTrainDetector.layout.ClickTrainSymbolManager;
import clipgenerator.ClipDataUnit;
import clipgenerator.ClipDisplayDataBlock;
import clipgenerator.clipDisplay.ClipDisplayDecorations;
import clipgenerator.clipDisplay.ClipDisplayParent;
import clipgenerator.clipDisplay.ClipDisplayUnit;
import dataPlotsFX.data.TDDataProviderRegisterFX;
import detectionPlotFX.data.DDPlotRegister;
import generalDatabase.SQLLoggingAddon;
@ -41,6 +46,7 @@ import rawDeepLearningClassifier.dlClassification.DLClassNameManager;
import rawDeepLearningClassifier.dlClassification.DLClassiferModel;
import rawDeepLearningClassifier.dlClassification.DLClassifierChooser;
import rawDeepLearningClassifier.dlClassification.DLClassifyProcess;
import rawDeepLearningClassifier.dlClassification.DLDetectionDataBlock;
import rawDeepLearningClassifier.dlClassification.animalSpot.SoundSpotClassifier;
import rawDeepLearningClassifier.dlClassification.archiveModel.PamZipModelClassifier;
import rawDeepLearningClassifier.dlClassification.delphinID.DelphinIDClassifier;
@ -63,6 +69,9 @@ import rawDeepLearningClassifier.logging.DLResultBinarySource;
import rawDeepLearningClassifier.logging.DLResultLogging;
import rawDeepLearningClassifier.offline.DLOfflineProcess;
import rawDeepLearningClassifier.segmenter.SegmenterProcess;
import rawDeepLearningClassifier.swing.DLClipDecorations;
import rawDeepLearningClassifier.swing.DLClipDisplayProvider;
import userDisplay.UserDisplayControl;
/**
* Module which uses an external deep learning classifier to identify any data
@ -107,7 +116,7 @@ import rawDeepLearningClassifier.segmenter.SegmenterProcess;
* @author Jamie Macaulay
*
*/
public class DLControl extends PamControlledUnit implements PamSettings {
public class DLControl extends PamControlledUnit implements PamSettings, ClipDisplayParent {
/**
* PLUGIN_BUILD boolean is set to true so that the class loader isn't changed. When
@ -367,6 +376,8 @@ public class DLControl extends PamControlledUnit implements PamSettings {
//create the classiifer chooser.
dlClassifierChooser = new DLClassifierChooser(this);
UserDisplayControl.addUserDisplayProvider(new DLClipDisplayProvider(this));
// ensure everything is updated.
updateParams(rawDLParmas);
}
@ -742,6 +753,34 @@ public class DLControl extends PamControlledUnit implements PamSettings {
}
@Override
public ClipDisplayDataBlock<ClipDataUnit> getClipDataBlock() {
Object dlBlock = dlClassifyProcess.getDLDetectionDatablock();
ClipDisplayDataBlock<ClipDataUnit> clipBlock = (ClipDisplayDataBlock<ClipDataUnit>) dlBlock;
return clipBlock;
}
@Override
public String getDisplayName() {
return getUnitName() + " Clips";
}
@Override
public ClipDisplayDecorations getClipDecorations(ClipDisplayUnit clipDisplayUnit) {
return new DLClipDecorations(this, clipDisplayUnit);
}
@Override
public void displaySettingChange() {
// TODO Auto-generated method stub
}

View File

@ -13,7 +13,9 @@ import PamguardMVC.DataUnitBaseData;
import PamguardMVC.PamDataUnit;
import PamguardMVC.PamInstantProcess;
import PamguardMVC.PamObservable;
import PamguardMVC.PamProcess;
import binaryFileStorage.DataUnitFileInformation;
import clipgenerator.ClipProcess;
import pamScrollSystem.AbstractScrollManager;
import rawDeepLearningClassifier.DLControl;
import rawDeepLearningClassifier.RawDLParams;
@ -39,7 +41,7 @@ import rawDeepLearningClassifier.segmenter.SegmenterDetectionGroup;
* @author Jamie Macaulay
*
*/
public class DLClassifyProcess extends PamInstantProcess {
public class DLClassifyProcess extends PamProcess {
/**
@ -95,7 +97,7 @@ public class DLClassifyProcess extends PamInstantProcess {
private DLGroupDataBlock dlGroupDetectionDataBlock;
public DLClassifyProcess(DLControl dlControl, SegmenterDataBlock parentDataBlock) {
super(dlControl);
super(dlControl, null);
this.setParentDataBlock(parentDataBlock);
@ -689,7 +691,7 @@ public class DLClassifyProcess extends PamInstantProcess {
basicData.setSampleDuration((long) (groupDataBuffer.size()*dlControl.getDLParams().rawSampleSize));
// System.out.println("Model result: " + modelResult.size());
DLDetection dlDetection = new DLDetection(basicData, rawdata);
DLDetection dlDetection = new DLDetection(basicData, rawdata, getSampleRate());
addDLAnnotation(dlDetection,modelResult);
//create the data unit

View File

@ -12,6 +12,7 @@ import PamguardMVC.RawDataHolder;
import PamguardMVC.RawDataTransforms;
import annotation.DataAnnotation;
import bearinglocaliser.annotation.BearingAnnotation;
import clipgenerator.ClipDataUnit;
import clipgenerator.ClipSpectrogram;
import rawDeepLearningClassifier.logging.DLAnnotation;
@ -23,7 +24,7 @@ import rawDeepLearningClassifier.logging.DLAnnotation;
* @author Jamie Macaulay
*
*/
public class DLDetection extends PamDataUnit implements PamDetection, RawDataHolder {
public class DLDetection extends ClipDataUnit implements PamDetection, RawDataHolder {
/**
* The abstract localisation
@ -51,8 +52,8 @@ public class DLDetection extends PamDataUnit implements PamDetection, RawDataHol
*/
@Deprecated
public DLDetection(long timeMilliseconds, int channelBitmap, long startSample, long durationSamples,
ArrayList<PredictionResult> modelResults, double[][] waveData) {
super(timeMilliseconds, channelBitmap, startSample, durationSamples);
ArrayList<PredictionResult> modelResults, double[][] waveData, float sampleRate) {
super(timeMilliseconds, timeMilliseconds, startSample, (int) durationSamples, channelBitmap, null, null, waveData, sampleRate);
DLAnnotation annotation = new DLAnnotation(null, modelResults);
this.addDataAnnotation(annotation);
this.waveData=waveData;
@ -68,9 +69,17 @@ public class DLDetection extends PamDataUnit implements PamDetection, RawDataHol
* @param probdata - the probability data.
* @param waveData - the wave data.
*/
public DLDetection(DataUnitBaseData baseData, double[][] waveData) {
super(baseData);
//System.out.println("Load DL deteciton: " + this.getChannelBitmap());
public DLDetection(DataUnitBaseData baseData, double[][] waveData, float sampleRate) {
// super(baseData);
/*
* public ClipDataUnit(long timeMilliseconds, long triggerMilliseconds,
long startSample, int durationSamples, int channelMap, String fileName,
String triggerName, double[][] rawData, float sourceSampleRate) {
super(timeMilliseconds, channelMap, startSample, durationSamples);
*/
super(baseData.getTimeMilliseconds(), baseData.getTimeMilliseconds(), baseData.getStartSample(), waveData == null ? 0 : waveData[0].length, baseData.getChannelBitmap(), null,
null, waveData, sampleRate);
//System.out.println("Load DL detection: " + this.getChannelBitmap());
this.waveData=waveData;
rawDataTransforms= new RawDataTransforms(this);
setAmplitude();//must set amplitude as this is not stored in binary files.
@ -139,7 +148,7 @@ public class DLDetection extends PamDataUnit implements PamDetection, RawDataHol
* @param channel
* @return
*/
private double[] getWaveData(int channel) {
public double[] getWaveData(int channel) {
if (waveData!=null) {
return this.getWaveData()[channel];
}

View File

@ -5,6 +5,8 @@ import PamView.GroupedSourceParameters;
import PamguardMVC.AcousticDataBlock;
import PamguardMVC.dataSelector.DataSelectorCreator;
import clickTrainDetector.dataselector.CTDataSelectCreator;
import clipgenerator.ClipDataBlock;
import clipgenerator.ClipDisplayDataBlock;
import rawDeepLearningClassifier.DLControl;
import rawDeepLearningClassifier.dataSelector.DLDataSelectCreator;
import rawDeepLearningClassifier.tethys.DLSpeciesManager;
@ -19,7 +21,7 @@ import tethys.species.DataBlockSpeciesManager;
* @author Jamie Macaulay
*
*/
public class DLDetectionDataBlock extends AcousticDataBlock<DLDetection> implements GroupedDataSource {
public class DLDetectionDataBlock extends ClipDisplayDataBlock<DLDetection> implements GroupedDataSource {
/**
* Reference to the deep learning classifier process.

View File

@ -198,7 +198,7 @@ public class OrcaSpotClassifier implements DLClassiferModel, PamSettings {
modelResults.add(modelResult);
dlControl.getDLClassifyProcess().getDLDetectionDatablock().addPamData(new DLDetection(groupedRawData.getTimeMilliseconds(),
groupedRawData.getChannelBitmap(), groupedRawData.getStartSample(),
groupedRawData.getSampleDuration(), modelResults, null));
groupedRawData.getSampleDuration(), modelResults, null, dlControl.getDLClassifyProcess().getSampleRate()));
}
groupedRawData= null; //just in case

View File

@ -134,7 +134,7 @@ public class DLDetectionBinarySource extends BinaryDataSource {
if (baseData.getChannelBitmap()==0) {
baseData.setChannelBitmap(1);
}
DLDetection newUnit = new DLDetection(baseData, rawData);
DLDetection newUnit = new DLDetection(baseData, rawData, clipDataBlock.getSampleRate());
return newUnit;
}

View File

@ -0,0 +1,85 @@
package rawDeepLearningClassifier.swing;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JLabel;
import javax.swing.JPanel;
import PamView.dialog.PamGridBagContraints;
import clipgenerator.clipDisplay.ClipDisplayDecorations;
import clipgenerator.clipDisplay.ClipDisplayUnit;
import rawDeepLearningClassifier.DLControl;
import rawDeepLearningClassifier.dlClassification.DLDetection;
import rawDeepLearningClassifier.dlClassification.PredictionResult;
public class DLClipDecorations extends ClipDisplayDecorations {
private Color normalGrey;
private DLDetection dlDetection;
private JPanel dataPanel;
private PredictionResult result;
public DLClipDecorations(DLControl dlControl, ClipDisplayUnit clipDisplayUnit) {
super(clipDisplayUnit);
JPanel panel = new JPanel();
normalGrey = panel.getBackground();
this.dlDetection = (DLDetection) clipDisplayUnit.getClipDataUnit();
result = dlControl.getDLClassifyProcess().getBestModelResult(dlDetection);
if (result != null) {
dataPanel = new JPanel(new BorderLayout());
// GridBagConstraints c = new PamGridBagContraints();
// String res = result.getResultString();
double best = 0;
int bestInd = -1;
float[] prediction = result.getPrediction();
if (prediction != null) {
for (int i = 0; i < prediction.length; i++) {
if (prediction[i] > best) {
best = prediction[i];
bestInd = i;
}
}
String p = String.format("Class %d, score %3.2f", bestInd, best);
dataPanel.add(BorderLayout.WEST, new JLabel(p));
}
}
}
@Override
public ClipDisplayUnit getClipDisplayUnit() {
return super.getClipDisplayUnit();
}
@Override
public Color getClipBackground() {
return Color.darkGray;
}
@Override
public void drawOnClipAxis(Graphics g) {
super.drawOnClipAxis(g);
}
@Override
public void drawOnClipBorder(Graphics g) {
super.drawOnClipBorder(g);
}
@Override
public void decorateDisplay() {
super.decorateDisplay();
if (dataPanel != null) {
getClipDisplayUnit().add(dataPanel, BorderLayout.NORTH);
}
}
}

View File

@ -0,0 +1,49 @@
package rawDeepLearningClassifier.swing;
import clipgenerator.clipDisplay.ClipDisplayPanel;
import rawDeepLearningClassifier.DLControl;
import userDisplay.UserDisplayComponent;
import userDisplay.UserDisplayControl;
import userDisplay.UserDisplayProvider;
public class DLClipDisplayProvider implements UserDisplayProvider {
private DLControl dlControl;
public DLClipDisplayProvider(DLControl dlControl) {
super();
this.dlControl = dlControl;
}
@Override
public String getName() {
return dlControl.getUnitName() + " clips";
}
@Override
public UserDisplayComponent getComponent(UserDisplayControl userDisplayControl, String uniqueDisplayName) {
return new ClipDisplayPanel(dlControl);
}
@Override
public Class getComponentClass() {
return ClipDisplayPanel.class;
}
@Override
public int getMaxDisplays() {
return 0;
}
@Override
public boolean canCreate() {
return true;
}
@Override
public void removeDisplay(UserDisplayComponent component) {
// TODO Auto-generated method stub
}
}

View File

@ -22,6 +22,7 @@
package rocca;
import java.awt.Frame;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.Serializable;
@ -30,20 +31,27 @@ import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import PamController.DataIntegrityChecker;
import PamController.DataOutputStore;
import PamController.PamControlledUnit;
import PamController.PamControlledUnitSettings;
import PamController.PamController;
import PamController.PamControllerInterface;
import PamController.PamSettingManager;
import PamController.PamSettings;
import PamController.fileprocessing.StoreStatus;
import PamUtils.PamCalendar;
import PamView.PamGui;
import PamguardMVC.PamDataBlock;
import PamguardMVC.PamDataUnit;
import PamguardMVC.dataOffline.OfflineDataLoadInfo;
import clickDetector.ClickControl;
import clickDetector.ClickDetection;
import clickDetector.offlineFuncs.OfflineEventDataBlock;
import clickDetector.offlineFuncs.OfflineEventDataUnit;
import dataGram.DatagramManager;
import dataMap.OfflineDataMapPoint;
import pamScrollSystem.ViewLoadObserver;
/**
@ -504,6 +512,61 @@ public class RoccaControl extends PamControlledUnit implements PamSettings {
public RoccaProcess getRoccaProcess() {
return roccaProcess;
}
/*
* Consider implementing the DataStore interface so that ROCCA data can be deleted on reprocessing.
@Override
public void createOfflineDataMap(Window parentFrame) {
// not used, but part of required interface.
}
@Override
public String getDataSourceName() {
return getUnitName();
}
@Override
public String getDataLocation() {
return null;
}
@Override
public boolean loadData(PamDataBlock dataBlock, OfflineDataLoadInfo offlineDataLoadInfo,
ViewLoadObserver loadObserver) {
return false;
}
@Override
public boolean saveData(PamDataBlock dataBlock) {
return false;
}
@Override
public boolean rewriteIndexFile(PamDataBlock dataBlock, OfflineDataMapPoint dmp) {
return false;
}
@Override
public DatagramManager getDatagramManager() {
return null;
}
@Override
public StoreStatus getStoreStatus(boolean getDetail) {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean deleteDataFrom(long timeMillis) {
// TODO Auto-generated method stub
return false;
}
@Override
public DataIntegrityChecker getInegrityChecker() {
// TODO Auto-generated method stub
return null;
}
*/
}

View File

@ -21,11 +21,15 @@
package rocca;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import PamView.GeneralProjector;
import PamView.PamDetectionOverlayGraphics;
import PamView.PamSymbol;
import PamView.PamSymbolType;
import PamView.symbol.SymbolData;
import PamguardMVC.PamDataUnit;
/**
* @author Michael Oswald
@ -46,8 +50,8 @@ public class RoccaGraphics extends PamDetectionOverlayGraphics {
int iCol = 0;
public RoccaGraphics(RoccaProcess roccaProcess) {
super(roccaProcess.fftDataBlockIn, new PamSymbol(defaultSymbol));
public RoccaGraphics(RoccaProcess roccaProcess, RoccaLoggingDataBlock rldb) {
super(rldb, new PamSymbol(defaultSymbol));
this.roccaProcess = roccaProcess;
// if (getPamSymbol() == null) {
// PamSymbol mapSymbol = new PamSymbol(PamSymbolType.SYMBOL_STAR, 8, 8, true,
@ -56,10 +60,11 @@ public class RoccaGraphics extends PamDetectionOverlayGraphics {
// }
}
// @Override
// protected Rectangle drawOnSpectrogram(Graphics g, PamDataUnit pamDataUnit, GeneralProjector generalProjector) {
// return drawContourShape(g, (RoccaSightingDataUnit) pamDataUnit, generalProjector);
// }
@Override
protected Rectangle drawOnSpectrogram(Graphics g, PamDataUnit pamDataUnit, GeneralProjector generalProjector) {
return super.drawOnSpectrogram(g, pamDataUnit, generalProjector);
}
//
// Rectangle drawContourShape(Graphics g, RoccaSightingDataUnit rsdu,
// GeneralProjector projector) {

View File

@ -64,6 +64,7 @@ public class RoccaLoggingDataBlock extends PamDataBlock<RoccaLoggingDataUnit> {
this.roccaControl = roccaControl;
//this.setNaturalLifetime(Integer.MAX_VALUE/1000);
this.setNaturalLifetime(10);
setPamSymbolManager(new RoccaSymbolManager(this, RoccaGraphics.defaultSymbol));
}

View File

@ -21,10 +21,16 @@
package rocca;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.Set;
import com.google.protobuf.Duration;
import PamDetection.PamDetection;
import PamguardMVC.PamDataUnit;
import rocca.RoccaContourStats.ParamIndx;
import tethys.pamdata.AutoTethysProvider;
/**
@ -248,6 +254,88 @@ public class RoccaLoggingDataUnit extends PamDataUnit<PamDataUnit,PamDataUnit> i
public void setLongitude(double longitude) {
this.longitude = longitude;
}
@Override
public String getSummaryString() {
String base = super.getSummaryString();
// if (detectionCount != 0) {
// base += String.format("Detection count: %d<br>", detectionCount);
// }
if (classifiedAs != null) {
base += "Classified as: " + classifiedAs + "<br>";
}
if (classifierUsed != null) {
base += "Classifier used: " + classifierUsed + "<br>";
}
if (classifier2Used != null) {
base += "Second Classifier: " + classifier2Used + "<br>";
}
if (contourStats == null) {
return base;
}
EnumMap<ParamIndx, Double> lst = contourStats.getContour();
if (lst == null) {
return base;
}
int npRow = 3;
Set<ParamIndx> keys = lst.keySet();
int i = 0;
for (ParamIndx aKey : keys) {
Double data = lst.get(aKey);
if (data == null) {
continue;
}
data = AutoTethysProvider.roundDecimalPlaces(data, 3);
base += String.format("%s: %s", aKey.toString(), data.toString());
if (++i % npRow == 0) {
base += ",<br>";
}
else {
base += ", ";
}
}
return base;
}
@Override
public double[] getFrequency() {
double[] fr = super.getFrequency();
if (fr != null && fr.length == 2 && fr[1] > 0) {
return fr;
}
if (contourStats.getContour() == null) {
return null;
}
ParamIndx[] ps = {RoccaContourStats.ParamIndx.FREQMIN, RoccaContourStats.ParamIndx.FREQMAX};
fr = new double[2];
for (int i = 0; i < 2; i++) {
Double f = contourStats.getContour().get(ps[i]);
if (f == null) {
return null;
}
else {
fr[i] = f;
}
}
return fr;
}
@Override
public Double getDurationInMilliseconds() {
if (contourStats.getContour() == null) {
return null;
}
Double dur = contourStats.getContour().get(RoccaContourStats.ParamIndx.DURATION);
if (dur == null) {
return null;
}
return dur*1000.;
}

View File

@ -152,6 +152,7 @@ public class RoccaProcess extends PamProcess {
roccaClassifier = new RoccaClassifier(this);
rldb = new RoccaLoggingDataBlock(roccaControl, this, 0);
rldb.setOverlayDraw(new RoccaGraphics(this, rldb));
rldb.SetLogging(new RoccaStatsLogger(roccaControl, rldb));
rldb.setMixedDirection(PamDataBlock.MIX_INTODATABASE);
addOutputDataBlock(rldb);

View File

@ -0,0 +1,14 @@
package rocca;
import PamView.symbol.StandardSymbolManager;
import PamView.symbol.SymbolData;
import PamguardMVC.PamDataBlock;
public class RoccaSymbolManager extends StandardSymbolManager {
public RoccaSymbolManager(PamDataBlock pamDataBlock, SymbolData defaultSymbol) {
super(pamDataBlock, defaultSymbol);
}
}

View File

@ -1,12 +1,9 @@
package tethys.species;
import java.io.Serializable;
import java.util.ArrayList;
import PamController.PamControlledUnitSettings;
import PamController.PamController;
import PamController.PamSettingManager;
import PamController.PamSettings;
import PamView.dialog.PamDialogPanel;
import PamguardMVC.PamDataBlock;
import PamguardMVC.PamDataUnit;
import tethys.species.swing.DataBlockSpeciesDialog;
@ -26,7 +23,7 @@ import tethys.species.swing.DataBlockSpeciesDialog;
* @author dg50
*
*/
abstract public class DataBlockSpeciesManager<T extends PamDataUnit> /*implements PamSettings*/ {
abstract public class DataBlockSpeciesManager<T extends PamDataUnit> {
/**
* The serialised bit. Always exists (or should be created) even if there
@ -264,6 +261,15 @@ abstract public class DataBlockSpeciesManager<T extends PamDataUnit> /*implement
}
datablockSpeciesMap.clearMap();
}
/**
* Return a (preferably) small dialog panel that can contain
* options for the species manager.
* @return
*/
public PamDialogPanel getDialogPanel(SpeciesManagerObserver speciesManagerObserver) {
return null;
}
/*
@Override

View File

@ -0,0 +1,12 @@
package tethys.species;
/**
* Observe changes in a spcies managers options.
* @author dg50
*
*/
public interface SpeciesManagerObserver {
public void update();
}

View File

@ -64,7 +64,9 @@ public class SpeciesMapManager implements PamSettings {
private SpeciesMapManager() {
PamSettingManager.getInstance().registerSettings(this);
globalSpeciesMap = new GlobalSpeciesMap();
if (globalSpeciesMap == null) {
globalSpeciesMap = new GlobalSpeciesMap();
}
}
/**
@ -169,7 +171,7 @@ public class SpeciesMapManager implements PamSettings {
return new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
exportSpeciesMaps(parentFrame);
exportSpeciesMaps(parentFrame, null);
}
};
}
@ -186,12 +188,13 @@ public class SpeciesMapManager implements PamSettings {
/**
* Export all species maps to a serialized object file.
* @param parentFrame
* @param singleDataBlock name of datablock to automatically check.
* @return
*/
public boolean exportSpeciesMaps(Window parentFrame) {
public boolean exportSpeciesMaps(Window parentFrame, String singleDataBlock) {
// gather the species maps from the data blocks...
gatherSpeciesMaps();
GlobalSpeciesMap toExport = SpeciesMapIODialog.showDialog(parentFrame, globalSpeciesMap, true, null);
GlobalSpeciesMap toExport = SpeciesMapIODialog.showDialog(parentFrame, globalSpeciesMap, true, singleDataBlock);
if (toExport == null) {
return false;
}

View File

@ -10,13 +10,16 @@ import javax.swing.JScrollPane;
import javax.swing.border.TitledBorder;
import PamView.dialog.PamDialogPanel;
import PamView.panel.PamAlignmentPanel;
import PamView.panel.WestAlignedPanel;
import PamguardMVC.PamDataBlock;
import tethys.species.DataBlockSpeciesManager;
import tethys.species.DataBlockSpeciesMap;
import tethys.species.SpeciesManagerObserver;
import tethys.species.DataBlockSpeciesCodes;
import tethys.species.SpeciesMapItem;
public class DataBlockSpeciesPanel implements PamDialogPanel {
public class DataBlockSpeciesPanel implements PamDialogPanel, SpeciesManagerObserver {
private JPanel mainPanel;
@ -28,6 +31,8 @@ public class DataBlockSpeciesPanel implements PamDialogPanel {
private String singleSpecies;
private DataBlockSpeciesManager speciesManager;
/**
* Panel of info about a species name in PAMGuard relating it to a call type and ITIS
* code for output to Tethys.
@ -38,7 +43,19 @@ public class DataBlockSpeciesPanel implements PamDialogPanel {
super();
this.dataBlock = dataBlock;
this.singleSpecies = singleSpecies;
speciesManager = dataBlock.getDatablockSpeciesManager();
mainPanel = new JPanel(new BorderLayout());
if (singleSpecies == null) {
// only add additional options if it's the more global use of this dialog.
PamDialogPanel dialogPanel = speciesManager.getDialogPanel(this);
if (dialogPanel != null) {
JPanel nwPanel = new WestAlignedPanel(dialogPanel.getDialogComponent());
mainPanel.add(BorderLayout.NORTH, nwPanel);
}
}
speciesPanel = new JPanel();
JScrollPane scrollPane = new JScrollPane(speciesPanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
mainPanel.add(scrollPane, BorderLayout.CENTER);
@ -57,7 +74,6 @@ public class DataBlockSpeciesPanel implements PamDialogPanel {
speciesPanel.setLayout(new BoxLayout(speciesPanel, BoxLayout.Y_AXIS));
subPanels.clear();
DataBlockSpeciesManager speciesManager = dataBlock.getDatablockSpeciesManager();
// DataBlockSpeciesCodes speciesTypes = speciesManager.getSpeciesCodes();
ArrayList<String> speciesNames = speciesManager.getAllSpeciesCodes();
DataBlockSpeciesMap speciesMap = speciesManager.getDatablockSpeciesMap();
@ -92,4 +108,9 @@ public class DataBlockSpeciesPanel implements PamDialogPanel {
return errors == 0;
}
@Override
public void update() {
setParams();
}
}

View File

@ -1,6 +1,7 @@
package tethys.swing.export;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
@ -16,6 +17,7 @@ import javax.swing.border.TitledBorder;
import PamController.PamController;
import PamView.component.PamSettingsIconButton;
import PamView.dialog.PamDialogPanel;
import PamView.dialog.PamGridBagContraints;
import PamView.dialog.warn.WarnOnce;
import PamView.panel.PamAlignmentPanel;
@ -25,6 +27,7 @@ import tethys.TethysControl;
import tethys.output.StreamExportParams;
import tethys.species.DataBlockSpeciesManager;
import tethys.species.DataBlockSpeciesMap;
import tethys.species.SpeciesManagerObserver;
import tethys.species.SpeciesMapItem;
import tethys.species.SpeciesMapManager;
import tethys.species.swing.DataBlockSpeciesDialog;
@ -35,7 +38,7 @@ import tethys.species.swing.DataBlockSpeciesDialog;
* @author dg50
*
*/
public class CallTypeCard extends ExportWizardCard {
public class CallTypeCard extends ExportWizardCard implements SpeciesManagerObserver {
private DataBlockSpeciesManager speciesManager;
// private DataBlockSpeciesCodes codes;
@ -53,18 +56,63 @@ public class CallTypeCard extends ExportWizardCard {
private DataBlockSpeciesMap speciesMap;
private JPanel speciesPanel;
public CallTypeCard(TethysControl tethysControl, PamWizard pamWizard, String title, PamDataBlock dataBlock) {
super(tethysControl, pamWizard, title, dataBlock);
speciesManager = dataBlock.getDatablockSpeciesManager();
speciesMap = speciesManager.getDatablockSpeciesMap();
speciesPanel = new JPanel();
speciesPanel.setLayout(new GridBagLayout());
speciesPanel.setToolTipText(bitTip);
fillSpeciesPanel();
JPanel nPanel = new PamAlignmentPanel(speciesPanel, BorderLayout.NORTH);
JScrollPane scrollPane = new JScrollPane(nPanel);
this.setBorder(new TitledBorder("Species / Call types to export"));
this.setLayout(new BorderLayout());
this.add(scrollPane, BorderLayout.CENTER);
JPanel northPanel = new JPanel(new BorderLayout());
PamDialogPanel dialogComp = speciesManager.getDialogPanel(this);
if (dialogComp != null) {
northPanel.add(BorderLayout.WEST, dialogComp.getDialogComponent());
this.add(BorderLayout.NORTH, northPanel);
}
JPanel southPanel = new JPanel(new BorderLayout());
// southPanel.setBorder(new TitledBorder("Controls"));
JButton importButton = new JButton("Import species map");
importButton.setToolTipText("Import a species map previously saved from another PAMGuard configuration");
importButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
importSpeciesMap(importButton);
}
});
JButton exportButton = new JButton("Export species map");
exportButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
exportSpeciesMap(exportButton);
}
});
JPanel swPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
southPanel.add(swPanel, BorderLayout.WEST);
swPanel.add(importButton);
swPanel.add(exportButton);
this.add(southPanel, BorderLayout.SOUTH);
}
private void fillSpeciesPanel() {
speciesPanel.removeAll();
names = speciesManager.getAllSpeciesCodes();
speciesSelection = new JCheckBox[names.size()];
itisLabels = new JLabel[names.size()];
speciesNames = new JLabel[names.size()];
callTypes = new JLabel[names.size()];
JPanel spPanel = new JPanel();
spPanel.setLayout(new GridBagLayout());
spPanel.setToolTipText(bitTip);
PamGridBagContraints c = new PamGridBagContraints();
commonNames = new JCheckBox("Species");
commonNames.addActionListener(new ActionListener() {
@ -78,10 +126,10 @@ public class CallTypeCard extends ExportWizardCard {
for (int i = 0; i < tits.length; i++) {
JComponent lab;
if (i == 3) {
spPanel.add(lab=commonNames, c);
speciesPanel.add(lab=commonNames, c);
}
else {
spPanel.add(lab = new JLabel(tits[i], JLabel.LEFT), c);
speciesPanel.add(lab = new JLabel(tits[i], JLabel.LEFT), c);
}
lab.setToolTipText(tips[i]);
c.gridx++;
@ -90,43 +138,26 @@ public class CallTypeCard extends ExportWizardCard {
c.gridx = 0;
c.gridy++;
speciesSelection[i] = new JCheckBox();
spPanel.add(speciesSelection[i], c);
speciesPanel.add(speciesSelection[i], c);
c.gridx++;
spPanel.add(new JLabel(names.get(i)), c);
speciesPanel.add(new JLabel(names.get(i)), c);
c.gridx++;
spPanel.add(itisLabels[i] = new JLabel(), c);
speciesPanel.add(itisLabels[i] = new JLabel(), c);
c.gridx++;
spPanel.add(speciesNames[i] = new JLabel(), c);
speciesPanel.add(speciesNames[i] = new JLabel(), c);
c.gridx++;
spPanel.add(callTypes[i] = new JLabel(), c);
speciesPanel.add(callTypes[i] = new JLabel(), c);
fillItemInfo(i);
c.gridx++;
PamSettingsIconButton but = new PamSettingsIconButton();
but.setToolTipText("Edit species id and call type");
but.addActionListener(new SpeciesAction(i));
spPanel.add(but, c);
speciesPanel.add(but, c);
}
JPanel nPanel = new PamAlignmentPanel(spPanel, BorderLayout.NORTH);
JScrollPane scrollPane = new JScrollPane(nPanel);
this.setBorder(new TitledBorder("Species / Call types to export"));
this.setLayout(new BorderLayout());
this.add(scrollPane, BorderLayout.CENTER);
JPanel southPanel = new JPanel(new BorderLayout());
// southPanel.setBorder(new TitledBorder("Controls"));
JButton importButton = new JButton("Import species mapping");
importButton.setToolTipText("Import a species map previously saved from another PAMGuard configuration");
importButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
importSpeciesMap(importButton);
}
});
southPanel.add(importButton, BorderLayout.WEST);
this.add(southPanel, BorderLayout.SOUTH);
}
private void fillAllItemInfo() {
for (int i = 0; i < names.size(); i++) {
fillItemInfo(i);
@ -165,6 +196,11 @@ public class CallTypeCard extends ExportWizardCard {
}
}
private void exportSpeciesMap(JButton exportButton) {
SpeciesMapManager mapManager = SpeciesMapManager.getInstance();
mapManager.exportSpeciesMaps(getPamWizard(), getDataBlock().getLongDataName());
}
private class SpeciesAction implements ActionListener {
private int itemIndex;
@ -229,4 +265,9 @@ public class CallTypeCard extends ExportWizardCard {
}
@Override
public void update() {
fillSpeciesPanel();
}
}