Overhaul cropping #5

Merged
blizzardfinnegan merged 2 commits from devel into stable 2023-02-10 10:33:07 -05:00
8 changed files with 97 additions and 70 deletions

View file

@ -20,6 +20,10 @@ This is a personal/professional project, which makes use of JavaCV, OpenCV, Tess
- [x] modify number of iterations for test suite - [x] modify number of iterations for test suite
- [ ] JavaFX GUI (see `gui` branch) - [ ] JavaFX GUI (see `gui` branch)
## Known Bugs
- As of v4.1.0, cropping images is done by a temporary window created by OpenCV. This window will crash after being used correctly. This can be safely killed when prompted, without affecting the rest of the project. Investigation into how to fix this crashing is ongoing, but it has not yet been resolved.
## Dependencies ## Dependencies
To install this project, you must have the following: To install this project, you must have the following:

View file

@ -4,7 +4,7 @@
<groupId>org.baxter.disco</groupId> <groupId>org.baxter.disco</groupId>
<artifactId>ocr</artifactId> <artifactId>ocr</artifactId>
<name>Disco OCR Accuracy Over Life Testing</name> <name>Disco OCR Accuracy Over Life Testing</name>
<version>4.0.0</version> <version>4.1.0</version>
<description>Testing Discos for long-term accuracy, using automated optical character recognition.</description> <description>Testing Discos for long-term accuracy, using automated optical character recognition.</description>
<organization> <organization>
<name>Baxter International</name> <name>Baxter International</name>
@ -108,7 +108,6 @@
<poi.version>5.2.3</poi.version> <poi.version>5.2.3</poi.version>
<run.with.java.module>true</run.with.java.module> <run.with.java.module>true</run.with.java.module>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<javafx.version>19</javafx.version>
<junit.version>5.9.1</junit.version> <junit.version>5.9.1</junit.version>
<beanutils.version>1.9.4</beanutils.version> <beanutils.version>1.9.4</beanutils.version>
</properties> </properties>

View file

@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>org.baxter.disco</groupId> <groupId>org.baxter.disco</groupId>
<artifactId>ocr</artifactId> <artifactId>ocr</artifactId>
<version>4.0.1</version> <version>4.1.0</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>Disco OCR Accuracy Over Life Testing</name> <name>Disco OCR Accuracy Over Life Testing</name>
<description>Testing Discos for long-term accuracy, using automated optical character recognition.</description> <description>Testing Discos for long-term accuracy, using automated optical character recognition.</description>
@ -25,7 +25,7 @@
<jvmargs.debug></jvmargs.debug> <jvmargs.debug></jvmargs.debug>
<pi4j.version>2.1.0</pi4j.version> <pi4j.version>2.1.0</pi4j.version>
<javafx.version>19</javafx.version> <!--<javafx.version>19</javafx.version>-->
<poi.version>5.2.3</poi.version> <poi.version>5.2.3</poi.version>
<commons.version>2.8.0</commons.version> <commons.version>2.8.0</commons.version>
<opencv.version>1.5.6</opencv.version> <opencv.version>1.5.6</opencv.version>

View file

@ -1,2 +1,2 @@
#! /usr/bin/env sh #! /usr/bin/env sh
sudo java -jar discoTesting-4.0.0-rc3.jar sudo java -jar discoTesting-4.1.0.jar 2>/dev/null

View file

