Output file fixes, version bump to 4.3.0 #7
11 changed files with 630 additions and 183 deletions
|
@ -4,7 +4,7 @@
|
|||
<groupId>org.baxter.disco</groupId>
|
||||
<artifactId>ocr</artifactId>
|
||||
<name>Disco OCR Accuracy Over Life Testing</name>
|
||||
<version>4.1.0</version>
|
||||
<version>4.2.0</version>
|
||||
<description>Testing Discos for long-term accuracy, using automated optical character recognition.</description>
|
||||
<organization>
|
||||
<name>Baxter International</name>
|
||||
|
@ -104,10 +104,11 @@
|
|||
<uitype>Cli</uitype>
|
||||
<target.platform.name>raspberry</target.platform.name>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
<opencv.version>1.5.6</opencv.version>
|
||||
<opencv.version>1.5.8</opencv.version>
|
||||
<poi.version>5.2.3</poi.version>
|
||||
<run.with.java.module>true</run.with.java.module>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<javafx.version>19</javafx.version>
|
||||
<junit.version>5.9.1</junit.version>
|
||||
<beanutils.version>1.9.4</beanutils.version>
|
||||
</properties>
|
||||
|
|
195
finalisedJavaUML.xmi
Normal file
195
finalisedJavaUML.xmi
Normal file
|
@ -0,0 +1,195 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<XMI xmi.version="1.2" timestamp="2023-02-10T15:42:51" verified="false" xmlns:UML="http://schema.omg.org/spec/UML/1.4">
|
||||
<XMI.header>
|
||||
<XMI.documentation>
|
||||
<XMI.exporter>umbrello uml modeller 2.32.3 http://umbrello.kde.org</XMI.exporter>
|
||||
<XMI.exporterVersion>1.7.3</XMI.exporterVersion>
|
||||
<XMI.exporterEncoding>UnicodeUTF8</XMI.exporterEncoding>
|
||||
</XMI.documentation>
|
||||
<XMI.metamodel xmi.name="UML" xmi.version="1.4" href="UML.xml"/>
|
||||
</XMI.header>
|
||||
<XMI.content>
|
||||
<UML:Model xmi.id="m1" name="UML Model" isSpecification="false" isAbstract="false" isRoot="false" isLeaf="false">
|
||||
<UML:Namespace.ownedElement>
|
||||
<UML:Stereotype isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="folder" name="folder" namespace="m1" visibility="public"/>
|
||||
<UML:Stereotype isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="enum" name="enum" namespace="m1" visibility="public"/>
|
||||
<UML:Model isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="Logical_View" name="Logical View" namespace="m1" visibility="public">
|
||||
<UML:Namespace.ownedElement>
|
||||
<UML:Package isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="Datatypes" name="Datatypes" namespace="Logical_View" visibility="public" stereotype="folder">
|
||||
<UML:Namespace.ownedElement>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uUqvKBDseGBT8" name="char" namespace="Datatypes" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uGrxjnu3NdGkS" name="int" namespace="Datatypes" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uVQA5vV2PfHS8" name="float" namespace="Datatypes" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uGEdyb7rYtJbR" name="double" namespace="Datatypes" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uPmQePzXPYBFw" name="boolean" namespace="Datatypes" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="ugB3shC3HW3bt" name="String" namespace="Datatypes" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uFrDHAwcuLu0K" name="unsigned char" namespace="Datatypes" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uOsZBNUExO74y" name="signed char" namespace="Datatypes" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="u2ffQSb9S8oCt" name="unsigned int" namespace="Datatypes" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uNj6ThaQPbIRF" name="signed int" namespace="Datatypes" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="ux7SnrmHLMP8A" name="short int" namespace="Datatypes" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uOP09e19M6XCK" name="unsigned short int" namespace="Datatypes" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="ueY965tY2Anss" name="signed short int" namespace="Datatypes" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uup0uQtaupJA2" name="long int" namespace="Datatypes" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uTyQLcjDfE5al" name="signed long int" namespace="Datatypes" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uVD8KLYSNJr6R" name="unsigned long int" namespace="Datatypes" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uFtz80V1i6e6W" name="long double" namespace="Datatypes" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="utoLI0CURUNlO" name="wchar_t" namespace="Datatypes" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="utYklzpE90p78" name="File" namespace="Datatypes" comment="java.io.File" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uPLfPTeiCHApE" name="List" namespace="Datatypes" comment="java.util.List" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uhxf4utUB9yw9" name="Map" namespace="Datatypes" comment="java.util.Map" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uip7MVxfAQJ07" name="Scanner" namespace="Datatypes" comment="java.util.Scanner" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="ut2HhRXRKmg9Q" name="Set" namespace="Datatypes" comment="java.util.Set" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uVQDGnttxJGvw" name="LocalDateTime" namespace="Datatypes" comment="java.time.LocalDateTime" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uQZkGcvvHmpdc" name="FileOutputStream" namespace="Datatypes" comment="java.io.FileOutputStream" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uIR2BbP8pwas8" name="Cell" namespace="Datatypes" comment="org.apache.poi.ss.usermodel.Cell" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uwIkaSubmJlRi" name="Row" namespace="Datatypes" comment="org.apache.poi.ss.usermodel.Row" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uzOpHYFIPuTBE" name="XSSFSheet" namespace="Datatypes" comment="org.apache.poi.xssf.usermodel.XSSFSheet Sheet of an XLSX workbook, in Java-object form" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uVULczmLK2Ekp" name="XSSFWorkbook" namespace="Datatypes" comment="org.apache.poi.xssf.usermodel.XSSFWorkbook XLSX Workbook, in Java-object form" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uTOcOSNHuXJyP" name="BufferedWriter" namespace="Datatypes" comment="java.io.BufferedWriter" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uzX3hHbj5KewD" name="PrintStream" namespace="Datatypes" comment="java.io.PrintStream" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uaMTlVo6ZPlbv" name="DateTimeFormatter" namespace="Datatypes" comment="java.time.format.DateTimeFormatter" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uaL98Rm7EKgtM" name="FileWriter" namespace="Datatypes" comment="java.io.FileWriter" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uBFg3i6c9CmfL" name="Pi4J" namespace="Datatypes" comment="com.pi4j.Pi4J Pi4J Context; used to create GPIO objects" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="ur90bbehes6KP" name="Context" namespace="Datatypes" comment="com.pi4j.context.Context Object used to communicate with the Pi4J API" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="usNbXCFOXZUb1" name="DigitalInput" namespace="Datatypes" comment="com.pi4j.io.gpio.digital.DigitalInput" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="u5nM17OoHAYAD" name="DigitalInputConfigBuilder" namespace="Datatypes" comment="com.pi4j.io.gpio.digital.DigitalInputConfigBuilder" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uCq1m7a90gZNi" name="DigitalOutput" namespace="Datatypes" comment="com.pi4j.io.gpio.digital.DigitalOutput" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uRF3RL0m1NpOT" name="DigitalOutputConfigBuilder" namespace="Datatypes" comment="com.pi4j.io.gpio.digital.DigitalOutputConfigBuilder" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uRCMbedZ3mPMC" name="DigitalState" namespace="Datatypes" comment="com.pi4j.io.gpio.digital.DigitalState" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="us7jxaKqWQIiW" name="PullResistance" namespace="Datatypes" comment="com.pi4j.io.gpio.digital.PullResistance" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uBZORGednrbEx" name="Pwm" namespace="Datatypes" comment="com.pi4j.iw.pwm.Pwm" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uCQrUPJPYCHCA" name="PwmConfigBuilder" namespace="Datatypes" comment="com.pi4j.io.pwm.PwmConfigBuilder" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="us3YZuRYzuxXn" name="PwmType" namespace="Datatypes" comment="com.pi4j.io.pwm.PwmType" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uBc3DEKv6xL0v" name="OpenCVFrameConverter.ToMat" namespace="Datatypes" comment="org.bytedeco.javacv.OpenCVFrameConverter.ToMat" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uSkySfC1PVbzu" name="Mat" namespace="Datatypes" comment="org.bytedeco.opencv.opencv_core.Mat" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uoaNTbxbl0bgu" name="FrameGrabber" namespace="Datatypes" comment="org.bytedeco.javacv.FrameGrabber An OpenCV-compatible camera object." visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uklvsQ2cKFH2p" name="Frame" namespace="Datatypes" comment="org.bytedeco.javacv.Frame" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uyHtw5cv74GVA" name="CanvasFrame" namespace="Datatypes" comment="org.bytedeco.javacv.CanvasFrame" visibility="public"/>
|
||||
<UML:DataType isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uFSRjsniasjt3" name="IplImage" namespace="Datatypes" comment="org.bytedeco.opencv.opencv_core.IplImage" visibility="public"/>
|
||||
</UML:Namespace.ownedElement>
|
||||
</UML:Package>
|
||||
<UML:Enumeration isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uvGD5ESq5Z2AT" name="ConfigProperties" namespace="Logical_View" comment="Enum of possible config properties. Due to limitations in Umbrello, each literal only shows their default values. Each literal also contains a human-readable name (retrievable by property.toString() ), or a config-readable name (retrievable by property.getConfig() ). These values are denoted in each literal's documentation. Retrieving the literal's default value is done by calling property.getDefaultValue()" visibility="public" stereotype="enum">
|
||||
<UML:Enumeration.literal>
|
||||
<UML:EnumerationLiteral isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="upEXxh4kZ64bG" name="CROP_X" namespace="uvGD5ESq5Z2AT" comment="X Coordinate of the top-left coordinate for the newly cropped image Human readable name: "Crop X" Config readable name: "cropX"" visibility="public" value="275"/>
|
||||
<UML:EnumerationLiteral isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="ufgfO1E5oazjm" name="CROP_Y" namespace="uvGD5ESq5Z2AT" comment="Y Coordinate of the top-left coordinate for the newly cropped image Human readable name: "Crop Y" Config readable name: "cropY"" visibility="public" value="205"/>
|
||||
<UML:EnumerationLiteral isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="ulLxfiM6RAmzB" name="CROP_W" namespace="uvGD5ESq5Z2AT" comment="Width of the newly cropped image Human readable name: "Crop Width" Config readable name: "cropW"" visibility="public" value="80"/>
|
||||
<UML:EnumerationLiteral isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="u9sxfmSblIz21" name="CROP_H" namespace="uvGD5ESq5Z2AT" comment="Height of the newly cropped image Human readable name: "Crop Height" Config readable name: "cropH"" visibility="public" value="50"/>
|
||||
<UML:EnumerationLiteral isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uMcIY87FH1xZg" name="THRESHOLD" namespace="uvGD5ESq5Z2AT" comment="pseudo-boolean to toggle whether an image should be thresholded during processing. Any value of this property that is not 0 will be considered TRUE, and the value 0 will be considered FALSE. Human-readable name: "Toggle threshold" Config-readable name: "threshold"" visibility="public" value="1"/>
|
||||
<UML:EnumerationLiteral isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="u2Fq8pGFKdO5a" name="CROP" namespace="uvGD5ESq5Z2AT" comment="pseudo-boolean to toggle whether an image should be cropped during processing. Any value of this property that is not 0 will be considered TRUE, and the value 0 will be considered FALSE. Human-readable name: "Toggle crop" Config-readable name: "crop"" visibility="public" value="1"/>
|
||||
<UML:EnumerationLiteral isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uOVDuobBco19d" name="COMPOSITE_FRAMES" namespace="uvGD5ESq5Z2AT" comment="The number of frames to composite together (using boolean ANDing) while processing this camera's images. Human-readable name: "Composite frame count" Config-readable name: "compositeCount"" visibility="public" value="5"/>
|
||||
<UML:EnumerationLiteral isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="uJgdnxP77NbVp" name="PRIME" namespace="uvGD5ESq5Z2AT" comment="Whether or not to prime the device under this camera, when under test. Human-readable name: "Prime device?" Config-readable name: "prime"" visibility="public" value="0"/>
|
||||
<UML:EnumerationLiteral isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="u2Zsi3jrcmEJ6" name="THRESHOLD_VALUE" namespace="uvGD5ESq5Z2AT" comment="Defines the cutoff point of the binary threshold. Human-readable name: "Threshold Value" Config-readable name: "thresholdValue"" visibility="public" value="45"/>
|
||||
<UML:EnumerationLiteral isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="umnsHXvMMFdeY" name="ACTIVE" namespace="uvGD5ESq5Z2AT" comment="Whether a camera should be used for the main test running. Human-readable name: "Camera active?" Config-readable name: "active"" visibility="public" value="1"/>
|
||||
</UML:Enumeration.literal>
|
||||
</UML:Enumeration>
|
||||
</UML:Namespace.ownedElement>
|
||||
<XMI.extension xmi.extender="umbrello">
|
||||
<diagrams resolution="96">
|
||||
<diagram xmi.id="uBO7PBkqnRCqe" name="class diagram" type="1" documentation="" backgroundcolor="#ffffff" fillcolor="#ffffc0" font="Noto Sans,10,-1,5,50,0,0,0,0,0,Regular" griddotcolor="#d3d3d3" linecolor="#990000" linewidth="0" textcolor="#000000" usefillcolor="1" showattribassocs="1" showatts="1" showattsig="1" showops="1" showopsig="1" showpackage="1" showpubliconly="0" showscope="1" showstereotype="2" localid="-1" showgrid="0" snapgrid="0" snapcsgrid="0" snapx="25" snapy="25" zoom="100" canvasheight="216" canvaswidth="160" isopen="1">
|
||||
<widgets>
|
||||
<enumwidget xmi.id="uvGD5ESq5Z2AT" localid="ukq9avhYimobQ" textcolor="#000000" linecolor="#990000" linewidth="0" usefillcolor="1" usesdiagramfillcolor="0" usesdiagramusefillcolor="0" fillcolor="#ffffc0" font="Noto Sans,10,-1,5,50,0,0,0,0,0,Regular" autoresize="1" x="-18" y="-66" width="160" height="216" isinstance="0" showstereotype="2" showpackage="1"/>
|
||||
</widgets>
|
||||
<messages/>
|
||||
<associations/>
|
||||
</diagram>
|
||||
</diagrams>
|
||||
</XMI.extension>
|
||||
</UML:Model>
|
||||
<UML:Model isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="Use_Case_View" name="Use Case View" namespace="m1" visibility="public">
|
||||
<UML:Namespace.ownedElement/>
|
||||
</UML:Model>
|
||||
<UML:Model isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="Component_View" name="Component View" namespace="m1" visibility="public">
|
||||
<UML:Namespace.ownedElement/>
|
||||
</UML:Model>
|
||||
<UML:Model isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="Deployment_View" name="Deployment View" namespace="m1" visibility="public">
|
||||
<UML:Namespace.ownedElement/>
|
||||
</UML:Model>
|
||||
<UML:Model isSpecification="false" isLeaf="false" isRoot="false" isAbstract="false" xmi.id="Entity_Relationship_Model" name="Entity Relationship Model" namespace="m1" visibility="public">
|
||||
<UML:Namespace.ownedElement/>
|
||||
</UML:Model>
|
||||
</UML:Namespace.ownedElement>
|
||||
</UML:Model>
|
||||
</XMI.content>
|
||||
<XMI.extensions xmi.extender="umbrello">
|
||||
<docsettings viewid="uBO7PBkqnRCqe" documentation="" uniqueid="uFSRjsniasjt3"/>
|
||||
<listview>
|
||||
<listitem id="Views" type="800" open="1">
|
||||
<listitem id="Component_View" type="821" open="1"/>
|
||||
<listitem id="Deployment_View" type="827" open="1"/>
|
||||
<listitem id="Entity_Relationship_Model" type="836" open="1"/>
|
||||
<listitem id="Logical_View" type="801" open="1">
|
||||
<listitem id="uBO7PBkqnRCqe" type="807" label="class diagram" open="0"/>
|
||||
<listitem id="uvGD5ESq5Z2AT" type="831" open="0">
|
||||
<listitem id="umnsHXvMMFdeY" type="839" open="0"/>
|
||||
<listitem id="uOVDuobBco19d" type="839" open="0"/>
|
||||
<listitem id="u2Fq8pGFKdO5a" type="839" open="0"/>
|
||||
<listitem id="u9sxfmSblIz21" type="839" open="0"/>
|
||||
<listitem id="ulLxfiM6RAmzB" type="839" open="0"/>
|
||||
<listitem id="upEXxh4kZ64bG" type="839" open="0"/>
|
||||
<listitem id="ufgfO1E5oazjm" type="839" open="0"/>
|
||||
<listitem id="uJgdnxP77NbVp" type="839" open="0"/>
|
||||
<listitem id="uMcIY87FH1xZg" type="839" open="0"/>
|
||||
<listitem id="u2Zsi3jrcmEJ6" type="839" open="0"/>
|
||||
</listitem>
|
||||
<listitem id="Datatypes" type="830" open="1">
|
||||
<listitem id="uPmQePzXPYBFw" type="829" open="0"/>
|
||||
<listitem id="uTOcOSNHuXJyP" type="829" open="1"/>
|
||||
<listitem id="uyHtw5cv74GVA" type="829" open="1"/>
|
||||
<listitem id="uIR2BbP8pwas8" type="829" open="1"/>
|
||||
<listitem id="uUqvKBDseGBT8" type="829" open="0"/>
|
||||
<listitem id="ur90bbehes6KP" type="829" open="1"/>
|
||||
<listitem id="uaMTlVo6ZPlbv" type="829" open="1"/>
|
||||
<listitem id="usNbXCFOXZUb1" type="829" open="1"/>
|
||||
<listitem id="u5nM17OoHAYAD" type="829" open="1"/>
|
||||
<listitem id="uCq1m7a90gZNi" type="829" open="1"/>
|
||||
<listitem id="uRF3RL0m1NpOT" type="829" open="1"/>
|
||||
<listitem id="uRCMbedZ3mPMC" type="829" open="1"/>
|
||||
<listitem id="uGEdyb7rYtJbR" type="829" open="0"/>
|
||||
<listitem id="utYklzpE90p78" type="829" open="1"/>
|
||||
<listitem id="uQZkGcvvHmpdc" type="829" open="1"/>
|
||||
<listitem id="uaL98Rm7EKgtM" type="829" open="1"/>
|
||||
<listitem id="uVQA5vV2PfHS8" type="829" open="0"/>
|
||||
<listitem id="uklvsQ2cKFH2p" type="829" open="1"/>
|
||||
<listitem id="uoaNTbxbl0bgu" type="829" open="1"/>
|
||||
<listitem id="uGrxjnu3NdGkS" type="829" open="0"/>
|
||||
<listitem id="uFSRjsniasjt3" type="829" open="1"/>
|
||||
<listitem id="uPLfPTeiCHApE" type="829" open="1"/>
|
||||
<listitem id="uVQDGnttxJGvw" type="829" open="1"/>
|
||||
<listitem id="uFtz80V1i6e6W" type="829" open="0"/>
|
||||
<listitem id="uup0uQtaupJA2" type="829" open="0"/>
|
||||
<listitem id="uhxf4utUB9yw9" type="829" open="1"/>
|
||||
<listitem id="uSkySfC1PVbzu" type="829" open="1"/>
|
||||
<listitem id="uBc3DEKv6xL0v" type="829" open="1"/>
|
||||
<listitem id="uBFg3i6c9CmfL" type="829" open="1"/>
|
||||
<listitem id="uzX3hHbj5KewD" type="829" open="1"/>
|
||||
<listitem id="us7jxaKqWQIiW" type="829" open="1"/>
|
||||
<listitem id="uBZORGednrbEx" type="829" open="1"/>
|
||||
<listitem id="uCQrUPJPYCHCA" type="829" open="1"/>
|
||||
<listitem id="us3YZuRYzuxXn" type="829" open="1"/>
|
||||
<listitem id="uwIkaSubmJlRi" type="829" open="1"/>
|
||||
<listitem id="uip7MVxfAQJ07" type="829" open="1"/>
|
||||
<listitem id="ut2HhRXRKmg9Q" type="829" open="1"/>
|
||||
<listitem id="ux7SnrmHLMP8A" type="829" open="0"/>
|
||||
<listitem id="uOsZBNUExO74y" type="829" open="0"/>
|
||||
<listitem id="uNj6ThaQPbIRF" type="829" open="0"/>
|
||||
<listitem id="uTyQLcjDfE5al" type="829" open="0"/>
|
||||
<listitem id="ueY965tY2Anss" type="829" open="0"/>
|
||||
<listitem id="ugB3shC3HW3bt" type="829" open="0"/>
|
||||
<listitem id="uFrDHAwcuLu0K" type="829" open="0"/>
|
||||
<listitem id="u2ffQSb9S8oCt" type="829" open="0"/>
|
||||
<listitem id="uVD8KLYSNJr6R" type="829" open="0"/>
|
||||
<listitem id="uOP09e19M6XCK" type="829" open="0"/>
|
||||
<listitem id="utoLI0CURUNlO" type="829" open="0"/>
|
||||
<listitem id="uzOpHYFIPuTBE" type="829" open="1"/>
|
||||
<listitem id="uVULczmLK2Ekp" type="829" open="1"/>
|
||||
</listitem>
|
||||
</listitem>
|
||||
<listitem id="Use_Case_View" type="802" open="1"/>
|
||||
</listitem>
|
||||
</listview>
|
||||
<codegeneration>
|
||||
<codegenerator language="C++"/>
|
||||
</codegeneration>
|
||||
</XMI.extensions>
|
||||
</XMI>
|
12
pom.xml
12
pom.xml
|
@ -3,7 +3,7 @@
|
|||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.baxter.disco</groupId>
|
||||
<artifactId>ocr</artifactId>
|
||||
<version>4.1.0</version>
|
||||
<version>4.3.0</version>
|
||||
<packaging>jar</packaging>
|
||||
<name>Disco OCR Accuracy Over Life Testing</name>
|
||||
<description>Testing Discos for long-term accuracy, using automated optical character recognition.</description>
|
||||
|
@ -25,10 +25,10 @@
|
|||
<jvmargs.debug></jvmargs.debug>
|
||||
|
||||
<pi4j.version>2.1.0</pi4j.version>
|
||||
<!--<javafx.version>19</javafx.version>-->
|
||||
<javafx.version>19</javafx.version>
|
||||
<poi.version>5.2.3</poi.version>
|
||||
<commons.version>2.8.0</commons.version>
|
||||
<opencv.version>1.5.6</opencv.version>
|
||||
<opencv.version>1.5.8</opencv.version>
|
||||
<junit.version>5.9.1</junit.version>
|
||||
<beanutils.version>1.9.4</beanutils.version>
|
||||
</properties>
|
||||
|
@ -47,6 +47,12 @@
|
|||
<artifactId>javacv-platform</artifactId>
|
||||
<version>${opencv.version}</version>
|
||||
</dependency>
|
||||
<!-- So... turns out, the showImage call requires JavaFX Swing, but doesn't actually *say* it requires that. -->
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-swing</artifactId>
|
||||
<version>${javafx.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Apache Commons Config Read/Write -->
|
||||
<dependency>
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
#! /usr/bin/env sh
|
||||
sudo java -jar discoTesting-4.1.0.jar 2>/dev/null
|
||||
sudo java -jar discoTesting-4.2.0.jar 2>/dev/null
|
||||
|
|
|
@ -5,10 +5,12 @@ module org.baxter.disco.ocr {
|
|||
requires com.pi4j.library.pigpio;
|
||||
//requires javafx.fxml;
|
||||
//requires javafx.controls;
|
||||
requires javafx.swing;
|
||||
requires org.apache.poi.poi;
|
||||
requires org.apache.commons.configuration2;
|
||||
requires org.apache.xmlbeans;
|
||||
requires org.bytedeco.tesseract;
|
||||
requires org.bytedeco.leptonica;
|
||||
requires org.bytedeco.opencv;
|
||||
requires org.bytedeco.javacpp;
|
||||
//requires javafx.graphics;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.baxter.disco.ocr;
|
||||
|
||||
//Standard imports
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
@ -24,8 +25,8 @@ public class Cli
|
|||
/**
|
||||
* Complete build version number
|
||||
*/
|
||||
private static final String version = "4.3.0";
|
||||
|
||||
private static final String version = "4.1.0";
|
||||
/**
|
||||
* Currently saved iteration count.
|
||||
*/
|
||||
|
@ -76,6 +77,7 @@ public class Cli
|
|||
|
||||
//private static Thread safeThread;
|
||||
|
||||
//Start of program message; always runs first
|
||||
static
|
||||
{
|
||||
ErrorLogging.logError("START OF PROGRAM");
|
||||
|
@ -83,49 +85,61 @@ public class Cli
|
|||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
//Beginning message to user
|
||||
ErrorLogging.logError("========================");
|
||||
ErrorLogging.logError("Accuracy Over Life Test");
|
||||
ErrorLogging.logError("Version: " + version);
|
||||
ErrorLogging.logError("========================");
|
||||
try{
|
||||
//Create scanner for user input from the console
|
||||
inputScanner = new Scanner(System.in);
|
||||
|
||||
//ErrorLogging.logError("DEBUG: Setting up multithreading...");
|
||||
//Initialise the fixture, start monitor thread
|
||||
fixture = new MovementFacade(LOCK);
|
||||
//ErrorLogging.logError("DEBUG: Multithreading complete!");
|
||||
|
||||
//ErrorLogging.logError("DEBUG: Importing config...");
|
||||
//Initialise the config
|
||||
ConfigFacade.init();
|
||||
//ErrorLogging.logError("DEBUG: Config imported!");
|
||||
|
||||
//Create the user input value
|
||||
int userInput = 0;
|
||||
|
||||
//Main menu loop
|
||||
do
|
||||
{
|
||||
//Show the main menu, wait for user input
|
||||
printMainMenu();
|
||||
userInput = inputFiltering(inputScanner.nextLine());
|
||||
|
||||
//Perform action based on user input
|
||||
switch (userInput)
|
||||
{
|
||||
case 1:
|
||||
//Test fixture movement, modify fixture values as necessary
|
||||
testMovement();
|
||||
break;
|
||||
case 2:
|
||||
//Warn user that starting cameras will take a moment.
|
||||
println("Setting up cameras...");
|
||||
println("This may take a moment...");
|
||||
configureCameras();
|
||||
//Set that cameras are successfully configured, to mute runTests warning
|
||||
camerasConfigured = true;
|
||||
break;
|
||||
case 3:
|
||||
//Set serials of the DUTs
|
||||
setDUTSerials();
|
||||
//serialsSet = true;
|
||||
break;
|
||||
case 4:
|
||||
//Change the number of iterations to run the tests
|
||||
setIterationCount();
|
||||
break;
|
||||
case 5:
|
||||
//Set cameras to use in testing
|
||||
setActiveCameras();
|
||||
break;
|
||||
case 6:
|
||||
//Warn user that cameras haven't been set up, if they haven't been set up
|
||||
//Won't warn user if config was imported successfully
|
||||
if(!camerasConfigured)
|
||||
{
|
||||
prompt("You have not configured the cameras yet! Are you sure you would like to continue? (y/N): ");
|
||||
|
@ -138,11 +152,14 @@ public class Cli
|
|||
{
|
||||
break;
|
||||
}
|
||||
//Save in the logs that cameras may not have been configured.
|
||||
else
|
||||
{
|
||||
ErrorLogging.logError("WARNING! - Potential for error: Un-initialised cameras.");
|
||||
}
|
||||
}
|
||||
|
||||
//If there's an unset camera serial, prompt the user to go back and set that up
|
||||
for(String cameraName : OpenCVFacade.getCameraNames())
|
||||
{
|
||||
if(ConfigFacade.getValue(cameraName,ConfigProperties.ACTIVE) != 0 &&
|
||||
|
@ -170,12 +187,16 @@ public class Cli
|
|||
ErrorLogging.logError("WARNING! - Potential for error: Un-initialised DUT Serial numbers.");
|
||||
}
|
||||
}
|
||||
|
||||
//Run tests for the given number of iterations
|
||||
runTests();
|
||||
break;
|
||||
case 7:
|
||||
//Show help menu
|
||||
printHelp();
|
||||
break;
|
||||
case 8:
|
||||
//Leave the menu
|
||||
break;
|
||||
default:
|
||||
//Input handling already done by inputFiltering()
|
||||
|
@ -184,11 +205,13 @@ public class Cli
|
|||
} while (userInput != mainMenuOptionCount);
|
||||
|
||||
}
|
||||
//If anything ever goes wrong, catch the error and exit
|
||||
catch(Exception e)
|
||||
{
|
||||
ErrorLogging.logError(e);
|
||||
ErrorLogging.logError("ERROR CAUGHT - CLOSING PROGRAM.");
|
||||
}
|
||||
//Always return the fixture back to the upper limit switch, close all open connections safely
|
||||
finally
|
||||
{
|
||||
close();
|
||||
|
@ -401,6 +424,7 @@ public class Cli
|
|||
private static void testMovement()
|
||||
{
|
||||
int userInput = -1;
|
||||
//Loop to allow multiple changes to device GPIO settings
|
||||
do
|
||||
{
|
||||
println("Testing movement...");
|
||||
|
@ -455,41 +479,19 @@ public class Cli
|
|||
private static void configureCameras()
|
||||
{
|
||||
List<String> cameraList = new ArrayList<>(OpenCVFacade.getCameraNames());
|
||||
//println(cameraList.toString());
|
||||
|
||||
// The below code should be unnecessary now. Leaving in for now to ensure things work properly.
|
||||
////Open a single new thread, so the canvas
|
||||
////used further down to display the temporary
|
||||
////image doesn't accidentally kill the program.
|
||||
////Created at beginning of function call to reduce
|
||||
////thread spawn count.
|
||||
////See also: https://docs.oracle.com/javase/8/docs/api/java/awt/doc-files/AWTThreadIssues.html#Autoshutdown
|
||||
//Runnable r = new Runnable() {
|
||||
// public void run() {
|
||||
// Object o = new Object();
|
||||
// try {
|
||||
// synchronized (o) {
|
||||
// o.wait();
|
||||
// }
|
||||
// } catch (InterruptedException ie) {
|
||||
// }
|
||||
// }
|
||||
//};
|
||||
//Thread t = new Thread(r);
|
||||
//t.setDaemon(false);
|
||||
//t.start();
|
||||
|
||||
//Always wake the camera, to ensure that the image is useful
|
||||
fixture.iterationMovement(true);
|
||||
double tesseractValue = 0.0;
|
||||
|
||||
//Main camera config loop
|
||||
do
|
||||
{
|
||||
//Main menu
|
||||
//Show the menu
|
||||
printCameraMenu(cameraList);
|
||||
|
||||
//Pick a camera to configure
|
||||
int userInput;
|
||||
|
||||
String cameraName = "";
|
||||
do
|
||||
{
|
||||
|
@ -503,13 +505,19 @@ public class Cli
|
|||
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
|
||||
fixture.pressButton();
|
||||
try{ Thread.sleep(2000); } catch(Exception e){ ErrorLogging.logError(e); }
|
||||
fixture.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
|
||||
|
@ -557,14 +565,16 @@ public class Cli
|
|||
else if(modifiedProperty == ConfigProperties.CROP_X)
|
||||
{ OpenCVFacade.setCrop(cameraName); }
|
||||
|
||||
//Modify config values
|
||||
else if(modifiedProperty != ConfigProperties.PRIME)
|
||||
//Modify number of composite frames, or threshold value
|
||||
else if(modifiedProperty == ConfigProperties.COMPOSITE_FRAMES ||
|
||||
modifiedProperty == ConfigProperties.THRESHOLD_VALUE)
|
||||
{
|
||||
prompt("Enter new value for this property (" + modifiedProperty.toString() + ", currently : " +
|
||||
prompt("Enter new value for this property (" + modifiedProperty.toString() + ": " +
|
||||
//Prompt is in int, as the ultimate values are cast
|
||||
//to int anyways, a decimal would be confusing
|
||||
(int)ConfigFacade.getValue(cameraName,modifiedProperty) + "): ");
|
||||
userInput = inputFiltering(inputScanner.nextLine());
|
||||
ConfigFacade.setValue(cameraName,modifiedProperty,userInput);
|
||||
//if(canvas != null) canvas.dispose();
|
||||
}
|
||||
|
||||
//Exit loop
|
||||
|
@ -573,6 +583,7 @@ public class Cli
|
|||
|
||||
} while(true);
|
||||
|
||||
//Save the current config to the config file
|
||||
ConfigFacade.saveCurrentConfig();
|
||||
println("Configuration complete!");
|
||||
}
|
||||
|
@ -582,7 +593,9 @@ public class Cli
|
|||
*/
|
||||
private static void setDUTSerials()
|
||||
{
|
||||
//Get a list of available cameras
|
||||
List<String> cameraList = new ArrayList<>(OpenCVFacade.getCameraNames());
|
||||
//Main serial setting loop
|
||||
do
|
||||
{
|
||||
//Main menu
|
||||
|
@ -590,12 +603,12 @@ public class Cli
|
|||
|
||||
//Pick a camera to configure
|
||||
int userInput;
|
||||
|
||||
String cameraName = "";
|
||||
do
|
||||
{
|
||||
prompt("Enter the camera you wish to set the serial of: ");
|
||||
userInput = inputFiltering(inputScanner.nextLine());
|
||||
//Compensate for off-by-one errors
|
||||
userInput--;
|
||||
} while (cameraList.size() < userInput || userInput < 0);
|
||||
|
||||
|
@ -603,6 +616,8 @@ public class Cli
|
|||
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());
|
||||
|
||||
|
@ -629,15 +644,17 @@ public class Cli
|
|||
*/
|
||||
private static void setActiveCameras()
|
||||
{
|
||||
//Get available cameras
|
||||
List<String> cameraList = new ArrayList<>(OpenCVFacade.getCameraNames());
|
||||
|
||||
//Main loop
|
||||
do
|
||||
{
|
||||
//Main menu
|
||||
//Print menu
|
||||
printActiveToggleMenu(cameraList);
|
||||
|
||||
//Pick a camera to configure
|
||||
int userInput;
|
||||
|
||||
String cameraName = "";
|
||||
do
|
||||
{
|
||||
|
@ -650,6 +667,7 @@ public class Cli
|
|||
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);
|
||||
|
@ -664,10 +682,15 @@ public class Cli
|
|||
{
|
||||
println("====================================");
|
||||
ErrorLogging.logError("Initialising tests...");
|
||||
|
||||
//Bring the iteration count into the function as a final variable
|
||||
//useful for multithreading, which isn't necessary in CLI
|
||||
final int localIterations = iterationCount;
|
||||
//testingThread = new Thread(() ->
|
||||
//{
|
||||
|
||||
//TODO: Hard-coded value that needs fixing
|
||||
boolean prime = false;
|
||||
|
||||
//Create a List of *active* cameras.
|
||||
List<String> cameraList = new ArrayList<>();
|
||||
for(String cameraName : OpenCVFacade.getCameraNames())
|
||||
{
|
||||
|
@ -682,43 +705,67 @@ public class Cli
|
|||
cameraList.add(cameraName);
|
||||
}
|
||||
}
|
||||
|
||||
//Initialise the workbook, with the number of cameras and the final output location
|
||||
DataSaving.initWorkbook(ConfigFacade.getOutputSaveLocation(),cameraList.size());
|
||||
|
||||
//Do 2 dummy passes, to make completely sure that the devices are awake
|
||||
ErrorLogging.logError("DEBUG: Waking devices...");
|
||||
fixture.iterationMovement(prime);
|
||||
fixture.pressButton();
|
||||
fixture.iterationMovement(prime);
|
||||
ErrorLogging.logError("DEBUG: Starting tests...");
|
||||
|
||||
//Create final maps for result images, result values, and camera names
|
||||
Map<File,Double> resultMap = new HashMap<>();
|
||||
Map<String,File> cameraToFile = new HashMap<>();
|
||||
|
||||
//Initialise cameraToFile, so keys don't shuffle.
|
||||
for(String cameraName : cameraList)
|
||||
{
|
||||
cameraToFile.put(cameraName,new File("/dev/null"));
|
||||
}
|
||||
|
||||
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++)
|
||||
{
|
||||
println("");
|
||||
ErrorLogging.logError("====================================");
|
||||
ErrorLogging.logError("Starting iteration " + (i+1) + " of " + localIterations + "...");
|
||||
|
||||
//Move the fixture for one iteration, with whether or not the DUTs need to be primed
|
||||
while(!LOCK.tryLock()) {}
|
||||
fixture.iterationMovement(prime);
|
||||
LOCK.unlock();
|
||||
|
||||
//Wait for the DUT to display an image
|
||||
try{ Thread.sleep(1500); } 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()) {}
|
||||
File file = OpenCVFacade.completeProcess(cameraName);
|
||||
LOCK.unlock();
|
||||
|
||||
while(!LOCK.tryLock()) {}
|
||||
cameraToFile.replace(cameraName,file);
|
||||
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()) {}
|
||||
File file = cameraToFile.get(cameraName);
|
||||
LOCK.unlock();
|
||||
while(!LOCK.tryLock()) {}
|
||||
//ErrorLogging.logError("DEBUG: File passed to Tesseract: " + file.getAbsolutePath());
|
||||
Double result = TesseractFacade.imageToDouble(file);
|
||||
LOCK.unlock();
|
||||
while(!LOCK.tryLock()) {}
|
||||
|
@ -726,15 +773,19 @@ public class Cli
|
|||
ErrorLogging.logError("Tesseract final output: " + result);
|
||||
LOCK.unlock();
|
||||
}
|
||||
//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();
|
||||
}
|
||||
//Close the Excel workbook
|
||||
DataSaving.closeWorkbook(cameraList.size());
|
||||
//Alert the user to testing being complete
|
||||
println("=======================================");
|
||||
println("Testing complete!");
|
||||
//});
|
||||
//testingThread.start();
|
||||
}
|
||||
|
||||
|
||||
|
@ -875,7 +926,7 @@ public class Cli
|
|||
*/
|
||||
private static void invalidInput(String input)
|
||||
{
|
||||
ErrorLogging.logError("Invalid User Input!!! - Message to user: '" + input + "'");
|
||||
ErrorLogging.logError("DEBUG: Invalid User Input!!! - Message to user: '" + input + "'");
|
||||
println("");
|
||||
println("=================================================");
|
||||
println("Invalid input! - " + input);
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
package org.baxter.disco.ocr;
|
||||
|
||||
//Standard imports
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.configuration2.*;
|
||||
import org.apache.commons.configuration2.builder.*;
|
||||
import org.apache.commons.configuration2.builder.fluent.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
|
@ -16,6 +12,11 @@ import java.nio.file.Paths;
|
|||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
|
||||
//Apache Commons Configuration imports
|
||||
import org.apache.commons.configuration2.INIConfiguration;
|
||||
import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder;
|
||||
import org.apache.commons.configuration2.builder.fluent.Parameters;
|
||||
|
||||
/**
|
||||
* Facade for working with config files, using the Apache Commons
|
||||
* Configuration library.
|
||||
|
@ -72,10 +73,13 @@ public class ConfigFacade
|
|||
*/
|
||||
private static INIConfiguration CONFIG_STORE;
|
||||
|
||||
static
|
||||
//This block will ALWAYS run first.
|
||||
static
|
||||
{
|
||||
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(); }
|
||||
|
@ -85,6 +89,7 @@ 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)
|
||||
{
|
||||
|
@ -93,17 +98,29 @@ public class ConfigFacade
|
|||
finally
|
||||
{
|
||||
if(CONFIG_STORE == null)
|
||||
ErrorLogging.logError("CONFIG INIT ERROR!!! - Unsuccessful config initialisation. Camera commands will fail!");
|
||||
ErrorLogging.logError("CONFIG INIT ERROR!!! - Unsuccessful "+
|
||||
"config initialisation. Please delete the current config "+
|
||||
"file, then restart this program!");
|
||||
else
|
||||
{
|
||||
ErrorLogging.logError("Config successfully imported!");
|
||||
loadConfig();
|
||||
ErrorLogging.logError("Configuration settings loaded!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//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...");
|
||||
saveDefaultConfig();
|
||||
boolean saveSuccessful = saveDefaultConfig();
|
||||
if(!saveSuccessful) ErrorLogging.logError("Save config failed!!!");
|
||||
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();
|
||||
|
@ -114,21 +131,13 @@ public class ConfigFacade
|
|||
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); }
|
||||
if(newConfig)
|
||||
{
|
||||
boolean saveSuccessful = saveDefaultConfig();
|
||||
if(!saveSuccessful) ErrorLogging.logError("Save config failed!!!");
|
||||
else ErrorLogging.logError("Configuration settings set up!");
|
||||
}
|
||||
else
|
||||
{
|
||||
loadConfig();
|
||||
ErrorLogging.logError("Configuration settings loaded!");
|
||||
}
|
||||
|
||||
//Autosave the config
|
||||
CONFIG_BUILDER.setAutoSave(true);
|
||||
}
|
||||
/**
|
||||
|
@ -150,6 +159,7 @@ 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());
|
||||
|
@ -160,17 +170,15 @@ public class ConfigFacade
|
|||
output = cameraConfig.get(property);
|
||||
//Debug logger.
|
||||
//NOTE THAT THIS BREAKS TUI MENUS, AS OF ErrorLogging 1.1.0
|
||||
//ErrorLogging.logError("DEBUG: getValue - return value: " + cameraName + "/" + property.getConfig() + " = " + output);
|
||||
//ErrorLogging.logError("DEBUG: getValue - return value: " + cameraName
|
||||
// + "/" + property.getConfig() + " = " + output);
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialises local list of available cameras
|
||||
* Called to force early calling of the static block
|
||||
*/
|
||||
public static void init()
|
||||
{
|
||||
//ErrorLogging.logError("Starting import...");
|
||||
}
|
||||
public static void init() {}
|
||||
|
||||
/**
|
||||
* Getter for the location of the output XLSX file.
|
||||
|
@ -222,7 +230,6 @@ public class ConfigFacade
|
|||
|
||||
/**
|
||||
* Set a given config value.
|
||||
* DOES NOT SAVE VALUE TO FILE.
|
||||
*
|
||||
* @param cameraName Name of the camera
|
||||
* @param property name of the property
|
||||
|
@ -270,6 +277,7 @@ public class ConfigFacade
|
|||
//**********************************************
|
||||
//SAVE AND LOAD SETTINGS
|
||||
//**********************************************
|
||||
|
||||
/**
|
||||
* Save current config to a user-defined file location.
|
||||
*
|
||||
|
@ -278,15 +286,34 @@ public class ConfigFacade
|
|||
*/
|
||||
public static boolean saveDefaultConfig(String filename)
|
||||
{
|
||||
//Get set of camera names
|
||||
boolean output = false;
|
||||
Set<String> cameraNames = OpenCVFacade.getCameraNames();
|
||||
CONFIG_BUILDER = new FileBasedConfigurationBuilder<>(INIConfiguration.class).configure(new Parameters().fileBased().setFile(new File(filename)));
|
||||
try
|
||||
{
|
||||
CONFIG_STORE = CONFIG_BUILDER.getConfiguration();
|
||||
}
|
||||
|
||||
//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); }
|
||||
finally { if(CONFIG_STORE == null) ErrorLogging.logError("CONFIG INIT ERROR!!! - Unsuccessful config initialisation. Camera commands will fail!"); }
|
||||
|
||||
//If the save default fails, warn the user that something is wrong
|
||||
finally
|
||||
{
|
||||
if(CONFIG_STORE == null)
|
||||
{
|
||||
ErrorLogging.logError("CONFIG INIT ERROR!!! - Unsuccessful config initialisation. Camera commands will fail!");
|
||||
ErrorLogging.logError("CONFIG INIT ERROR!!! - Attempted file save point: "+ filename);
|
||||
}
|
||||
}
|
||||
|
||||
//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<ConfigProperties,Double> cameraConfig = new HashMap<>();
|
||||
|
@ -301,15 +328,14 @@ public class ConfigFacade
|
|||
}
|
||||
configMap.put(camera,cameraConfig);
|
||||
}
|
||||
|
||||
//Save out to the file
|
||||
try
|
||||
{
|
||||
CONFIG_BUILDER.save();
|
||||
output = true;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
ErrorLogging.logError(e);
|
||||
}
|
||||
catch(Exception e){ ErrorLogging.logError(e); }
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@ -319,7 +345,8 @@ public class ConfigFacade
|
|||
*
|
||||
* @return true if saved successfully, otherwise false
|
||||
*/
|
||||
public static boolean saveDefaultConfig() { return saveDefaultConfig(configFileLocation); }
|
||||
public static boolean saveDefaultConfig()
|
||||
{ return saveDefaultConfig(configFileLocation); }
|
||||
|
||||
/**
|
||||
* Save current config to a user-defined file location.
|
||||
|
@ -330,7 +357,12 @@ public class ConfigFacade
|
|||
public static boolean saveCurrentConfig(String filename)
|
||||
{
|
||||
boolean output = false;
|
||||
|
||||
//Get a list of all cameras
|
||||
List<String> activeCameras = new ArrayList<>(OpenCVFacade.getCameraNames());
|
||||
|
||||
//For every available camera
|
||||
// get every current property value, save it to the CONFIG_STORE
|
||||
for(String camera : activeCameras)
|
||||
{
|
||||
for(ConfigProperties property : ConfigProperties.values())
|
||||
|
@ -340,15 +372,14 @@ public class ConfigFacade
|
|||
CONFIG_STORE.setProperty(propertyName,propertyValue);
|
||||
}
|
||||
}
|
||||
|
||||
//Save to the file
|
||||
try
|
||||
{
|
||||
CONFIG_BUILDER.save();
|
||||
output = true;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
ErrorLogging.logError(e);
|
||||
}
|
||||
catch(Exception e) { ErrorLogging.logError(e); }
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@ -358,7 +389,8 @@ public class ConfigFacade
|
|||
*
|
||||
* @return true if saved successfully, otherwise false
|
||||
*/
|
||||
public static boolean saveCurrentConfig() { return saveCurrentConfig(configFileLocation); }
|
||||
public static boolean saveCurrentConfig()
|
||||
{ return saveCurrentConfig(configFileLocation); }
|
||||
|
||||
/**
|
||||
* Load config from a user-defined file location.
|
||||
|
@ -368,60 +400,55 @@ public class ConfigFacade
|
|||
*/
|
||||
public static boolean loadConfig(String filename)
|
||||
{
|
||||
//Check if the current configMap is empty
|
||||
boolean emptyMap = configMap.keySet().size() == 0;
|
||||
boolean output = false;
|
||||
|
||||
//If the config file we're trying to load from doesn't exist, failover to saving
|
||||
//the default values to a new file with that name
|
||||
File file = new File(filename);
|
||||
try
|
||||
{
|
||||
if(file.createNewFile())
|
||||
return saveDefaultConfig();
|
||||
}
|
||||
try{ if(file.createNewFile()) return saveDefaultConfig(); }
|
||||
catch(Exception e)
|
||||
{
|
||||
ErrorLogging.logError(e);
|
||||
return saveDefaultConfig();
|
||||
return saveDefaultConfig(filename);
|
||||
}
|
||||
|
||||
//At this point, the file should exist
|
||||
//Get a list of camera names
|
||||
List<String> cameraNames = new ArrayList<>(OpenCVFacade.getCameraNames());
|
||||
if(Files.isRegularFile(Path.of(file.toURI())))
|
||||
{
|
||||
//Import the config file into a Java object
|
||||
try
|
||||
{
|
||||
CONFIG_BUILDER = new FileBasedConfigurationBuilder<>(INIConfiguration.class).configure(new Parameters().fileBased().setFile(file));
|
||||
CONFIG_BUILDER = new FileBasedConfigurationBuilder<>(INIConfiguration.class)
|
||||
.configure(new Parameters().fileBased().setFile(file));
|
||||
CONFIG_STORE = CONFIG_BUILDER.getConfiguration();
|
||||
}
|
||||
catch(Exception e){ ErrorLogging.logError(e); }
|
||||
|
||||
//Iterate over the imported object, saving the file's config values to the map
|
||||
Set<String> configSections = CONFIG_STORE.getSections();
|
||||
//ErrorLogging.logError("DEBUG: imported sections - " + configSections.toString());
|
||||
//ErrorLogging.logError("DEBUG: empty map? : " + (configMap.keySet().size() == 0));
|
||||
//ErrorLogging.logError("DEBUG: imported section size - " + configSections.size());
|
||||
for(String sectionName : configSections)
|
||||
{
|
||||
Map<ConfigProperties,Double> savedSection = new HashMap<>();
|
||||
String subSectionPrefix = "";
|
||||
for(String cameraName : cameraNames)
|
||||
{
|
||||
if(cameraName == null)
|
||||
{
|
||||
ErrorLogging.logError("CONFIG LOAD ERROR!!! - Empty camera name.");
|
||||
continue;
|
||||
}
|
||||
else if(sectionName == null)
|
||||
{
|
||||
ErrorLogging.logError("CONFIG LOAD ERROR!!! - Invalid imported section name.");
|
||||
continue;
|
||||
}
|
||||
else if(sectionName.equals(cameraName))
|
||||
if(sectionName.equals(cameraName))
|
||||
{
|
||||
subSectionPrefix = cameraName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//If an imported section fails, fallback to saving the default values to
|
||||
//the given location
|
||||
if(subSectionPrefix.equals(""))
|
||||
{
|
||||
ErrorLogging.logError("CONFIG LOAD ERROR!!! - Failed import from file. Setting default config.");
|
||||
return saveDefaultConfig();
|
||||
return saveDefaultConfig(filename);
|
||||
}
|
||||
|
||||
for(ConfigProperties configState : ConfigProperties.values())
|
||||
|
@ -444,8 +471,8 @@ public class ConfigFacade
|
|||
output = true;
|
||||
}
|
||||
|
||||
//If something broke, complain
|
||||
if(!output) ErrorLogging.logError("CONFIG LOAD ERROR!!! - Invalid path.");
|
||||
else Cli.configImported();
|
||||
return output;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.baxter.disco.ocr;
|
||||
|
||||
//Standard imports
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.util.ArrayList;
|
||||
|
@ -7,27 +8,37 @@ import java.util.LinkedList;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
import org.apache.poi.xssf.usermodel.XSSFSheet;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
|
||||
//Generic spreadsheet imports
|
||||
import org.apache.poi.ss.util.CellReference;
|
||||
import org.apache.poi.ss.usermodel.DataFormat;
|
||||
import org.apache.poi.ss.usermodel.FillPatternType;
|
||||
import org.apache.poi.ss.usermodel.FormulaEvaluator;
|
||||
|
||||
//Excel-specific imports
|
||||
import org.apache.poi.hssf.usermodel.HSSFCell;
|
||||
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
import org.apache.poi.hssf.usermodel.HSSFRow;
|
||||
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
||||
import static org.apache.poi.hssf.util.HSSFColor.HSSFColorPredefined;
|
||||
|
||||
/**
|
||||
* Facade for saving data out to a file.
|
||||
*
|
||||
* @author Blizzard Finnegan
|
||||
* @version 3.0.0, 06 Feb. 2023
|
||||
* @version 4.0.1, 13 Feb. 2023
|
||||
*/
|
||||
public class DataSaving
|
||||
{
|
||||
/**
|
||||
* Workbook object; used for writing to the final XLSX file.
|
||||
*/
|
||||
private static XSSFWorkbook outputWorkbook;
|
||||
private static HSSFWorkbook outputWorkbook;
|
||||
/**
|
||||
* Object defining what sheet within the workbook we are working in.
|
||||
*/
|
||||
private static XSSFSheet outputSheet;
|
||||
private static HSSFSheet outputSheet;
|
||||
|
||||
/**
|
||||
* File representing the location of the final output file.
|
||||
|
@ -35,40 +46,166 @@ public class DataSaving
|
|||
private static File outputFile;
|
||||
|
||||
/**
|
||||
* Prepares writer to write to XLSX file.
|
||||
* Default target temperature
|
||||
*/
|
||||
private static double targetTemp = 36.0;
|
||||
|
||||
/**
|
||||
* Default range for a measurement to be considered a fail
|
||||
*/
|
||||
private static double failRange = 0.2;
|
||||
|
||||
/**
|
||||
* Style of cell if the measurement falls outside the fail range
|
||||
*/
|
||||
private static HSSFCellStyle failStyle;
|
||||
|
||||
/**
|
||||
* Style of cell if Tesseract can't read the image
|
||||
*/
|
||||
private static HSSFCellStyle errorStyle;
|
||||
|
||||
/**
|
||||
* Style of a default cell
|
||||
*/
|
||||
private static HSSFCellStyle defaultStyle;
|
||||
|
||||
/**
|
||||
* Style of the total cells (sets typing to %)
|
||||
*/
|
||||
private static HSSFCellStyle finalValuesStyle;
|
||||
|
||||
/**
|
||||
* Prepares writer to write to XLSX file, with default fail values.
|
||||
*/
|
||||
public static boolean initWorkbook(String filename, int camCount)
|
||||
{ return initWorkbook(filename, camCount, targetTemp, failRange); }
|
||||
|
||||
/**
|
||||
* Prepares writer to write to XLSX file, with custom fail values.
|
||||
*/
|
||||
public static boolean initWorkbook(String filename, int camCount, double targetTemp, double failRange)
|
||||
{
|
||||
DataSaving.targetTemp = targetTemp;
|
||||
DataSaving.failRange = failRange;
|
||||
boolean output = false;
|
||||
outputFile = new File(filename);
|
||||
try
|
||||
DataFormat format = null;
|
||||
|
||||
//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%"));
|
||||
|
||||
//Note on backgrounds:
|
||||
//Excel cells have a foreground and a background, allowing
|
||||
//for various patterned backgrounds.
|
||||
//To set a solid background, and NOT modify the font,
|
||||
//as below is shown, we need to set the foreground color.
|
||||
//As of POI 5.2.3, there is no defined fill type
|
||||
//SOLID_BACKGROUND or similar
|
||||
failStyle = outputWorkbook.createCellStyle();
|
||||
failStyle.setFillForegroundColor(HSSFColorPredefined.RED.getIndex());
|
||||
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++)
|
||||
{
|
||||
outputWorkbook = new XSSFWorkbook();
|
||||
outputSheet = outputWorkbook.createSheet();
|
||||
int startingRow = outputSheet.getLastRowNum();
|
||||
Row row = outputSheet.createRow(++startingRow);
|
||||
int cellnum = 0;
|
||||
Cell cell = row.createCell(cellnum++);
|
||||
cell.setCellValue("Iteration");
|
||||
for(int i = 0; i < camCount; i++)
|
||||
{
|
||||
cell = row.createCell(cellnum++);
|
||||
cell.setCellValue("Serial");
|
||||
cell = row.createCell(cellnum++);
|
||||
cell.setCellValue("Image Location");
|
||||
cell = row.createCell(cellnum++);
|
||||
cell.setCellValue("Read Value");
|
||||
cell = row.createCell(cellnum++);
|
||||
cell.setCellValue("");
|
||||
}
|
||||
FileOutputStream outputStream = new FileOutputStream(outputFile);
|
||||
outputWorkbook.write(outputStream);
|
||||
output = true;
|
||||
outputStream.close();
|
||||
cell = row.createCell(cellnum++);
|
||||
cell.setCellValue("Serial");
|
||||
cell = row.createCell(cellnum++);
|
||||
cell.setCellValue("Image Location");
|
||||
cell = row.createCell(cellnum++);
|
||||
cell.setCellValue("Read Value");
|
||||
cell = row.createCell(cellnum++);
|
||||
cell.setCellValue("");
|
||||
}
|
||||
catch(Exception e) { ErrorLogging.logError(e); }
|
||||
|
||||
//Save to file
|
||||
try (FileOutputStream outputStream = new FileOutputStream(outputFile))
|
||||
{ outputWorkbook.write(outputStream); }
|
||||
catch(Exception e) {ErrorLogging.logError(e);}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add final totals to the excel document.
|
||||
* Run at the end of testing.
|
||||
*
|
||||
* @param cameraCount The number of cameras that were used.
|
||||
*/
|
||||
public static void closeWorkbook(int cameraCount)
|
||||
{
|
||||
//Get the last row, add another row below it, and name the first cell "Totals:"
|
||||
int lastRowOfData = outputSheet.getLastRowNum();
|
||||
HSSFRow finalRow = outputSheet.createRow(++lastRowOfData);
|
||||
HSSFCell titleCell = finalRow.createCell(0);
|
||||
titleCell.setCellValue("Totals:");
|
||||
|
||||
//ErrorLogging.logError("DEBUG: 3 ?= " + (cameraCount*3));
|
||||
|
||||
//For each camera, create a unique total line
|
||||
for(int column = 3; column <= (cameraCount*3); column+=3)
|
||||
{
|
||||
//Create a cell in the right column
|
||||
HSSFCell cell = finalRow.createCell(column);
|
||||
FormulaEvaluator formulaEvaluator = outputWorkbook.getCreationHelper().createFormulaEvaluator();
|
||||
String columnName = CellReference.convertNumToColString(column);
|
||||
|
||||
//Intermediate variable to store the array of possible values
|
||||
//Dollar signs in use here indicate that if the cell is copied and pasted,
|
||||
//the same cells will be referenced
|
||||
String verticalArray = String.format("$%s$2:$%s$%s",columnName,columnName,lastRowOfData);
|
||||
ErrorLogging.logError("DEBUG: Vertical Array: " + verticalArray);
|
||||
|
||||
//Create the error formula, then set it as the cell's formula.
|
||||
String formula = String.format(
|
||||
"(COUNT(%s)-COUNTIF(%s,{\"<%s\",\">%s\"}))/(COUNT(%s))",
|
||||
verticalArray,
|
||||
verticalArray, (targetTemp - failRange), (targetTemp + failRange),
|
||||
verticalArray);
|
||||
cell.setCellFormula(formula);
|
||||
|
||||
//Make the percentage human-readable
|
||||
cell.setCellStyle(finalValuesStyle);
|
||||
|
||||
//To make the cell be a readable value, you need to
|
||||
//evaluate the formula within the cell.
|
||||
formulaEvaluator.evaluate(cell);
|
||||
|
||||
ErrorLogging.logError("DEBUG: Formula: " + formula);
|
||||
}
|
||||
|
||||
//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);}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes line to XLSX file.
|
||||
*
|
||||
|
@ -80,14 +217,17 @@ public class DataSaving
|
|||
public static boolean writeValues(int cycle, Map<File,Double> inputMap, Map<String,File> cameraToFile)
|
||||
{
|
||||
boolean output = false;
|
||||
int cellnum = 0;
|
||||
int startingRow = outputSheet.getLastRowNum();
|
||||
Row row = outputSheet.createRow(++startingRow);
|
||||
HSSFRow row = outputSheet.createRow(++startingRow);
|
||||
List<String> cameraNames = new ArrayList<>(cameraToFile.keySet());
|
||||
//ErrorLogging.logError("DEBUG: image locations: " + imageLocations.toString());
|
||||
List<Object> objectArray = new LinkedList<>();
|
||||
|
||||
cycle++;
|
||||
objectArray.add((double)cycle);
|
||||
|
||||
HSSFCell indexCell = row.createCell(cellnum++);
|
||||
indexCell.setCellValue(cycle);
|
||||
for(String cameraName : cameraNames)
|
||||
{
|
||||
File file = cameraToFile.get(cameraName);
|
||||
|
@ -99,16 +239,28 @@ public class DataSaving
|
|||
objectArray.add(inputMap.get(file));
|
||||
objectArray.add(" ");
|
||||
}
|
||||
int cellnum = 0;
|
||||
for(Object cellObject : objectArray)
|
||||
{
|
||||
Cell cell = row.createCell(cellnum++);
|
||||
HSSFCell cell = row.createCell(cellnum++);
|
||||
if(cellObject instanceof Double)
|
||||
{
|
||||
Double cellValue = (Double)cellObject;
|
||||
ErrorLogging.logError("DEBUG: " + cellValue + " ?= " + targetTemp + " +- " + failRange);
|
||||
if(cellValue.equals(Double.NEGATIVE_INFINITY))
|
||||
{
|
||||
cell.setCellValue("ERROR!");
|
||||
else cell.setCellValue(cellValue);
|
||||
cell.setCellStyle(errorStyle);
|
||||
}
|
||||
else
|
||||
{
|
||||
cell.setCellValue(cellValue);
|
||||
if( cellValue.doubleValue() > (targetTemp + failRange) ||
|
||||
cellValue.doubleValue() < (targetTemp - failRange) )
|
||||
{
|
||||
ErrorLogging.logError("DEBUG: Cell value " + cellValue.doubleValue() + " is outside the allowed range! (" + (targetTemp -failRange) + "-" + (targetTemp + failRange) + "). Setting cell to fail colouring.");
|
||||
cell.setCellStyle(failStyle);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(cellObject instanceof String) cell.setCellValue((String) cellObject);
|
||||
else
|
||||
|
@ -118,13 +270,8 @@ public class DataSaving
|
|||
}
|
||||
|
||||
}
|
||||
try
|
||||
{
|
||||
FileOutputStream outputStream = new FileOutputStream(outputFile);
|
||||
outputWorkbook.write(outputStream);
|
||||
output = true;
|
||||
outputStream.close();
|
||||
}
|
||||
try (FileOutputStream outputStream = new FileOutputStream(outputFile))
|
||||
{ outputWorkbook.write(outputStream); output = true; }
|
||||
catch(Exception e) {ErrorLogging.logError(e);}
|
||||
return output;
|
||||
}
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
package org.baxter.disco.ocr;
|
||||
|
||||
//Standard imports
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
//Error parsing import
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
|
||||
/**
|
||||
|
@ -54,10 +55,16 @@ public class ErrorLogging
|
|||
*/
|
||||
public static final DateTimeFormatter fileDatetime;
|
||||
|
||||
//This will always run first, before anything else in this file
|
||||
static
|
||||
{
|
||||
//Make sure the filename formatter is compatible with Windows and Linux
|
||||
fileDatetime = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH.mm.ss");
|
||||
|
||||
//Local formatter for logs
|
||||
datetime = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
|
||||
|
||||
//Create a new log file on every run; put them all in a common folder
|
||||
logFile = "logs/" + fileDatetime.format(LocalDateTime.now()) + "-log.txt";
|
||||
File logDirectory = new File("logs");
|
||||
File outFile = new File(logFile);
|
||||
|
@ -70,7 +77,7 @@ public class ErrorLogging
|
|||
fileOut = new PrintWriter(bw);
|
||||
System.setErr(new PrintStream(new FileOutputStream(logFile,true)));
|
||||
}
|
||||
catch (IOException e)
|
||||
catch (Exception e)
|
||||
{
|
||||
System.err.println(e);
|
||||
}
|
||||
|
@ -125,7 +132,7 @@ public class ErrorLogging
|
|||
if(bw != null) bw.close();
|
||||
if(fw != null) fw.close();
|
||||
}
|
||||
catch(IOException e)
|
||||
catch(Exception e)
|
||||
{ /* This is being run because the program is closing. Errors here don't matter. */}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,13 +3,23 @@ package org.baxter.disco.ocr;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.bytedeco.opencv.global.opencv_imgproc.*;
|
||||
import static org.bytedeco.opencv.global.opencv_imgcodecs.*;
|
||||
import static org.bytedeco.opencv.global.opencv_highgui.*;
|
||||
import static org.bytedeco.opencv.global.opencv_core.*;
|
||||
import static org.bytedeco.opencv.global.opencv_imgproc.CV_BGR2GRAY;
|
||||
import static org.bytedeco.opencv.global.opencv_imgproc.THRESH_BINARY;
|
||||
import static org.bytedeco.opencv.global.opencv_imgproc.cvtColor;
|
||||
import static org.bytedeco.opencv.global.opencv_imgproc.threshold;
|
||||
import static org.bytedeco.opencv.global.opencv_imgcodecs.imread;
|
||||
import static org.bytedeco.opencv.global.opencv_imgcodecs.cvSaveImage;
|
||||
import static org.bytedeco.opencv.global.opencv_highgui.selectROI;
|
||||
import static org.bytedeco.opencv.global.opencv_core.bitwise_and;
|
||||
|
||||
import org.bytedeco.javacv.*;
|
||||
import org.bytedeco.opencv.opencv_core.*;
|
||||
import org.bytedeco.javacv.Frame;
|
||||
import org.bytedeco.javacv.CanvasFrame;
|
||||
import org.bytedeco.javacv.FrameGrabber;
|
||||
import org.bytedeco.javacv.OpenCVFrameGrabber;
|
||||
import org.bytedeco.javacv.OpenCVFrameConverter;
|
||||
import org.bytedeco.opencv.opencv_core.Mat;
|
||||
import org.bytedeco.opencv.opencv_core.IplImage;
|
||||
import org.bytedeco.opencv.opencv_core.Rect;
|
||||
|
||||
import java.io.File;
|
||||
import java.time.LocalDateTime;
|
||||
|
@ -21,9 +31,9 @@ import java.util.List;
|
|||
/**
|
||||
* Facade for the OpenCV package.
|
||||
* Performs image capture, as well as image manipulation.
|
||||
*
|
||||
*
|
||||
* @author Blizzard Finnegan
|
||||
* @version 1.5.0, 10 Feb. 2023
|
||||
* @version 2.0.0, 15 Feb. 2023
|
||||
*/
|
||||
public class OpenCVFacade
|
||||
{
|
||||
|
@ -185,7 +195,7 @@ public class OpenCVFacade
|
|||
//ErrorLogging.logError("DEBUG: Image location: " + imageLocation.getAbsolutePath());
|
||||
Frame outputImage = MAT_CONVERTER.convert(imread(imageLocation.getAbsolutePath()));
|
||||
String canvasTitle = "Camera " + cameraName + " Preview";
|
||||
CanvasFrame canvas = new CanvasFrame(canvasTitle);
|
||||
final CanvasFrame canvas = new CanvasFrame(canvasTitle);
|
||||
canvas.showImage(outputImage);
|
||||
return imageLocation;
|
||||
}
|
||||
|
@ -270,16 +280,17 @@ public class OpenCVFacade
|
|||
*/
|
||||
public static Mat crop(Mat image, Rect roi, String cameraName)
|
||||
{
|
||||
Mat output = null;
|
||||
output = image.apply(roi);
|
||||
String fileLocation = ConfigFacade.getImgSaveLocation() + "/debug/"
|
||||
+ ErrorLogging.fileDatetime.format(LocalDateTime.now()) +
|
||||
"." + cameraName + "-preProcess.jpg";
|
||||
cvSaveImage(fileLocation,MAT_CONVERTER.convertToIplImage(
|
||||
MAT_CONVERTER.convert(output)));
|
||||
Mat output = image.apply(roi).clone();
|
||||
//IplImage croppedImage = MAT_CONVERTER.convertToIplImage(MAT_CONVERTER.convert(output));
|
||||
//String fileLocation = ConfigFacade.getImgSaveLocation() + "/debug/"
|
||||
// + ErrorLogging.fileDatetime.format(LocalDateTime.now()) +
|
||||
// "." + cameraName + "-preProcess.jpg";
|
||||
//cvSaveImage(fileLocation,croppedImage);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Put the given image through a binary threshold.
|
||||
* This reduces the image from greyscale to only pure white and black pixels.
|
||||
|
|
|
@ -3,8 +3,8 @@ package org.baxter.disco.ocr;
|
|||
import java.io.File;
|
||||
import java.util.Scanner;
|
||||
|
||||
import org.bytedeco.leptonica.*;
|
||||
import org.bytedeco.leptonica.global.*;
|
||||
import org.bytedeco.leptonica.PIX;
|
||||
import static org.bytedeco.leptonica.global.leptonica.pixRead;
|
||||
import org.bytedeco.tesseract.TessBaseAPI;
|
||||
|
||||
/**
|
||||
|
@ -14,7 +14,7 @@ import org.bytedeco.tesseract.TessBaseAPI;
|
|||
* information for this specific testing aparatus.
|
||||
*
|
||||
* @author Blizzard Finnegan
|
||||
* @version 2.0.0, 06 Feb. 2023
|
||||
* @version 2.1.0, 06 Feb. 2023
|
||||
*/
|
||||
public class TesseractFacade
|
||||
{
|
||||
|
@ -53,7 +53,7 @@ public class TesseractFacade
|
|||
double output = Double.NEGATIVE_INFINITY;
|
||||
|
||||
//Import image, parse image
|
||||
PIX importedImage = lept.pixRead(file.getAbsolutePath());
|
||||
PIX importedImage = pixRead(file.getAbsolutePath());
|
||||
api.SetImage(importedImage);
|
||||
String stringOutput = api.GetUTF8Text().getString();
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue