More work on delphinID classifier but not quite there yet.

This commit is contained in:
Jamie Mac 2024-05-03 16:29:37 +01:00
parent ee694146c3
commit c1f4ba9e37
10 changed files with 240 additions and 88 deletions

View File

@ -228,6 +228,7 @@ public class DLControl extends PamControlledUnit implements PamSettings {
// classify the raw data segments.
addPamProcess(dlClassifyProcess = new DLClassifyProcess(this, segmenterProcess.getSegmenterDataBlock()));
dlClassifyProcess.addMultiPlexDataBlock(segmenterProcess.getSegmenteGrouprDataBlock());
//manages the names assigned to different output classes.
dlClassNameManager = new DLClassNameManager(this);

View File

@ -20,6 +20,7 @@ import rawDeepLearningClassifier.logging.DLAnnotation;
import rawDeepLearningClassifier.logging.DLAnnotationType;
import rawDeepLearningClassifier.segmenter.GroupedRawData;
import rawDeepLearningClassifier.segmenter.SegmenterDataBlock;
import rawDeepLearningClassifier.segmenter.SegmenterDetectionGroup;
/**
* The deep learning classification process. This takes a segment of raw data from the segmenter.
@ -64,15 +65,13 @@ public class DLClassifyProcess extends PamInstantProcess {
/**
* The DL buffer
*/
private ArrayList<GroupedRawData> classificationBuffer;
private ArrayList<PamDataUnit> classificationBuffer;
/**
* The DL annotation type.
*/
private DLAnnotationType dlAnnotationType;
/**
* The last parent data for grouped data. This is used to ensure that DLDetections
* correspond to the raw chunk of data from a parent detection e.g. a click detection.
@ -117,7 +116,7 @@ public class DLClassifyProcess extends PamInstantProcess {
overlayGraphics.setDetectionData(true);
dlDetectionDataBlock.setOverlayDraw(overlayGraphics);
classificationBuffer = new ArrayList<GroupedRawData>();
classificationBuffer = new ArrayList<PamDataUnit>();
//the process name.
setProcessName("Deep Learning Classifier");
@ -194,36 +193,71 @@ public class DLClassifyProcess extends PamInstantProcess {
*/
@Override
public void newData(PamObservable obs, PamDataUnit pamRawData) {
// System.out.println("NEW SEGMENTER DATA");
if (pamRawData instanceof SegmenterDetectionGroup) {
if (classificationBuffer.size()>=1) {
System.out.println("RUN THE MODEL FOR WHISTLES: ");
runDetectionGroupModel();
classificationBuffer.clear();
}
else {
classificationBuffer.add(pamRawData);
}
}
if (pamRawData instanceof GroupedRawData) {
//the raw data units should appear in sequential channel order
GroupedRawData rawDataUnit = (GroupedRawData) pamRawData;
if (checkGroupData(rawDataUnit)) {
//check whether the classification buffer is full. If it is then run
if (isClassificationBufferFull(classificationBuffer, rawDataUnit)) {
if (isRawClassificationBufferFull(classificationBuffer, rawDataUnit)) {
//first call run model to clear out the classification buffer if needs be
runModel();
runRawModel();
classificationBuffer.clear();
}
classificationBuffer.add(rawDataUnit);
}
// System.out.println("New raw data in: chan: " + PamUtils.getSingleChannel(pamRawData.getChannelBitmap()) +
// " Size: " + pamRawData.getSampleDuration() + " first sample: " + rawDataUnit.getRawData()[0][0]
// + "Parent UID: " + rawDataUnit.getParentDataUnit().getUID());
}
// System.out.println("New raw data in: chan: " + PamUtils.getSingleChannel(pamRawData.getChannelBitmap()) +
// " Size: " + pamRawData.getSampleDuration() + " first sample: " + rawDataUnit.getRawData()[0][0]
// + "Parent UID: " + rawDataUnit.getParentDataUnit().getUID());
}
/**
* Run a model for which the input is a detection group.
*/
private void runDetectionGroupModel() {
if (classificationBuffer.size()<=0) return;
ArrayList<PamDataUnit> classificationBufferTemp = (ArrayList<PamDataUnit>) classificationBuffer.clone();
ArrayList<? extends PredictionResult> modelResults = this.dlControl.getDLModel().runModel(classificationBufferTemp);
for (int i=0; i<classificationBufferTemp.size(); i++) {
if (modelResults.get(i)!=null) {
DLDataUnit dlDataUnit = predictionToDataUnit(classificationBuffer.get(i), modelResults.get(i));
this.dlModelResultDataBlock.addPamData(dlDataUnit); //here
}
}
}
/**
* Run the model if the classification buffer is full.
*/
private void runModel() {
private void runRawModel() {
if (classificationBuffer.size()<=0) return;
//run the deep learning algorithm
ArrayList<GroupedRawData> classificationBufferTemp = (ArrayList<GroupedRawData>) classificationBuffer.clone();
ArrayList<? extends PredictionResult> modelResults = this.dlControl.getDLModel().runModel(classificationBuffer);
ArrayList<? extends PredictionResult> modelResults = this.dlControl.getDLModel().runModel(classificationBufferTemp);
if (modelResults==null) {
return; //there has been a problem
@ -235,18 +269,18 @@ public class DLClassifyProcess extends PamInstantProcess {
// System.out.println("Compare Times: " + PamCalendar.formatDBDateTime(modelResults.get(i).getTimeMillis(), true) +
// " " + PamCalendar.formatDBDateTime(classificationBufferTemp.get(i).getTimeMilliseconds(), true) + " " +
// modelResults.get(i).getPrediction()[1]);
newModelResult(modelResults.get(i), classificationBufferTemp.get(i));
newRawModelResult(modelResults.get(i), classificationBufferTemp.get(i));
}
}
}
/**
* Check whether the buffer is full and the results should be passed to the classification model.
* Check whether the buffer is full and the results should be passed to the classification model if we are using GrpoupDataUnits
* @param classificationBuffer2 - the classification buffer.
* @param rawDataUnit - the next raw data unit to add to the buffer.
* @return true if the buffer is full.
*/
private boolean isClassificationBufferFull(ArrayList<GroupedRawData> classificationBuffer2, GroupedRawData rawDataUnit) {
private boolean isRawClassificationBufferFull(ArrayList<PamDataUnit> classificationBuffer2, GroupedRawData rawDataUnit) {
if (classificationBuffer2.size()==0) return false;
@ -254,16 +288,16 @@ public class DLClassifyProcess extends PamInstantProcess {
//1) It's over a max time
//2) Contains different parent data units (if not from raw data).
GroupedRawData lastUnit = classificationBuffer2.get(classificationBuffer2.size()-1);
GroupedRawData lastUnit = (GroupedRawData) classificationBuffer2.get(classificationBuffer2.size()-1);
if (!(lastUnit.getParentDataUnit() instanceof RawDataUnit) && lastUnit.getParentDataUnit()!=rawDataUnit.getParentDataUnit()) {
//there is a new parent data unit.
return true;
}
//get the start time. Use min value instead of first data just in case units ar enot in order.
//get the start time. Use min value instead of first data just in case units are not in order.
long min = Long.MAX_VALUE;
for (GroupedRawData groupedRawData: classificationBuffer2) {
for (PamDataUnit groupedRawData: classificationBuffer2) {
if (groupedRawData.getTimeMilliseconds()<min) {
min=groupedRawData.getTimeMilliseconds();
}
@ -299,18 +333,7 @@ public class DLClassifyProcess extends PamInstantProcess {
return true;
}
/**
* Create a data unit form a model result. This is called whenever data passes a prediction threshold.
*
* @param modelResult - the model result.
* @param pamRawData - the raw data unit which the model result came from.
*/
public void newModelResult(PredictionResult modelResult, GroupedRawData pamRawData) {
//the model result may be null if the classifier uses a new thread.
//System.out.println("New segment: parent UID: " + pamRawData.getParentDataUnit().getUID() + " Prediciton: " + modelResult.getPrediction()[0]+ " " + getSourceParams().countChannelGroups());
private DLDataUnit predictionToDataUnit(PamDataUnit pamRawData, PredictionResult modelResult) {
//create a new data unit - always add to the model result section.
DLDataUnit dlDataUnit = new DLDataUnit(pamRawData.getTimeMilliseconds(), pamRawData.getChannelBitmap(),
pamRawData.getStartSample(), pamRawData.getSampleDuration(), modelResult);
@ -319,17 +342,35 @@ public class DLClassifyProcess extends PamInstantProcess {
dlDataUnit.setFrequency(new double[] {0, dlControl.getDLClassifyProcess().getSampleRate()/2});
dlDataUnit.setDurationInMilliseconds(pamRawData.getDurationInMilliseconds());
return dlDataUnit;
}
/**
* Create a data unit form a model result. This is called whenever data passes a prediction threshold.
*
* @param modelResult - the model result.
* @param pamRawData - the raw data unit which the model result came from.
*/
public void newRawModelResult(PredictionResult modelResult, GroupedRawData pamRawData) {
//the model result may be null if the classifier uses a new thread.
//System.out.println("New segment: parent UID: " + pamRawData.getParentDataUnit().getUID() + " Prediciton: " + modelResult.getPrediction()[0]+ " " + getSourceParams().countChannelGroups());
//create a new data unit - always add to the model result section.
DLDataUnit dlDataUnit = predictionToDataUnit(pamRawData, modelResult);
this.dlModelResultDataBlock.addPamData(dlDataUnit); //here
//need to implement multiple groups.
for (int i=0; i<getSourceParams().countChannelGroups(); i++) {
// System.out.println("RawDataIn: chan: " + pamRawData.getChannelBitmap()+ " " +
// PamUtils.hasChannel(getSourceParams().getGroupChannels(i), pamRawData.getChannelBitmap()) +
// " grouped source: " +getSourceParams().getGroupChannels(i) + " Channels OK? "
// +PamUtils.hasChannel(getSourceParams().getGroupChannels(i), PamUtils.getSingleChannel(pamRawData.getChannelBitmap()))
// + " groupchan: " + getSourceParams().getGroupChannels(i) + " " + PamUtils.getLowestChannel(pamRawData.getChannelBitmap())
// + " chan bitmap: " + pamRawData.getChannelBitmap());
// System.out.println("RawDataIn: chan: " + pamRawData.getChannelBitmap()+ " " +
// PamUtils.hasChannel(getSourceParams().getGroupChannels(i), pamRawData.getChannelBitmap()) +
// " grouped source: " +getSourceParams().getGroupChannels(i) + " Channels OK? "
// +PamUtils.hasChannel(getSourceParams().getGroupChannels(i), PamUtils.getSingleChannel(pamRawData.getChannelBitmap()))
// + " groupchan: " + getSourceParams().getGroupChannels(i) + " " + PamUtils.getLowestChannel(pamRawData.getChannelBitmap())
// + " chan bitmap: " + pamRawData.getChannelBitmap());
if (PamUtils.hasChannel(getSourceParams().getGroupChannels(i), PamUtils.getLowestChannel(pamRawData.getChannelBitmap()))) {
@ -425,17 +466,17 @@ public class DLClassifyProcess extends PamInstantProcess {
//first call run model to clear out the classification buffer if needs be
runModel();
runRawModel();
classificationBuffer.clear();
//need to implement multiple groups.
for (int i=0; i<getSourceParams().countChannelGroups(); i++) {
// System.out.println("Nummber segments " + groupDataBuffer[i].size() + " data unit len: " + dataUnit.getSampleDurationAsInt() + " samples UID: " + dataUnit.getUID());
// System.out.println("RawDataIn: chan: " + dataUnit.getChannelBitmap()+ " " +
// PamUtils.hasChannel(getSourceParams().getGroupChannels(i), dataUnit.getChannelBitmap()) +
// " grouped source: " +getSourceParams().getGroupChannels(i));
// System.out.println("Nummber segments " + groupDataBuffer[i].size() + " data unit len: " + dataUnit.getSampleDurationAsInt() + " samples UID: " + dataUnit.getUID());
// System.out.println("RawDataIn: chan: " + dataUnit.getChannelBitmap()+ " " +
// PamUtils.hasChannel(getSourceParams().getGroupChannels(i), dataUnit.getChannelBitmap()) +
// " grouped source: " +getSourceParams().getGroupChannels(i));
if (PamUtils.hasChannel(getSourceParams().getGroupChannels(i), PamUtils.getSingleChannel(dataUnit.getChannelBitmap()))) {
@ -532,14 +573,21 @@ public class DLClassifyProcess extends PamInstantProcess {
@Override
public void pamStart() {
// TODO Auto-generated method stub
System.out.println("PREP MODEL:");
// System.out.println("PREP MODEL:");
this.dlControl.getDLModel().prepModel();
}
@Override
public void pamStop() {
runModel(); //make sure to run the last data in the buffer.
//make sure to run the last data in the buffer.
if (this.classificationBuffer.size()>0) {
if (classificationBuffer.get(0) instanceof GroupedRawData) {
runRawModel(); //raw data or raw data units
}
if (classificationBuffer.get(0) instanceof SegmenterDetectionGroup) {
runDetectionGroupModel(); //any other data units.
}
}
//21/11/2022 - it seems like this causes a memory leak when models are reopened and closed every file...
//this.dlControl.getDLModel().closeModel();

View File

@ -271,7 +271,7 @@ public abstract class StandardClassifierModel implements DLClassiferModel, PamSe
*/
protected void newResult(StandardPrediction modelResult, PamDataUnit groupedRawData) {
if (groupedRawData instanceof GroupedRawData) {
this.dlControl.getDLClassifyProcess().newModelResult(modelResult, (GroupedRawData) groupedRawData);
this.dlControl.getDLClassifyProcess().newRawModelResult(modelResult, (GroupedRawData) groupedRawData);
}
}
//

View File

@ -91,7 +91,7 @@ public class DelphinIDClassifier extends StandardClassifierModel {
@Override
public boolean isDecision(StandardPrediction modelResult, StandardModelParams modelParmas) {
//TODO
//DelphinID uses a different decision making process to most of the standard classifiers which just pass a binary threhsoild.
//DelphinID uses a different decision making process to most of the standard classifiers which just pass a binary threshold.
return false;
}

View File

@ -49,8 +49,8 @@ public class DelphinIDWorker extends ArchiveModelWorker {
this.setModel(null); // set model to null to make sure nothing works and errors are thrown
}
dlParams.binaryClassification = new boolean[dlParams.classNames.length];
for (int i=0; i<dlParams.classNames.length; i++) {
dlParams.binaryClassification = new boolean[dlParams.numClasses];
for (int i=0; i<dlParams.numClasses; i++) {
dlParams.binaryClassification[i]=true;
}
}
@ -110,6 +110,7 @@ public class DelphinIDWorker extends ArchiveModelWorker {
double[][] transformedData2; //spectrogram data
for (int j=0; j<numChunks; j++) {
System.out.println("Number of whisltes to process: " + whistleGroups.get(j).getSubDetectionsCount() + " " + whistleGroups.get(j).getSegmentStartMillis());
//create the first transform and set then whistle data. Note that the absolute time limits are
//contained within the SegmenterDetectionGroup unit.
Whistles2Image whistles2Image = new Whistles2Image(whistleGroups.get(j), whistleImageParams);

View File

@ -185,7 +185,7 @@ public class GenericDLClassifier extends StandardClassifierModel {
* @param groupedRawData - the grouped raw data.
*/
protected void newResult(StandardPrediction modelResult, GroupedRawData groupedRawData) {
this.dlControl.getDLClassifyProcess().newModelResult(modelResult, groupedRawData);
this.dlControl.getDLClassifyProcess().newRawModelResult(modelResult, groupedRawData);
}

View File

@ -9,6 +9,7 @@ import org.jamdev.jdl4pam.transforms.FreqTransform;
import PamModel.PamModel;
import PamModel.PamModel.PluginClassloader;
import PamUtils.PamArrayUtils;
import rawDeepLearningClassifier.DLControl;
import rawDeepLearningClassifier.dlClassification.animalSpot.StandardModelParams;
@ -32,7 +33,7 @@ public class GenericModelWorker extends DLModelWorker<StandardPrediction> {
@Override
public float[] runModel(float[][][] transformedDataStack) {
//System.out.println("RUN GENERIC MODEL: " + transformedDataStack.length + " " + transformedDataStack[0].length + " " + transformedDataStack[0][0].length);
System.out.println("RUN GENERIC MODEL: " + transformedDataStack.length + " " + transformedDataStack[0].length + " " + transformedDataStack[0][0].length);
// System.out.println("RUN GENERIC MODEL: " + transformedDataStack[0][0][0]);
float[] results;
if (freqTransform)
@ -47,7 +48,8 @@ public class GenericModelWorker extends DLModelWorker<StandardPrediction> {
//System.out.println("RUN GENERIC MODEL WAVE: " + waveStack.length + " " + waveStack[0].length + " " + waveStack[0][0]);
results = getModel().runModel(waveStack);
}
//System.out.println("GENERIC MODEL RESULTS: " + results== null ? null : results.length);
System.out.println("GENERIC MODEL RESULTS: " + (results== null ? null : results.length));
PamArrayUtils.printArray(results);
return results;
}

View File

@ -28,7 +28,7 @@ public class SegmenterDetectionGroup extends GroupDetection<PamDataUnit> {
* @param timeMilliseconds - this is the start of the SEGMENT - Note that the
* @param channelBitmap - channels of all detections
* @param startSample - the stratSample of the SEGMENT.
* @param duration - the duration of the SEGMENT.
* @param duration - the duration of the SEGMENT in milliseconds.
*/
public SegmenterDetectionGroup(long timeMilliseconds, int channelBitmap, long startSample, double duration) {
super(timeMilliseconds, channelBitmap, startSample, (long) duration);
@ -52,5 +52,9 @@ public class SegmenterDetectionGroup extends GroupDetection<PamDataUnit> {
return segDuration;
}
public long getSegmentEndMillis() {
return (long) (segMillis+segDuration);
}
}

View File

@ -12,6 +12,8 @@ public class SegmenterGroupDataBlock extends PamDataBlock<SegmenterDetectionGrou
public SegmenterGroupDataBlock(String dataName, PamProcess parentProcess, int channelMap) {
super(SegmenterDetectionGroup.class, dataName, parentProcess, channelMap);
this.setNaturalLifetimeMillis(15000); //do not want to keep the data for very long - it's raw data segmnents so memory intensive
}

View File

@ -6,6 +6,7 @@ import java.util.Arrays;
import PamController.PamController;
import PamDetection.RawDataUnit;
import PamUtils.PamArrayUtils;
import PamUtils.PamUtils;
import PamView.GroupedSourceParameters;
import PamView.PamDetectionOverlayGraphics;
@ -70,7 +71,7 @@ public class SegmenterProcess extends PamProcess {
/**
* The current segmenter detection group.
*/
private SegmenterDetectionGroup segmenterDetectionGroup = null;
private SegmenterDetectionGroup[] segmenterDetectionGroup = null;
public SegmenterProcess(DLControl pamControlledUnit, PamDataBlock parentDataBlock) {
@ -111,6 +112,8 @@ public class SegmenterProcess extends PamProcess {
setupSegmenter();
}
/**
* A list of data block class types which are compatible as parent data blocks
* for the PamProcess. This can return null, e.g. in the case of Acquisition
@ -159,6 +162,7 @@ public class SegmenterProcess extends PamProcess {
if (chanGroups!=null) {
currentRawChunks = new GroupedRawData[chanGroups.length];
nextRawChunks = new GroupedRawData[chanGroups.length][];
segmenterDetectionGroup = new SegmenterDetectionGroup[chanGroups.length];
}
@ -236,33 +240,118 @@ public class SegmenterProcess extends PamProcess {
/**
* A new whistle data unit.
* A new detection data unit i.e. this is only if we have detection data which is being grouped into segments.
* @param dataUnit - the whistle data unit.
*/
private void newWhistleData(PamDataUnit dataUnit) {
ConnectedRegionDataUnit whistle = (ConnectedRegionDataUnit) dataUnit;
//TODO
//this contains no raw data so we are branching off on a completely different processing path here.
//Whislte data units are saved to a buffer and then fed to the deep learning algorithms
if (segmenterDetectionGroup==null) {
//iterate until we find the correct time
int[] chanGroups = dlControl.getDLParams().groupedSourceParams.getChannelGroups();
int index = -1;
for (int i=0; i<chanGroups.length; i++) {
if (dlControl.getDLParams().groupedSourceParams.getGroupChannels(chanGroups[i])==dataUnit.getChannelBitmap())
index=i;
}
//System.out.println("Whiste data: " + dataUnit + " " + chanGroups.length + " " + index + " " + dataUnit.getChannelBitmap());
// PamArrayUtils.printArray(chanGroups);
if (index<0) {
return;
}
if (segmenterDetectionGroup[index] == null || !detectionInSegment(dataUnit, segmenterDetectionGroup[index])) {
//System.out.println("Whiste not in segment");
//iterate until we find the correct time for this detection. This keeps the segments consist no matter
//the data units. What we do not want is the first data unit defining the start of the first segment.
long segmentStart = firstClockUpdate;
while() {
long segmenterEnd = (long) (segmentStart + getSegmentLenMillis());
}
while(!detectionInSegment(dataUnit, segmentStart, segmenterEnd)) {
segmentStart = segmenterEnd;
segmenterEnd = (long) (segmentStart + getSegmentLenMillis());
}
long startSample = this.absMillisecondsToSamples(segmenterEnd);
//now we need to create a new data unit.
if (segmenterDetectionGroup[index]!=null) {
System.out.println("SAVE WHISTLE SEGMENT!: " + segmenterDetectionGroup[index]);
//save the data unit
this.segmenterGroupDataBlock.addPamData(segmenterDetectionGroup[index]);
}
//TODO There is no good way to get the start sample?
segmenterDetectionGroup[index] = new SegmenterDetectionGroup(segmentStart, chanGroups[index], startSample, getSegmentLenMillis());
}
//System.out.println("Add whistle to existing segment");
segmenterDetectionGroup[index].addSubDetection(whistle);
}
private boolean detectionInSegment(PamDataUnit dataUnit, SegmenterDetectionGroup segmenterDetectionGroup2) {
return detectionInSegment(dataUnit, segmenterDetectionGroup2.getSegmentStartMillis(),
(long) (segmenterDetectionGroup2.getSegmentStartMillis()+segmenterDetectionGroup2.getSegmentDuration()));
}
private boolean detectionInSegment(PamDataUnit dataUnit, long segStart, long segEnd) {
//TODO - this is going to fail for very small segments.
long whistleStart = dataUnit.getTimeMilliseconds();
long whistleEnd = dataUnit.getDurationInMilliseconds().longValue();
if ((whistleStart>=segStart && whistleStart<segEnd) || ((whistleEnd>=segStart && whistleEnd<segEnd))){
//some part of the whistle is in the segment.
System.out.println("Whsitle in segment: " + whistleStart + " " + whistleEnd);
return true;
}
return false;
}
private double getSegmentLenMillis() {
double millis = (dlControl.getDLParams().rawSampleSize/this.getSampleRate())*1000.;
return millis;
}
int count=0;
public void masterClockUpdate(long milliSeconds, long sampleNumber) {
super.masterClockUpdate(milliSeconds, sampleNumber);
if (firstClockUpdate<0) {
firstClockUpdate = milliSeconds;
}
//want to make sure that a segment isn't saved if we suddenly lose
// a steady stream of data units. This ensure that the segments are saved properly
//after the master clock has gone past the end of the current segment.
if (segmenterDetectionGroup!=null && count%20==0) {
for (int i=0; i<segmenterDetectionGroup.length; i++) {
if (segmenterDetectionGroup[i]!=null && segmenterDetectionGroup[i].getSegmentEndMillis()<milliSeconds) {
//add the segment to the datablock
this.segmenterGroupDataBlock.addPamData(segmenterDetectionGroup[i]);
//create a new segment
SegmenterDetectionGroup aSegmenterDetectionGroup =
new SegmenterDetectionGroup(segmenterDetectionGroup[i].getSegmentEndMillis(),
segmenterDetectionGroup[i].getChannelBitmap(),
this.absMillisecondsToSamples(segmenterDetectionGroup[i].getSegmentEndMillis()),
getSegmentLenMillis());
segmenterDetectionGroup[i] = aSegmenterDetectionGroup;
}
}
}
count++;
}
@ -376,7 +465,7 @@ public class SegmenterProcess extends PamProcess {
/**
* Take a raw sound chunk of data and segment into discrete groups. This handles
* much situations e.g. where the segment is much larger than the raw data or
* many situations e.g. where the segment is much larger than the raw data or
* where the segment is much small than each rawDataChunk returning multiple
* segments.
*
@ -392,7 +481,7 @@ public class SegmenterProcess extends PamProcess {
/**
* Take a raw sound chunk of data and segment into discrete groups. This handles
* much situations e.g. where the segment is much larger than the raw data or
* many situations e.g. where the segment is much larger than the raw data or
* where the segment is much small than each rawDataChunk returning multiple
* segments.
*
@ -624,7 +713,7 @@ public class SegmenterProcess extends PamProcess {
//Need to copy a section of the old data into the new
if (nextRawChunks[i]!=null) {
/**
* It's very important to clone this as otherwise some very weird things happnen as the units are
* It's very important to clone this as otherwise some very weird things happen as the units are
* passed to downstream processes.
*/
currentRawChunks[i] = nextRawChunks[i][nextRawChunks[i].length-1].clone(); //in an unlikely situation this could be null should be picked up by the first null check.
@ -721,4 +810,9 @@ public class SegmenterProcess extends PamProcess {
return segmenterDataBlock;
}
public SegmenterGroupDataBlock getSegmenteGrouprDataBlock() {
return this.segmenterGroupDataBlock;
}
}