diff --git a/dependency-reduced-pom.xml b/dependency-reduced-pom.xml
index bb421ef..0211333 100644
--- a/dependency-reduced-pom.xml
+++ b/dependency-reduced-pom.xml
@@ -4,7 +4,7 @@
org.baxter.discoocrDisco OCR Accuracy Over Life Testing
- 4.3.5
+ 4.3.6Testing Discos for long-term accuracy, using automated optical character recognition.Baxter International
@@ -91,9 +91,6 @@
maven-javadoc-plugin3.4.1
-
- private
-
diff --git a/pom.xml b/pom.xml
index af94a17..9ba0377 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
4.0.0org.baxter.discoocr
- 4.3.5
+ 4.3.6jarDisco OCR Accuracy Over Life TestingTesting Discos for long-term accuracy, using automated optical character recognition.
@@ -47,7 +47,6 @@
javacv-platform${opencv.version}
-
org.openjfxjavafx-swing
@@ -91,13 +90,6 @@
pi4j-plugin-pigpio${pi4j.version}
-
-
-
@@ -184,30 +176,6 @@
-
@@ -216,9 +184,9 @@
org.apache.maven.pluginsmaven-javadoc-plugin3.4.1
-
+
diff --git a/src/main/java/org/baxter/disco/ocr/Cli.java b/src/main/java/org/baxter/disco/ocr/Cli.java
index 8012638..45c5181 100644
--- a/src/main/java/org/baxter/disco/ocr/Cli.java
+++ b/src/main/java/org/baxter/disco/ocr/Cli.java
@@ -18,14 +18,14 @@ import java.util.concurrent.locks.ReentrantLock;
* classes).
*
* @author Blizzard Finnegan
- * @version 1.7.0, 06 Mar. 2023
+ * @version 1.7.1, 10 Mar. 2023
*/
public class Cli
{
/**
* Complete build version number
*/
- private static final String version = "4.3.5";
+ private static final String version = "4.3.6";
/**
* Currently saved iteration count.
@@ -65,12 +65,10 @@ public class Cli
*/
public static final Lock LOCK = new ReentrantLock();
- //private static Thread safeThread;
- //Start of program message; always runs first
static
{
- ErrorLogging.logError("START OF PROGRAM");
+ ErrorLogging.logError("DEBUG: START OF PROGRAM");
}
public static void main(String[] args)
@@ -354,13 +352,10 @@ public class Cli
MovementFacade.iterationMovement(true);
double tesseractValue = 0.0;
- //Main camera config loop
do
{
- //Show the menu
printCameraMenu(cameraList);
- //Pick a camera to configure
int userInput;
String cameraName = "";
do
@@ -370,12 +365,10 @@ public class Cli
userInput--;
} while (cameraList.size() < userInput && userInput < 0);
- //Leave do-while loop if the user asks to
if(userInput == (cameraList.size())) break;
else if(userInput < 0) continue;
else cameraName = cameraList.get((userInput));
- //Single camera config loop
do
{
//Press button twice, to make sure the DUT is awake
@@ -384,17 +377,12 @@ public class Cli
MovementFacade.pressButton();
try{ Thread.sleep(2000); } catch(Exception e){ ErrorLogging.logError(e); }
- //Show image
File image = OpenCVFacade.showImage(cameraName);
-
- //Parse the image with Tesseract, to show user what the excel output will be
tesseractValue = TesseractFacade.imageToDouble(image);
- //User input parsing
ConfigProperties modifiedProperty = null;
do
{
- //list configurable settings
printCameraConfigMenu(cameraName,tesseractValue);
userInput = (int)inputFiltering(inputScanner.nextLine(),Menus.CAMERA);
@@ -422,7 +410,6 @@ public class Cli
}
} while(modifiedProperty == null);
- //Toggle threshold/crop
if(modifiedProperty == ConfigProperties.THRESHOLD ||
modifiedProperty == ConfigProperties.CROP)
{
@@ -431,11 +418,9 @@ public class Cli
ConfigFacade.setValue(cameraName,modifiedProperty,newValue);
}
- //Redefine crop points
else if(modifiedProperty == ConfigProperties.CROP_X)
{ OpenCVFacade.setCrop(cameraName); }
- //Modify number of composite frames, or threshold value
else if(modifiedProperty == ConfigProperties.COMPOSITE_FRAMES ||
modifiedProperty == ConfigProperties.THRESHOLD_VALUE)
{
@@ -447,7 +432,6 @@ public class Cli
ConfigFacade.setValue(cameraName,modifiedProperty,userInput);
}
- //Exit loop
else
{
ConfigFacade.saveCurrentConfig();
@@ -457,7 +441,6 @@ public class Cli
} while(true);
- //Save the current config to the config file
ConfigFacade.saveCurrentConfig();
println("Configuration complete!");
}
@@ -467,15 +450,11 @@ public class Cli
*/
private static void setDUTSerials()
{
- //Get a list of available cameras
List cameraList = new ArrayList<>(OpenCVFacade.getCameraNames());
- //Main serial setting loop
do
{
- //Main menu
printSerialMenu(cameraList);
- //Pick a camera to configure
int userInput;
String cameraName = "";
do
@@ -486,12 +465,9 @@ public class Cli
userInput--;
} while (cameraList.size() < userInput || userInput < 0);
- //Leave do-while loop if the user asks to
if(userInput == (cameraList.size())) break;
else cameraName = cameraList.get((userInput));
- //Save the serial number.
- //No parsing is ever done on this serial number.
prompt("Enter the serial number you wish to use for this camera: ");
ConfigFacade.setSerial(cameraName,inputScanner.nextLine());
@@ -518,16 +494,12 @@ public class Cli
*/
private static void setActiveCameras()
{
- //Get available cameras
List cameraList = new ArrayList<>(OpenCVFacade.getCameraNames());
- //Main loop
do
{
- //Print menu
printActiveToggleMenu(cameraList);
- //Pick a camera to configure
int userInput;
String cameraName = "";
do
@@ -537,11 +509,9 @@ public class Cli
userInput--;
} while (cameraList.size() < userInput || userInput < 0);
- //Leave do-while loop if the user asks to
if(userInput == (cameraList.size())) break;
else cameraName = cameraList.get((userInput));
- //Toggle whether the camera is active, at the config level
double newValue = ConfigFacade.getValue(cameraName,ConfigProperties.ACTIVE);
newValue = Math.abs(newValue - 1);
ConfigFacade.setValue(cameraName,ConfigProperties.ACTIVE,newValue);
@@ -561,22 +531,18 @@ public class Cli
//useful for multithreading, which isn't necessary in CLI
final int localIterations = iterationCount;
- //Save whether to prime the devices; defaults to false
+ //Hide legacy functionality
boolean prime = false;
- //Create a List of *active* cameras.
List cameraList = new ArrayList<>();
for(String cameraName : OpenCVFacade.getCameraNames())
{
prime = (ConfigFacade.getValue(cameraName,ConfigProperties.PRIME) != 0) || prime;
if(ConfigFacade.getValue(cameraName,ConfigProperties.ACTIVE) != 0)
- {
cameraList.add(cameraName);
- }
}
- //Initialise the workbook, with the number of cameras and the final output location
DataSaving.initWorkbook(ConfigFacade.getOutputSaveLocation(),cameraList.size());
//Wake the device, then wait to ensure they're awake before continuing
@@ -584,7 +550,6 @@ public class Cli
MovementFacade.pressButton();
try{ Thread.sleep(2000); } catch(Exception e){ ErrorLogging.logError(e); }
- //Create final maps for result images, result values, and camera names
Map resultMap = new HashMap<>();
Map cameraToFile = new HashMap<>();
@@ -595,7 +560,7 @@ public class Cli
}
ErrorLogging.logError("DEBUG: Starting tests...");
- //Start actually running tests
+
//All portions of the test check with the GPIO Run/Pause switch before
//continuing, using the Lock object.
for(int i = 0; i < localIterations; i++)
@@ -611,7 +576,6 @@ public class Cli
do
{
fail = false;
- //Move the fixture for one iteration, with whether or not the DUTs need to be primed
while(!LOCK.tryLock()) {}
MovementFacade.iterationMovement(prime);
LOCK.unlock();
@@ -619,9 +583,6 @@ public class Cli
//Wait for the DUT to display an image
try{ Thread.sleep(2000); } catch(Exception e){ ErrorLogging.logError(e); }
- //For all available cameras:
- // take an image, process it, and save it to a file
- // put that file into the camera name file Map
for(String cameraName : cameraList)
{
while(!LOCK.tryLock()) {}
@@ -633,9 +594,6 @@ public class Cli
LOCK.unlock();
}
- //ONCE ALL IMAGES ARE CREATED
- //Re-iterate over list of cameras, parse the images with Tesseract, then add
- //the parsed value to the map
for(String cameraName : cameraList)
{
while(!LOCK.tryLock()) {}
@@ -666,16 +624,13 @@ public class Cli
}
while(fail);
- //Write all given values to the Excel file
while(!LOCK.tryLock()) {}
DataSaving.writeValues(i,resultMap,cameraToFile);
LOCK.unlock();
- //Clear the result map
//DO NOT CLEAR camera to file Map. This will change the order of the objects within it
resultMap.clear();
}
- //Alert the user to testing being complete
println("=======================================");
println("Testing complete!");
}
diff --git a/src/main/java/org/baxter/disco/ocr/ConfigFacade.java b/src/main/java/org/baxter/disco/ocr/ConfigFacade.java
index 2a79741..5f2804d 100644
--- a/src/main/java/org/baxter/disco/ocr/ConfigFacade.java
+++ b/src/main/java/org/baxter/disco/ocr/ConfigFacade.java
@@ -24,7 +24,7 @@ import org.apache.commons.configuration2.builder.fluent.Parameters;
* Can write to file when requested, reads from file on initial start.
*
* @author Blizzard Finnegan
- * @version 1.3.1, 09 Feb. 2023
+ * @version 1.3.2, 10 Mar. 2023
*/
public class ConfigFacade
{
@@ -44,7 +44,7 @@ public class ConfigFacade
/**
* Location to save output XLSX file to.
*/
- public static String outputSaveLocation = "outputData/" +
+ private static String outputSaveLocation = "outputData/" +
(LocalDateTime.now().format(ErrorLogging.fileDatetime)) + ".xlsx";
/**
@@ -73,16 +73,14 @@ public class ConfigFacade
*/
private static INIConfiguration CONFIG_STORE;
- //This block will ALWAYS run first.
static
{
- //Get config values
ErrorLogging.logError("Starting configuration setup...");
- //Give CONFIG_STORE an intentionally bad value
CONFIG_STORE = null;
- //See if a config file already exists
+
File configFile = new File(configFileLocation);
boolean newConfig = true;
+
try{ newConfig = configFile.createNewFile(); }
catch(Exception e){ ErrorLogging.logError(e); }
@@ -90,7 +88,6 @@ public class ConfigFacade
CONFIG_BUILDER = new FileBasedConfigurationBuilder<>(INIConfiguration.class)
.configure(new Parameters().fileBased().setFile(configFile));
- //Try to import the config
ErrorLogging.logError("Attempting to import config...");
if(!newConfig)
{
@@ -111,8 +108,6 @@ public class ConfigFacade
}
}
- //If there isn't a config file yet (or rather, if we just made a new one)
- //save the default values to it
else
{
ErrorLogging.logError("Unable to import config. Loading defaults...");
@@ -121,24 +116,19 @@ public class ConfigFacade
else ErrorLogging.logError("Configuration settings set up!");
}
- //Make necessary directories, if not already available
ErrorLogging.logError("Creating image storage directories...");
File imageLocation = new File(imageSaveLocation);
imageLocation.mkdir();
- File debugImageLocation = new File(imageSaveLocation + "/debug");
- debugImageLocation.mkdir();
- File configImageLocation = new File(imageSaveLocation + "/config");
- configImageLocation.mkdir();
+ File setupImageLocation = new File(imageSaveLocation + "/config");
+ setupImageLocation.mkdir();
File outputFileDirectory = new File("outputData");
outputFileDirectory.mkdir();
- //Create a new output file
ErrorLogging.logError("Creating output file....");
File outputFile = new File(outputSaveLocation);
try{ outputFile.createNewFile(); }
catch(Exception e){ ErrorLogging.logError(e); }
- //Autosave the config
CONFIG_BUILDER.setAutoSave(true);
}
@@ -161,7 +151,6 @@ public class ConfigFacade
double output = 0.0;
if(!configMap.keySet().contains(cameraName))
{
- //Log failure information
ErrorLogging.logError("CONFIG ERROR!!! - Invalid camera name: " + cameraName);
ErrorLogging.logError("\tKey set: " + configMap.keySet().toString());
ErrorLogging.logError("\tProperty: " + property.getConfig());
@@ -170,9 +159,6 @@ public class ConfigFacade
}
Map cameraConfig = configMap.get(cameraName);
output = cameraConfig.get(property);
- //Debug logger.
- //ErrorLogging.logError("DEBUG: getValue - return value: " + cameraName
- // + "/" + property.getConfig() + " = " + output);
return output;
}
@@ -240,12 +226,16 @@ public class ConfigFacade
public static boolean setValue(String cameraName, ConfigProperties property, double propertyValue)
{
boolean output = false;
+
List activeCameras = new ArrayList<>(OpenCVFacade.getCameraNames());
if(!activeCameras.contains(cameraName)) return output;
+
Map cameraConfig = configMap.get(cameraName);
if(cameraConfig == null) return output;
+
Double oldValue = cameraConfig.get(property);
output = cameraConfig.replace(property,oldValue,propertyValue);
+
saveCurrentConfig();
return output;
}
@@ -288,21 +278,15 @@ public class ConfigFacade
*/
public static boolean saveDefaultConfig(String filename)
{
- //Get set of camera names
boolean output = false;
Set cameraNames = OpenCVFacade.getCameraNames();
- //Set the config builder to a file-based, INI configuration,
- //with the given filename
CONFIG_BUILDER = new FileBasedConfigurationBuilder<>(INIConfiguration.class)
.configure(new Parameters().fileBased()
.setFile(new File(filename)));
- //Set CONFIG_STORE to the Configuration created by the Builder
try { CONFIG_STORE = CONFIG_BUILDER.getConfiguration(); }
catch(Exception e) { ErrorLogging.logError(e); }
-
- //If the save default fails, warn the user that something is wrong
finally
{
if(CONFIG_STORE == null)
@@ -312,10 +296,6 @@ public class ConfigFacade
}
}
- //Iterate over every camera
- // Create a map of the default values
- // Save the default values to the CONFIG_STORE
- // save the map to the main config map
for(String camera : cameraNames)
{
Map cameraConfig = new HashMap<>();
@@ -324,14 +304,11 @@ public class ConfigFacade
String propertyName = camera + "." + property.getConfig();
double propertyValue = property.getDefaultValue();
cameraConfig.put(property,propertyValue);
- //ErrorLogging.logError("DEBUG: Attempting to save to config: ");
- //ErrorLogging.logError("DEBUG: " + propertyName + ", " + propertyValue);
CONFIG_STORE.setProperty(propertyName,propertyValue);
}
configMap.put(camera,cameraConfig);
}
- //Save out to the file
try
{
CONFIG_BUILDER.save();
@@ -442,7 +419,6 @@ public class ConfigFacade
for(ConfigProperties configState : ConfigProperties.values())
{
Double configValue = CONFIG_STORE.getDouble(sectionName + "." + configState.getConfig());
- //ErrorLogging.logError("DEBUG: Imported config value: " + Double.toString(configValue));
savedSection.put(configState,configValue);
}
}
@@ -456,7 +432,6 @@ public class ConfigFacade
{
for(String key : configMap.keySet())
{
- //ErrorLogging.logError("DEBUG: configMap Key: " + key + " ?= " + sectionName);
if( key.equals(sectionName))
{ configMap.put(key,savedSection); }
}
@@ -493,8 +468,6 @@ public class ConfigFacade
String propertyName = sectionName + "." + property.getConfig();
double propertyValue = property.getDefaultValue();
cameraConfig.put(property,propertyValue);
- //ErrorLogging.logError("DEBUG: Attempting to save to config: ");
- //ErrorLogging.logError("DEBUG: " + propertyName + ", " + propertyValue);
CONFIG_STORE.setProperty(propertyName,propertyValue);
}
configMap.put(sectionName,cameraConfig);
diff --git a/src/main/java/org/baxter/disco/ocr/DataSaving.java b/src/main/java/org/baxter/disco/ocr/DataSaving.java
index ba47b76..6a8fed1 100644
--- a/src/main/java/org/baxter/disco/ocr/DataSaving.java
+++ b/src/main/java/org/baxter/disco/ocr/DataSaving.java
@@ -1,10 +1,10 @@
package org.baxter.disco.ocr;
-import java.io.DataInputStream;
//Standard imports
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
+import java.io.DataInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
@@ -32,7 +32,7 @@ import static org.apache.poi.hssf.util.HSSFColor.HSSFColorPredefined;
* Facade for saving data out to a file.
*
* @author Blizzard Finnegan
- * @version 5.0.0, 07 Mar. 2023
+ * @version 5.0.1, 10 Mar. 2023
*/
public class DataSaving
{
@@ -99,16 +99,13 @@ public class DataSaving
//Create workbook, Sheet, and DataFormat object
//HSSF objects are used, as these are compatible with Microsoft Excel
- //XSSF objects were initially used, but caused issues.
outputWorkbook = new HSSFWorkbook();
outputSheet = outputWorkbook.createSheet();
format = outputWorkbook.createDataFormat();
- //Create a default style for values.
defaultStyle = outputWorkbook.createCellStyle();
defaultStyle.setDataFormat(format.getFormat("0.0"));
- //Create a style for the final percentage values
finalValuesStyle = outputWorkbook.createCellStyle();
finalValuesStyle.setDataFormat(format.getFormat("0.000%"));
@@ -124,19 +121,16 @@ public class DataSaving
failStyle.setDataFormat(format.getFormat("0.0"));
failStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
- //Create a style for error-ed, but not out-of-range, values
errorStyle = outputWorkbook.createCellStyle();
errorStyle.setFillForegroundColor(HSSFColorPredefined.YELLOW.getIndex());
errorStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
- //Create the header
int startingRow = outputSheet.getLastRowNum();
HSSFRow row = outputSheet.createRow(++startingRow);
int cellnum = 0;
HSSFCell cell = row.createCell(cellnum++);
cell.setCellValue("Iteration");
- //Create a section for every camera
for(int i = 0; i < camCount; i++)
{
cell = row.createCell(cellnum++);
@@ -153,7 +147,6 @@ public class DataSaving
HSSFCell passPercentCell = row.createCell(cellnum++);
passPercentCell.setCellValue("Pass %");
- //Save to file
try (FileOutputStream outputStream = new FileOutputStream(outputFile))
{ outputWorkbook.write(outputStream); }
catch(Exception e) {ErrorLogging.logError(e);}
@@ -175,10 +168,8 @@ public class DataSaving
int serialColumn = lastColumnOfData - 2;
int percentColumn = lastColumnOfData - 1;
- //Get the last row, add another row below it, and name the first cell "Totals:"
int lastRowOfData = outputSheet.getLastRowNum();
- //For each camera, create a unique total line
int column = 1;
for(int i = 0; i < cameraCount; i++)
{
@@ -219,7 +210,6 @@ public class DataSaving
column += 4;
}
- //Once all totals have been created, write to the file
try (FileOutputStream outputStream = new FileOutputStream(outputFile))
{ outputWorkbook.write(outputStream); }
catch(Exception e) {ErrorLogging.logError(e);}
@@ -238,10 +228,8 @@ public class DataSaving
boolean output = false;
int cellnum = 0;
int startingRow = outputSheet.getLastRowNum();
- HSSFRow row = (startingRow == 1) ? outputSheet.getRow(++startingRow) : outputSheet.createRow(++startingRow);
+ HSSFRow row = (cycle == 1) ? outputSheet.getRow(startingRow) : outputSheet.createRow(++startingRow);
List cameraNames = new ArrayList<>(cameraToFile.keySet());
- //ErrorLogging.logError("DEBUG: image locations: " + imageLocations.toString());
- //List