@ -18,7 +18,7 @@ module org.baxter.disco.ocr {
requires org.apache.commons.lang3; requires org.apache.commons.lang3;
requires org.bytedeco.javacv.platform; requires org.bytedeco.javacv.platform;
requires java.desktop; //requires java.desktop;
uses com.pi4j.extension.Extension; uses com.pi4j.extension.Extension;
uses com.pi4j.provider.Provider; uses com.pi4j.provider.Provider;

View file

@ -17,7 +17,7 @@ import java.util.concurrent.locks.ReentrantLock;
* classes). * classes).
* *
* @author Blizzard Finnegan * @author Blizzard Finnegan
* @version 1.4.1, 09 Feb. 2023 * @version 1.5.0, 10 Feb. 2023
*/ */
public class Cli public class Cli
{ {
@ -25,7 +25,7 @@ public class Cli
* Complete build version number * Complete build version number
*/ */
private static final String version = "4.0.0"; private static final String version = "4.1.0";
/** /**
* Currently saved iteration count. * Currently saved iteration count.
*/ */
@ -239,7 +239,9 @@ public class Cli
"\n\tfor use in OCR. Can modify"+ "\n\tfor use in OCR. Can modify"+
"\n\tconfig file, if requested." + "\n\tconfig file, if requested." +
"\n\tAvailable variables to change:"+ "\n\tAvailable variables to change:"+
"\n\t\tCrop dimensions"); "\n\t\tCrop dimensions"+
"\n\t\tComposite frame count"+
"\n\t\tThreshold value");
println("----------------------------------------"); println("----------------------------------------");
println("3. Set serial numbers: Set the serial " + println("3. Set serial numbers: Set the serial " +
"\n\tnumber for the device under test." + "\n\tnumber for the device under test." +
@ -373,17 +375,6 @@ public class Cli
println("===================================="); println("====================================");
println("Camera Config Menu:"); println("Camera Config Menu:");
println("------------------------------------"); println("------------------------------------");
println("Current Crop values: ");
println("************************************");
print("X: " + ConfigFacade.getValue(cameraName,
ConfigProperties.CROP_X));
print(" | Y: " + ConfigFacade.getValue(cameraName,
ConfigProperties.CROP_Y));
print(" | Width: " + ConfigFacade.getValue(cameraName,
ConfigProperties.CROP_W));
println(" | Height: " + ConfigFacade.getValue(cameraName,
ConfigProperties.CROP_H));
println("************************************");
println("Current composite frame count: " + println("Current composite frame count: " +
ConfigFacade.getValue(cameraName,ConfigProperties.COMPOSITE_FRAMES)); ConfigFacade.getValue(cameraName,ConfigProperties.COMPOSITE_FRAMES));
println("Current threshold value: " + println("Current threshold value: " +
@ -392,20 +383,14 @@ public class Cli
println("Will the image be cropped? " + cropValue); println("Will the image be cropped? " + cropValue);
String thresholdImage = ((ConfigFacade.getValue(cameraName,ConfigProperties.THRESHOLD) != 0) ? "yes" : "no"); String thresholdImage = ((ConfigFacade.getValue(cameraName,ConfigProperties.THRESHOLD) != 0) ? "yes" : "no");
println("Will the image be thresholded? " + thresholdImage); println("Will the image be thresholded? " + thresholdImage);
String cameraActive = ((ConfigFacade.getValue(cameraName,ConfigProperties.ACTIVE) != 0) ? "yes" : "no");
println("Will the camera be used when running tests? " + cameraActive);
println("Tesseract parsed value for camera " + cameraName + ": " + tesseractValue); println("Tesseract parsed value for camera " + cameraName + ": " + tesseractValue);
println("------------------------------------"); println("------------------------------------");
println("1. Change Crop X"); println("1. Change Crop Point");
println("2. Change Crop Y"); println("2. Change Composite Frame Count");
println("3. Change Crop Width"); println("3. Change Threshold Value");
println("4. Change Crop Height"); println("4. Toggle crop");
println("5. Change Composite Frame Count"); println("5. Toggle threshold");
println("6. Change Threshold Value"); println("6. Exit");
println("7. Toggle crop");
println("8. Toggle threshold");
println("9. Toggle camera");
println("10. Exit");
println("===================================="); println("====================================");
} }
@ -541,53 +526,48 @@ public class Cli
modifiedProperty = ConfigProperties.CROP_X; modifiedProperty = ConfigProperties.CROP_X;
break; break;
case 2: case 2:
modifiedProperty = ConfigProperties.CROP_Y;
break;
case 3:
modifiedProperty = ConfigProperties.CROP_W;
break;
case 4:
modifiedProperty = ConfigProperties.CROP_H;
break;
case 5:
modifiedProperty = ConfigProperties.COMPOSITE_FRAMES; modifiedProperty = ConfigProperties.COMPOSITE_FRAMES;
break; break;
case 6: case 3:
modifiedProperty = ConfigProperties.THRESHOLD_VALUE; modifiedProperty = ConfigProperties.THRESHOLD_VALUE;
break; break;
case 7: case 4:
modifiedProperty = ConfigProperties.CROP; modifiedProperty = ConfigProperties.CROP;
break; break;
case 8: case 5:
modifiedProperty = ConfigProperties.THRESHOLD; modifiedProperty = ConfigProperties.THRESHOLD;
break; break;
case 9: case 6:
modifiedProperty = ConfigProperties.ACTIVE;
break;
case 0:
case 10:
modifiedProperty = ConfigProperties.PRIME; modifiedProperty = ConfigProperties.PRIME;
break; break;
default: default:
} }
} while(modifiedProperty == null); } while(modifiedProperty == null);
//Toggle threshold/crop
if(modifiedProperty == ConfigProperties.THRESHOLD || if(modifiedProperty == ConfigProperties.THRESHOLD ||
modifiedProperty == ConfigProperties.CROP || modifiedProperty == ConfigProperties.CROP)
modifiedProperty == ConfigProperties.ACTIVE)
{ {
double newValue = ConfigFacade.getValue(cameraName,modifiedProperty); double newValue = ConfigFacade.getValue(cameraName,modifiedProperty);
newValue = Math.abs(newValue - 1); newValue = Math.abs(newValue - 1);
ConfigFacade.setValue(cameraName,modifiedProperty,newValue); ConfigFacade.setValue(cameraName,modifiedProperty,newValue);
} }
//Redefine crop points
else if(modifiedProperty == ConfigProperties.CROP_X)
{ OpenCVFacade.setCrop(cameraName); }
//Modify config values
else if(modifiedProperty != ConfigProperties.PRIME) else if(modifiedProperty != ConfigProperties.PRIME)
{ {
prompt("Enter new value for this property (" + modifiedProperty.toString() + ", currently : " + prompt("Enter new value for this property (" + modifiedProperty.toString() + ", currently : " +
ConfigFacade.getValue(cameraName,modifiedProperty) + "): "); (int)ConfigFacade.getValue(cameraName,modifiedProperty) + "): ");
userInput = inputFiltering(inputScanner.nextLine()); userInput = inputFiltering(inputScanner.nextLine());
ConfigFacade.setValue(cameraName,modifiedProperty,userInput); ConfigFacade.setValue(cameraName,modifiedProperty,userInput);
//if(canvas != null) canvas.dispose(); //if(canvas != null) canvas.dispose();
} }
//Exit loop
else break; else break;
} while(true); } while(true);

View file

@ -5,6 +5,7 @@ import java.util.Set;
import static org.bytedeco.opencv.global.opencv_imgproc.*; import static org.bytedeco.opencv.global.opencv_imgproc.*;
import static org.bytedeco.opencv.global.opencv_imgcodecs.*; 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_core.*;
import org.bytedeco.javacv.*; import org.bytedeco.javacv.*;
@ -22,7 +23,7 @@ import java.util.List;
* Performs image capture, as well as image manipulation. * Performs image capture, as well as image manipulation.
* *
* @author Blizzard Finnegan * @author Blizzard Finnegan
* @version 1.4.1, 09 Feb. 2023 * @version 1.5.0, 10 Feb. 2023
*/ */
public class OpenCVFacade public class OpenCVFacade
{ {
@ -36,7 +37,7 @@ public class OpenCVFacade
/** /**
* Object used to convert between Mats and Frames * Object used to convert between Mats and Frames
*/ */
private static final OpenCVFrameConverter.ToMat MAT_CONVERTER = new OpenCVFrameConverter.ToMat(); public static final OpenCVFrameConverter.ToMat MAT_CONVERTER = new OpenCVFrameConverter.ToMat();
/** /**
* Width of the image created by the camera. * Width of the image created by the camera.
@ -228,15 +229,68 @@ public class OpenCVFacade
return output; return output;
} }
/** /**
* Crop the given image to the dimensions in the configuration. * Set crop size and location by GUI means.
* *
* @param cameraName The name of the camera being configured
*/
public static void setCrop(String cameraName)
{
Mat uncroppedImage = takePicture(cameraName);
Rect roi = selectROI("Pick Crop Location", uncroppedImage);
ConfigFacade.setValue(cameraName,ConfigProperties.CROP_X, roi.x());
ConfigFacade.setValue(cameraName,ConfigProperties.CROP_Y, roi.y());
ConfigFacade.setValue(cameraName,ConfigProperties.CROP_W, roi.width());
ConfigFacade.setValue(cameraName,ConfigProperties.CROP_H, roi.height());
}
/**
* Crop a given image, based on dimensions in the configuration.
*
* @param image Frame taken from the camera
* @param cameraName Name of the camera the frame is from
*/
public static Mat crop(Mat image, String cameraName)
{
int x = (int)ConfigFacade.getValue(cameraName,ConfigProperties.CROP_X);
int y = (int)ConfigFacade.getValue(cameraName,ConfigProperties.CROP_Y);
int width = (int)ConfigFacade.getValue(cameraName,ConfigProperties.CROP_W);
int height = (int)ConfigFacade.getValue(cameraName,ConfigProperties.CROP_H);
Rect roi = new Rect(x,y,width,height);
return crop(image, roi,cameraName);
}
/**
* Crop the given image, based on dimensions defined in a {@link Rect}
*
* @param image Frame taken from the camera
* @param roi The region of interest to crop the image to
*
* @return Frame of the cropped image
*/
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)));
return output;
}
/**
* Crop the given image to the dimensions in the configuration;
* deprecated in favour of {@link #crop(Mat, Rect)}
*
* @deprecated
* @param image Frame taken from the camera. * @param image Frame taken from the camera.
* @param cameraName Name of the camera taking the picture * @param cameraName Name of the camera taking the picture
* *
* @return Frame of the cropped image * @return Frame of the cropped image
*/ */
public static Mat crop(Mat image, String cameraName) private static Mat cropImage(Mat image, String cameraName)
{ {
Mat output = null; Mat output = null;
int x = (int)ConfigFacade.getValue(cameraName,ConfigProperties.CROP_X); int x = (int)ConfigFacade.getValue(cameraName,ConfigProperties.CROP_X);

View file

@ -4,31 +4,21 @@
## Cli(?) ## Cli(?)
- [ ] enable camera toggling - [x] enable camera toggling
- may require more classes to be modified
### MovementFacade
- [x] Implement multithreading for physical Run switch\*
- Currently questionably implemented, consider looking into more
### OpenCVFacade ### OpenCVFacade
- [x] Overload takeBurst with a default framecount from config
- [x] Overload crop with default values from config
- [ ] completeProcess should have more robust file output checking - [ ] completeProcess should have more robust file output checking
### Gui ### Gui
- [x] rebuild menus with current feature set - [ ] Debug and ensure GUI is written properly
- [x] Complete implementation
- currently questionably implemented; debugging...
## Low-priority improvements ## Low-priority improvements
### All ### All
- [ ] denote overrided functions in first sentence of function - [x] denote overrided functions in first sentence of function
- [ ] reduce Javadoc linking to one link per reference per class - [ ] reduce Javadoc linking to one link per reference per class
- [ ] Use generated Javadocs to improve Javadocs (perpetual) - [ ] Use generated Javadocs to improve Javadocs (perpetual)