first commit
This commit is contained in:
760
src/main/java/id/co/gtc/erhacam/Cameradetail.java
Normal file
760
src/main/java/id/co/gtc/erhacam/Cameradetail.java
Normal file
@@ -0,0 +1,760 @@
|
||||
package id.co.gtc.erhacam;
|
||||
|
||||
import Camera.ArducamIMX477Preset;
|
||||
import Camera.CameraProperty;
|
||||
import Camera.LiveCamEvent;
|
||||
import Config.CameraConfigEnum;
|
||||
import com.google.zxing.BinaryBitmap;
|
||||
import com.google.zxing.NotFoundException;
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
|
||||
import com.google.zxing.common.HybridBinarizer;
|
||||
import javafx.application.Platform;
|
||||
|
||||
import javafx.concurrent.Task;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.Slider;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.image.PixelFormat;
|
||||
import javafx.scene.image.WritableImage;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.val;
|
||||
import org.bytedeco.javacv.Frame;
|
||||
import org.bytedeco.javacv.OpenCVFrameGrabber;
|
||||
import org.bytedeco.opencv.global.opencv_imgproc;
|
||||
import org.bytedeco.opencv.opencv_core.*;
|
||||
import org.opencv.videoio.Videoio;
|
||||
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.DataBufferByte;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.file.Path;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import static Config.SomeCodes.*;
|
||||
import static org.bytedeco.opencv.global.opencv_core.CV_8UC3;
|
||||
import static org.bytedeco.opencv.global.opencv_core.mean;
|
||||
import static org.bytedeco.opencv.global.opencv_imgcodecs.imwrite;
|
||||
import static org.bytedeco.opencv.global.opencv_imgproc.*;
|
||||
|
||||
@SuppressWarnings({"unused"})
|
||||
public class Cameradetail {
|
||||
private final AtomicBoolean Capturing = new AtomicBoolean(false);
|
||||
private final AtomicBoolean TakingPhoto = new AtomicBoolean(false);
|
||||
private final AtomicBoolean IsGrabbingLiveView = new AtomicBoolean(false);
|
||||
private OpenCVFrameGrabber mGrabber = null;
|
||||
private LiveCamEvent event = null;
|
||||
private @Getter @Setter CameraConfigEnum cameraConfigEnum = CameraConfigEnum.CameraConfigCenter;
|
||||
private @Getter int LiveFPS = 0;
|
||||
|
||||
/**
|
||||
* Get detected QR text from Live View
|
||||
*/
|
||||
private @Getter String qrtext = null;
|
||||
|
||||
@FXML
|
||||
private Label cameratitle;
|
||||
|
||||
@FXML
|
||||
private ImageView camerastream;
|
||||
|
||||
@FXML
|
||||
private AnchorPane streamanchor;
|
||||
|
||||
@FXML
|
||||
private Label camerastatus;
|
||||
|
||||
@FXML
|
||||
private Slider brightnessSlider;
|
||||
@FXML
|
||||
private Slider contrastSlider;
|
||||
@FXML
|
||||
private Slider saturationSlider;
|
||||
@FXML
|
||||
private Slider hueSlider;
|
||||
@FXML
|
||||
private Slider gainSlider;
|
||||
@FXML
|
||||
private Slider exposureSlider;
|
||||
@FXML
|
||||
private CheckBox AutoExposure;
|
||||
@FXML
|
||||
private CheckBox AutoWhiteBalance;
|
||||
@FXML
|
||||
private CheckBox AutoFocus;
|
||||
|
||||
private final UMat BestMat = new UMat();
|
||||
private final UMat LiveMat = new UMat();
|
||||
private Size LiveSize = new Size(640, 480);
|
||||
private Size PhotoSize = new Size(1920, 1080);
|
||||
|
||||
private void setSliderValue(Slider sld, CameraProperty prop, double value){
|
||||
sld.setMin(prop.Min);
|
||||
sld.setMax(prop.Max);
|
||||
sld.setValue(value);
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void initialize(){
|
||||
|
||||
camerastream.fitHeightProperty().bind(streamanchor.heightProperty());
|
||||
//camerastream.fitWidthProperty().bind(streamanchor.widthProperty());
|
||||
camerastream.setPreserveRatio(true);
|
||||
|
||||
Platform.runLater(()->{
|
||||
setSliderValue(brightnessSlider, ArducamIMX477Preset.Brightness, config.getBrightness(cameraConfigEnum));
|
||||
setSliderValue(contrastSlider, ArducamIMX477Preset.Contrast, config.getContrast(cameraConfigEnum));
|
||||
setSliderValue(saturationSlider, ArducamIMX477Preset.Saturation, config.getSaturation(cameraConfigEnum));
|
||||
setSliderValue(hueSlider, ArducamIMX477Preset.Hue, config.getHue(cameraConfigEnum));
|
||||
setSliderValue(gainSlider, ArducamIMX477Preset.Gain, config.getGain(cameraConfigEnum));
|
||||
setSliderValue(exposureSlider, ArducamIMX477Preset.ExposureTime, config.getExposure(cameraConfigEnum));
|
||||
AutoExposure.setSelected(config.getAutoExposure(cameraConfigEnum));
|
||||
AutoWhiteBalance.setSelected(config.getAutoWhiteBalance(cameraConfigEnum));
|
||||
AutoFocus.setSelected(config.getAutoFocus(cameraConfigEnum));
|
||||
});
|
||||
|
||||
AutoExposure.selectedProperty().addListener((obs, oldVal, newVal) -> {
|
||||
setAutoExposure(newVal);
|
||||
config.setAutoExposure(cameraConfigEnum, newVal);
|
||||
raise_log("AutoExposure for "+getCameraTitle()+" changed to " + newVal);
|
||||
});
|
||||
|
||||
AutoWhiteBalance.selectedProperty().addListener((obs, oldVal, newVal) -> {
|
||||
setAutoWB(newVal);
|
||||
config.setAutoWhiteBalance(cameraConfigEnum, newVal);
|
||||
raise_log("AutoWhiteBalance for "+getCameraTitle()+" changed to "+newVal);
|
||||
});
|
||||
AutoFocus.selectedProperty().addListener((obs, oldVal, newVal) -> {
|
||||
setAutoFocus(newVal);
|
||||
config.setAutoFocus(cameraConfigEnum, newVal);
|
||||
raise_log("AutoFocus for "+getCameraTitle()+" changed to "+newVal);
|
||||
});
|
||||
|
||||
brightnessSlider.valueProperty().addListener((obs, oldVal, newVal) -> {
|
||||
setBrightness(newVal.doubleValue());
|
||||
config.setBrightness(cameraConfigEnum, newVal.doubleValue());
|
||||
raise_log("Brightness for "+getCameraTitle()+" changed to "+newVal);
|
||||
});
|
||||
contrastSlider.valueProperty().addListener((obs, oldVal, newVal) -> {
|
||||
setContrast(newVal.doubleValue());
|
||||
config.setContrast(cameraConfigEnum, newVal.doubleValue());
|
||||
raise_log("Contrast for "+getCameraTitle()+" changed to "+newVal);
|
||||
});
|
||||
saturationSlider.valueProperty().addListener((obs, oldVal, newVal) -> {
|
||||
setSaturation(newVal.doubleValue());
|
||||
config.setSaturation(cameraConfigEnum, newVal.doubleValue());
|
||||
raise_log("Saturation for "+getCameraTitle()+" changed to "+newVal);
|
||||
});
|
||||
hueSlider.valueProperty().addListener((obs, oldVal, newVal) -> {
|
||||
setHue(newVal.doubleValue());
|
||||
config.setHue(cameraConfigEnum, newVal.doubleValue());
|
||||
raise_log("Hue for "+getCameraTitle()+" changed to "+newVal);
|
||||
});
|
||||
gainSlider.valueProperty().addListener((obs, oldVal, newVal) -> {
|
||||
setGain(newVal.doubleValue());
|
||||
config.setGain(cameraConfigEnum, newVal.doubleValue());
|
||||
raise_log("Gain for "+getCameraTitle()+" changed to "+newVal);
|
||||
});
|
||||
exposureSlider.valueProperty().addListener((obs, oldVal, newVal) -> {
|
||||
setExposure(newVal.doubleValue());
|
||||
config.setExposure(cameraConfigEnum, newVal.doubleValue());
|
||||
raise_log("Exposure for "+getCameraTitle()+" changed to "+newVal);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void resetClick(){
|
||||
brightnessSlider.adjustValue(ArducamIMX477Preset.Brightness.Default);
|
||||
contrastSlider.adjustValue(ArducamIMX477Preset.Contrast.Default);
|
||||
saturationSlider.adjustValue(ArducamIMX477Preset.Saturation.Default);
|
||||
hueSlider.adjustValue(ArducamIMX477Preset.Hue.Default);
|
||||
gainSlider.adjustValue(ArducamIMX477Preset.Gain.Default);
|
||||
exposureSlider.adjustValue(ArducamIMX477Preset.ExposureTime.Default);
|
||||
AutoExposure.setSelected(true);
|
||||
AutoFocus.setSelected(true);
|
||||
AutoWhiteBalance.setSelected(true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public boolean isCapturing(){
|
||||
return Capturing.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Camera Title
|
||||
* @param title Title of the Camera
|
||||
*/
|
||||
public void setCameraTitle(String title){
|
||||
if (ValidString(title)){
|
||||
if (cameratitle!=null){
|
||||
cameratitle.setText(title);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setSaturation(double value){
|
||||
if (mGrabber!=null){
|
||||
mGrabber.setOption(Videoio.CAP_PROP_SATURATION, value);
|
||||
}
|
||||
}
|
||||
|
||||
public double getSaturation(){
|
||||
if (mGrabber!=null){
|
||||
return mGrabber.getOption(Videoio.CAP_PROP_SATURATION);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setHue(double value){
|
||||
if (mGrabber!=null){
|
||||
mGrabber.setOption(Videoio.CAP_PROP_HUE, value);
|
||||
}
|
||||
}
|
||||
|
||||
public double getHue(){
|
||||
if (mGrabber!=null){
|
||||
return mGrabber.getOption(Videoio.CAP_PROP_HUE);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setGain(double value){
|
||||
if (mGrabber!=null){
|
||||
mGrabber.setOption(Videoio.CAP_PROP_GAIN, value);
|
||||
}
|
||||
}
|
||||
|
||||
public double getGain(){
|
||||
if (mGrabber!=null){
|
||||
return mGrabber.getOption(Videoio.CAP_PROP_GAIN);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Camera Title
|
||||
* @return Title of the Camera, or empty string if not set
|
||||
*/
|
||||
public String getCameraTitle(){
|
||||
if (cameratitle!=null){
|
||||
return cameratitle.getText();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Camera Status
|
||||
* @param status Status of the Camera
|
||||
*/
|
||||
public void setCameraStatus(String status){
|
||||
if (ValidString(status)){
|
||||
if (camerastatus!=null){
|
||||
camerastatus.setText(status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Camera Status
|
||||
* @return Status of the Camera, or empty string if not set
|
||||
*/
|
||||
public String getCameraStatus(){
|
||||
if (camerastatus!=null){
|
||||
return camerastatus.getText();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Camera Stream
|
||||
* @param image Image to be displayed
|
||||
*/
|
||||
public void setCameraStream(Image image){
|
||||
if (image!=null){
|
||||
if (camerastream!=null){
|
||||
camerastream.setImage(image);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Camera Stream
|
||||
* @return Image of the Camera Stream, or null if not set
|
||||
*/
|
||||
public Image getCameraStream(){
|
||||
if (camerastream!=null){
|
||||
return camerastream.getImage();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setFPS(double value){
|
||||
if (mGrabber!=null){
|
||||
mGrabber.setOption(Videoio.CAP_PROP_FPS, value);
|
||||
}
|
||||
}
|
||||
|
||||
public double getFPS(){
|
||||
if (mGrabber!=null){
|
||||
return mGrabber.getOption(Videoio.CAP_PROP_FPS);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Camera Grabber and Target Width and Height
|
||||
* @param grabber Camera Grabber
|
||||
* @param livewidth Width used on live view
|
||||
* @param liveheight Height used on live view
|
||||
* @param photowidth Width used on photo capture
|
||||
* @param photoheight Height used on photo capture
|
||||
*/
|
||||
public void SetGrabber(OpenCVFrameGrabber grabber, int livewidth, int liveheight, int photowidth, int photoheight){
|
||||
if (mGrabber!=null) {
|
||||
StopLiveView();
|
||||
}
|
||||
LiveSize = new Size(livewidth, liveheight);
|
||||
PhotoSize = new Size(photowidth, photoheight);
|
||||
mGrabber = grabber;
|
||||
}
|
||||
|
||||
//Exposure and Focus Tricks :
|
||||
// https://stackoverflow.com/questions/53545945/how-to-set-camera-to-auto-exposure-with-opencv-3-4-2
|
||||
// https://github.com/opencv/opencv/issues/9738
|
||||
|
||||
/**
|
||||
* Set Auto Exposure Mode
|
||||
* @param ON if true, set autoexposure on, otherwise off
|
||||
*/
|
||||
public void setAutoExposure(boolean ON){
|
||||
if (mGrabber!=null){
|
||||
mGrabber.setOption(Videoio.CAP_PROP_AUTO_EXPOSURE, ON?ArducamIMX477Preset.AutoExposure.On:ArducamIMX477Preset.AutoExposure.Off);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Auto Exposure Mode
|
||||
* @return true if autoexposure is on, otherwise off
|
||||
*/
|
||||
public boolean getAutoExposure(){
|
||||
if (mGrabber!=null){
|
||||
return mGrabber.getOption(Videoio.CAP_PROP_AUTO_EXPOSURE)==ArducamIMX477Preset.AutoExposure.On;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Exposure when Auto Exposure is Off
|
||||
* @param value exposure value
|
||||
*/
|
||||
public void setExposure(double value){
|
||||
if (mGrabber!=null){
|
||||
mGrabber.setOption(Videoio.CAP_PROP_EXPOSURE, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Exposure when Auto Exposure is Off
|
||||
* @return exposure value
|
||||
*/
|
||||
public double getExposure(){
|
||||
if (mGrabber!=null){
|
||||
return mGrabber.getOption(Videoio.CAP_PROP_EXPOSURE);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Auto Focus
|
||||
* @param ON if true, set autofocus on, otherwise off
|
||||
*/
|
||||
public void setAutoFocus(boolean ON){
|
||||
if (mGrabber!=null){
|
||||
mGrabber.setOption(Videoio.CAP_PROP_AUTOFOCUS, ON?ArducamIMX477Preset.AutoFocus.On:ArducamIMX477Preset.AutoFocus.Off);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Auto Focus
|
||||
* @return true if autofocus is on, otherwise off
|
||||
*/
|
||||
public boolean getAutoFocus(){
|
||||
if (mGrabber!=null){
|
||||
return mGrabber.getOption(Videoio.CAP_PROP_AUTOFOCUS)==ArducamIMX477Preset.AutoFocus.On;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setAutoWB(boolean ON){
|
||||
if (mGrabber!=null){
|
||||
mGrabber.setOption(Videoio.CAP_PROP_AUTO_WB, ON?ArducamIMX477Preset.AutoWhiteBalance.On:ArducamIMX477Preset.AutoWhiteBalance.Off);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getAutoWB(){
|
||||
if (mGrabber!=null){
|
||||
return mGrabber.getOption(Videoio.CAP_PROP_AUTO_WB)==ArducamIMX477Preset.AutoWhiteBalance.On;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Focus when Auto Focus is Off
|
||||
* @param value focus value
|
||||
*/
|
||||
public void setFocus(double value){
|
||||
if (mGrabber!=null){
|
||||
mGrabber.setOption(Videoio.CAP_PROP_FOCUS, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Focus when Auto Focus is Off
|
||||
* @return focus value
|
||||
*/
|
||||
public double getFocus(){
|
||||
if (mGrabber!=null){
|
||||
return mGrabber.getOption(Videoio.CAP_PROP_FOCUS);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setBrightness(double value){
|
||||
if (mGrabber!=null){
|
||||
mGrabber.setOption(Videoio.CAP_PROP_BRIGHTNESS, value);
|
||||
}
|
||||
}
|
||||
|
||||
public double getBrightness(){
|
||||
if (mGrabber!=null){
|
||||
return mGrabber.getOption(Videoio.CAP_PROP_BRIGHTNESS);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setContrast(double value){
|
||||
if (mGrabber!=null){
|
||||
mGrabber.setOption(Videoio.CAP_PROP_CONTRAST, value);
|
||||
}
|
||||
}
|
||||
|
||||
public double getContrast(){
|
||||
if (mGrabber!=null){
|
||||
return mGrabber.getOption(Videoio.CAP_PROP_CONTRAST);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setFrameWidth(int width){
|
||||
if (mGrabber!=null){
|
||||
mGrabber.setOption(Videoio.CAP_PROP_FRAME_WIDTH, width);
|
||||
}
|
||||
}
|
||||
|
||||
public double getFrameWidth(){
|
||||
if (mGrabber!=null){
|
||||
return mGrabber.getOption(Videoio.CAP_PROP_FRAME_WIDTH);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setFrameHeight(int height){
|
||||
if (mGrabber!=null){
|
||||
mGrabber.setOption(Videoio.CAP_PROP_FRAME_HEIGHT, height);
|
||||
}
|
||||
}
|
||||
|
||||
public double getFrameHeight(){
|
||||
if (mGrabber!=null){
|
||||
return mGrabber.getOption(Videoio.CAP_PROP_FRAME_HEIGHT);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setSharpness(double value){
|
||||
if (mGrabber!=null){
|
||||
mGrabber.setOption(Videoio.CAP_PROP_SHARPNESS, value);
|
||||
}
|
||||
}
|
||||
|
||||
public double getSharpness(){
|
||||
if (mGrabber!=null){
|
||||
return mGrabber.getOption(Videoio.CAP_PROP_SHARPNESS);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setGamma(double value){
|
||||
if (mGrabber!=null){
|
||||
mGrabber.setOption(Videoio.CAP_PROP_GAMMA, value);
|
||||
}
|
||||
}
|
||||
|
||||
public double getGamma(){
|
||||
if (mGrabber!=null){
|
||||
return mGrabber.getOption(Videoio.CAP_PROP_GAMMA);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Take Photo from Camera
|
||||
* @param directory directory to save the photo, if null, will use default directory
|
||||
* @param prefix filename prefix
|
||||
* @return filename path of the saved photo, or null if failed
|
||||
*/
|
||||
@SuppressWarnings("BusyWait")
|
||||
public String TakePhoto(String directory, String prefix) throws InterruptedException {
|
||||
String result = null;
|
||||
if (!ValidDirectory(directory)) directory = currentDirectory;
|
||||
if (mGrabber!=null){
|
||||
while(IsGrabbingLiveView.get()){
|
||||
Thread.sleep(10);
|
||||
}
|
||||
TakingPhoto.set(true);
|
||||
if (!BestMat.empty()){
|
||||
Size sz = BestMat.size();
|
||||
raise_log("TakePhoto got frame with width: " + sz.width() + " and height: " + sz.height());
|
||||
String filename = Path.of(directory, makeFileName(prefix)).toString();
|
||||
if (imwrite(filename, BestMat)){
|
||||
raise_log("TakePhoto success, Photo saved to " + filename);
|
||||
result = filename;
|
||||
} else raise_log("TakePhoto failed, Unable to Save Photo");
|
||||
} else raise_log("TakePhoto failed, Live View is Empty");
|
||||
} else raise_log("TakePhoto failed, Grabber is null");
|
||||
TakingPhoto.set(false);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private String makeFileName(String prefix){
|
||||
//make filename with prefix_POSITION_YYYY-MM-DD_HH-MM-SS
|
||||
|
||||
LocalDateTime ldt = LocalDateTime.now();
|
||||
String timetag = ldt.getYear() + "-" + ldt.getMonthValue() + "-" + ldt.getDayOfMonth() + "_" + ldt.getHour() + "-" + ldt.getMinute() + "-" + ldt.getSecond();
|
||||
return prefix+"_"
|
||||
+ switch(cameratitle.getText()){
|
||||
case "Camera Left 90" -> "LEFT90";
|
||||
case "Camera Left 45" -> "LEFT45";
|
||||
case "Camera Center" -> "CENTER";
|
||||
case "Camera Right 45" -> "RIGHT45";
|
||||
case "Camera Right 90" -> "RIGHT90";
|
||||
default -> "UNKNOWN";
|
||||
}
|
||||
+ "_" + timetag + ".jpg";
|
||||
|
||||
}
|
||||
|
||||
public void StopLiveView(){
|
||||
Capturing.set(false);
|
||||
if (mGrabber!=null){
|
||||
try{
|
||||
mGrabber.stop();
|
||||
Platform.runLater(()->setCameraStatus("Camera Stopped"));
|
||||
} catch (Exception e){
|
||||
raise_log("StopLiveView failed, Unable to Stop Camera, Error: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
TakingPhoto.set(false);
|
||||
IsGrabbingLiveView.set(false);
|
||||
}
|
||||
|
||||
|
||||
public boolean StartLiveView(LiveCamEvent event, String cameratitle, final boolean use_qr , final boolean use_face) {
|
||||
this.event = event;
|
||||
if (mGrabber != null) {
|
||||
try {
|
||||
|
||||
if (use_qr) raise_log("QR Reader loaded");
|
||||
if (use_face) raise_log("Face detector loaded");
|
||||
// capture with best resolution
|
||||
setFrameHeight(PhotoSize.height());
|
||||
setFrameWidth(PhotoSize.width());
|
||||
|
||||
LiveFPS = 0;
|
||||
mGrabber.start();
|
||||
|
||||
Capturing.set(true);
|
||||
// just information
|
||||
String ss = String.format("Camera Started with resolution %dx%d@%d", PhotoSize.width(), PhotoSize.height(),LiveFPS);
|
||||
Platform.runLater(()->setCameraStatus(ss));
|
||||
raise_log(ss);
|
||||
|
||||
AutoExposure.setSelected(true);
|
||||
AutoFocus.setSelected(true);
|
||||
AutoWhiteBalance.setSelected(true);
|
||||
|
||||
Task<Image> task = new Task<>() {
|
||||
@SuppressWarnings("BusyWait")
|
||||
@Override
|
||||
protected Image call() {
|
||||
// repeat until capturing is false
|
||||
AtomicInteger fps = new AtomicInteger(0);
|
||||
TimerTask timerTask = new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
LiveFPS = fps.getAndSet(0);
|
||||
}
|
||||
};
|
||||
Timer timer = new java.util.Timer();
|
||||
timer.scheduleAtFixedRate(timerTask, 1000, 1000);
|
||||
while (Capturing.get()) {
|
||||
try {
|
||||
// selama proses pengambilan foto, jangan ambil frame
|
||||
while(TakingPhoto.get() && Capturing.get()){
|
||||
Thread.sleep(10);
|
||||
}
|
||||
|
||||
if (!Capturing.get()) return null;
|
||||
IsGrabbingLiveView.set(true);
|
||||
Frame frame = mGrabber.grab(); // grab frame
|
||||
Mat mat = matconverter.convert(frame); // convert to Mat
|
||||
mat.copyTo(BestMat); // copy to BestMat for using OpenCL
|
||||
fps.addAndGet(1);
|
||||
IsGrabbingLiveView.set(false);
|
||||
|
||||
if (frame != null) {
|
||||
opencv_imgproc.resize(BestMat, LiveMat, LiveSize); // resize to LiveSize
|
||||
UMat graymat = new UMat(); // use OpenCL for grayscale
|
||||
opencv_imgproc.cvtColor(LiveMat,graymat, COLOR_BGR2GRAY); // convert to grayscale
|
||||
if (use_qr){
|
||||
String qr = DetectQRFromMat(graymat);
|
||||
if (qr!=null) {
|
||||
if (!qr.equals(qrtext)){
|
||||
qrtext = qr;
|
||||
raise_log("QR Detected: " + qr);
|
||||
if (event!=null) event.onDetectedQRCode(qr);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (use_face){
|
||||
RectVector face = DetectFace(graymat);
|
||||
if (face!=null && face.size()>0){
|
||||
if (event!=null) event.onFaceDetector(true, PhotoSize.width(), PhotoSize.height());
|
||||
for(int i=0; i<face.size(); i++){
|
||||
Rect rect = face.get(i);
|
||||
rectangle(LiveMat, rect, Scalar.GREEN);
|
||||
}
|
||||
} else if (event!=null) event.onFaceDetector(false, PhotoSize.width(), PhotoSize.height());
|
||||
|
||||
}
|
||||
|
||||
|
||||
UMat rgbmat = new UMat(LiveMat.size(), CV_8UC3);
|
||||
cvtColor(LiveMat, rgbmat, COLOR_BGR2RGB);
|
||||
|
||||
Mat imgmat = new Mat();
|
||||
rgbmat.copyTo(imgmat); // copy back to CPU
|
||||
// Update Task Value usign matToWritableImage
|
||||
updateValue(matToWritableImage(imgmat, imgmat.cols(), imgmat.rows()));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
raise_log("Unable to Grab Frame, Error: " + e.getMessage());
|
||||
//if (!Capturing.get()) Platform.runLater(this::StopLiveView);
|
||||
}
|
||||
}
|
||||
timer.cancel();
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
// value dari task, yaitu image, akan diupdate ke camerastream
|
||||
task.valueProperty().addListener((obs, oldVal, newVal) -> {
|
||||
if (newVal != null) {
|
||||
setCameraStream(newVal);
|
||||
}
|
||||
});
|
||||
|
||||
// start task
|
||||
new Thread(task).start();
|
||||
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
raise_log("StartLiveView failed, Unable to Start Camera, Error: " + e.getMessage());
|
||||
}
|
||||
} else raise_log("StartLiveView failed, grabber is null");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect QR Code from Mat
|
||||
* @param graymat Mat in Gray Scale
|
||||
* @return QR Code Text, or null if not detected
|
||||
*/
|
||||
private String DetectQRFromMat(UMat graymat){
|
||||
if (qrreader!=null){
|
||||
Mat mat = new Mat();
|
||||
graymat.copyTo(mat); // back to CPU, because zxing only accept BufferedImage
|
||||
BufferedImage bufferedImage = matToBufferedImage(mat);
|
||||
String title = cameratitle.getText();
|
||||
BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(new BufferedImageLuminanceSource(bufferedImage)));
|
||||
try{
|
||||
Result result = qrreader.decode(binaryBitmap);
|
||||
if (result!=null){
|
||||
return result.getText();
|
||||
}
|
||||
} catch (NotFoundException ignored) {
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect Face from Mat
|
||||
* @param graymat Mat in Gray Scale
|
||||
* @return RectVector if face detected, otherwise false
|
||||
*/
|
||||
private RectVector DetectFace(UMat graymat){
|
||||
if (faceDetector!=null){
|
||||
RectVector face = new RectVector();
|
||||
faceDetector.detectMultiScale(graymat, face);
|
||||
return face;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private double getBrightnessFromGrayMat(Mat graymat){
|
||||
Scalar mean = mean(graymat);
|
||||
return mean.get(0);
|
||||
}
|
||||
|
||||
private WritableImage matToWritableImage(Mat mat, int cols, int rows){
|
||||
WritableImage writableImage = new WritableImage(cols, rows);
|
||||
ByteBuffer buffer = mat.createBuffer();
|
||||
PixelFormat<ByteBuffer> pixelFormat = PixelFormat.getByteRgbInstance();
|
||||
writableImage.getPixelWriter().setPixels(0, 0, mat.cols(), mat.rows(), pixelFormat, buffer, mat.cols() * 3);
|
||||
return writableImage;
|
||||
}
|
||||
|
||||
private BufferedImage matToBufferedImage(Mat mat){
|
||||
int type = BufferedImage.TYPE_BYTE_GRAY;
|
||||
if (mat.channels() > 1) {
|
||||
type = BufferedImage.TYPE_3BYTE_BGR;
|
||||
}
|
||||
BufferedImage image = new BufferedImage(mat.cols(), mat.rows(), type);
|
||||
byte[] data = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
|
||||
|
||||
mat.data().get(data);
|
||||
return image;
|
||||
}
|
||||
|
||||
private void raise_log(String msg){
|
||||
if (event!=null) event.onLog(msg);
|
||||
}
|
||||
}
|
||||
633
src/main/java/id/co/gtc/erhacam/CaptureView.java
Normal file
633
src/main/java/id/co/gtc/erhacam/CaptureView.java
Normal file
@@ -0,0 +1,633 @@
|
||||
package id.co.gtc.erhacam;
|
||||
|
||||
import BASS.AudioPlayer;
|
||||
import BASS.PlaybackStatus;
|
||||
import Camera.*;
|
||||
import Config.CameraConfigEnum;
|
||||
import Config.SomeCodes;
|
||||
import Database.PhotoReviewClass;
|
||||
import Database.Sqlite;
|
||||
import FTP.FTPUpload;
|
||||
import FTP.FTPUploadEvent;
|
||||
import javafx.application.Platform;
|
||||
import javafx.concurrent.Task;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import javafx.stage.DirectoryChooser;
|
||||
import lombok.val;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import javafx.scene.control.Alert.AlertType;
|
||||
import org.bytedeco.javacv.OpenCVFrameConverter;
|
||||
import org.bytedeco.javacv.OpenCVFrameGrabber;
|
||||
import org.bytedeco.javacv.VideoInputFrameGrabber;
|
||||
import org.bytedeco.opencv.opencv_core.Size;
|
||||
import org.tinylog.Logger;
|
||||
|
||||
import static Config.SomeCodes.*;
|
||||
|
||||
public class CaptureView {
|
||||
|
||||
@FXML
|
||||
private AnchorPane cam1, cam2, cam3, cam4, cam5, controlpane;
|
||||
|
||||
private Cameradetail image1, image2, image3, image4, image5;
|
||||
|
||||
|
||||
@FXML
|
||||
private TextArea directorypath, prefixfile;
|
||||
|
||||
@FXML
|
||||
private AnchorPane progressanchor;
|
||||
|
||||
private AudioPlayer audioPlayer;
|
||||
private String audio_posisikan_muka = "satu.wav";
|
||||
private String audio_posisi_diam = "dua.wav";
|
||||
private String audio_foto_selesai = "tiga.wav";
|
||||
private String audio_ke_ruangtunggu = "empat.wav";
|
||||
|
||||
private List<String> cams;
|
||||
|
||||
@FXML
|
||||
private void ChangeDirectory(){
|
||||
DirectoryChooser dc = new DirectoryChooser();
|
||||
dc.setTitle("Select Directory");
|
||||
String path = dc.showDialog(null).getAbsolutePath();
|
||||
|
||||
config.SetPhotoDirectory(path);
|
||||
config.Save();
|
||||
directorypath.setText(path);
|
||||
}
|
||||
|
||||
private void trigger_autofocus(Cameradetail image) throws InterruptedException {
|
||||
if (image!=null){
|
||||
if (image.isCapturing()){
|
||||
image.setAutoFocus(false);
|
||||
Thread.sleep(2);
|
||||
image.setFocus(0.9);
|
||||
Thread.sleep(2);
|
||||
image.setAutoFocus(true);
|
||||
Thread.sleep(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void AutoFocus() throws InterruptedException {
|
||||
trigger_autofocus(image1);
|
||||
trigger_autofocus(image2);
|
||||
trigger_autofocus(image3);
|
||||
trigger_autofocus(image4);
|
||||
trigger_autofocus(image5);
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("resource")
|
||||
@FXML
|
||||
private void TakePhotos(){
|
||||
Size thumbsize = new Size(160,120);
|
||||
String directory = directorypath.getText();
|
||||
String prefix = RemoveSpaces(prefixfile.getText()) ;
|
||||
if (ValidDirectory(directory)){
|
||||
if (ValidString(prefix)){
|
||||
audioPlayer.PlayFile(audio_posisi_diam, ps);
|
||||
PhotoReviewClass prc = new PhotoReviewClass();
|
||||
prc.setPrefix(prefix);
|
||||
|
||||
long nanostart = System.nanoTime(); // for performance measurement
|
||||
|
||||
ExecutorService executor = Executors.newFixedThreadPool(5);
|
||||
|
||||
Callable<String> task1 = ()->{
|
||||
if (image1!=null) {
|
||||
String p1 = image1.TakePhoto(directory,prefix);
|
||||
if (ValidFile(p1)) {
|
||||
Platform.runLater(()->image1.setCameraStatus("Photo: "+ SomeCodes.GetFileName(p1)));
|
||||
|
||||
prc.setFileLeft90(p1);
|
||||
String thumb1 = MakeThumbfile(p1, thumbsize);
|
||||
if (ValidFile(thumb1)) prc.setThumbLeft90(thumb1);
|
||||
}
|
||||
}
|
||||
return "Task 1 Done";
|
||||
};
|
||||
Callable<String> task2 = ()->{
|
||||
if (image2!=null) {
|
||||
String p2 = image2.TakePhoto(directory,prefix);
|
||||
if (ValidFile(p2)) {
|
||||
Platform.runLater(()->image2.setCameraStatus("Photo: "+ SomeCodes.GetFileName(p2)));
|
||||
|
||||
prc.setFileLeft45(p2);
|
||||
String thumb2 = MakeThumbfile(p2, thumbsize);
|
||||
if (ValidFile(thumb2)) prc.setThumbLeft45(thumb2);
|
||||
}
|
||||
}
|
||||
return "Task 2 Done";
|
||||
};
|
||||
|
||||
Callable<String> task3 = ()->{
|
||||
if (image3!=null) {
|
||||
String p3 = image3.TakePhoto(directory,prefix);
|
||||
if (ValidFile(p3)) {
|
||||
Platform.runLater(()->image3.setCameraStatus("Photo: "+ SomeCodes.GetFileName(p3)));
|
||||
prc.setFileCenter(p3);
|
||||
String thumb3 = MakeThumbfile(p3, thumbsize);
|
||||
if (ValidFile(thumb3)) prc.setThumbCenter(thumb3);
|
||||
}
|
||||
}
|
||||
return "Task 3 Done";
|
||||
};
|
||||
|
||||
Callable<String> task4 = ()->{
|
||||
if (image4!=null) {
|
||||
String p4 = image4.TakePhoto(directory,prefix);
|
||||
if (ValidFile(p4)) {
|
||||
Platform.runLater(()->image4.setCameraStatus("Photo: "+ SomeCodes.GetFileName(p4)));
|
||||
prc.setFileRight45(p4);
|
||||
String thumb4 = MakeThumbfile(p4, thumbsize);
|
||||
if (ValidFile(thumb4)) prc.setThumbRight45(thumb4);
|
||||
}
|
||||
}
|
||||
return "Task 4 Done";
|
||||
};
|
||||
|
||||
Callable<String> task5 = ()->{
|
||||
if (image5!=null) {
|
||||
String p5 = image5.TakePhoto(directory,prefix);
|
||||
if (ValidFile(p5)) {
|
||||
Platform.runLater(()->image5.setCameraStatus("Photo: "+ SomeCodes.GetFileName(p5)));
|
||||
prc.setFileRight90(p5);
|
||||
String thumb5 = MakeThumbfile(p5, thumbsize);
|
||||
if (ValidFile(thumb5)) prc.setThumbRight90(thumb5);
|
||||
}
|
||||
}
|
||||
return "Task 5 Done";
|
||||
};
|
||||
|
||||
try{
|
||||
Future<String> f1 = executor.submit(task1);
|
||||
Future<String> f2 = executor.submit(task2);
|
||||
Future<String> f3 = executor.submit(task3);
|
||||
Future<String> f4 = executor.submit(task4);
|
||||
Future<String> f5 = executor.submit(task5);
|
||||
|
||||
f1.get();
|
||||
f2.get();
|
||||
f3.get();
|
||||
f4.get();
|
||||
f5.get();
|
||||
} catch (Exception e){
|
||||
Logger.error("Error TakePhotos: " + e.getMessage());
|
||||
} finally {
|
||||
executor.shutdown();
|
||||
}
|
||||
|
||||
long duration = (System.nanoTime() - nanostart) / 1000000; // in milliseconds
|
||||
System.out.println("TakePhotos duration: "+duration+" ms");
|
||||
|
||||
|
||||
audioPlayer.PlayFile(audio_foto_selesai, ps);
|
||||
String[] files = prc.files();
|
||||
if (files!=null && files.length>0){
|
||||
InsertSQL(prc);
|
||||
progressanchor.getChildren().clear();
|
||||
prefixfile.setText("");
|
||||
new Thread(()-> UploadToFTP(files)).start();
|
||||
} else {
|
||||
Alert Alert = new Alert(AlertType.ERROR);
|
||||
Alert.setTitle("Error");
|
||||
Alert.setHeaderText("No Photos Taken");
|
||||
Alert.setContentText("No Photos Taken, please check camera");
|
||||
Alert.showAndWait();
|
||||
}
|
||||
} else {
|
||||
Alert Alert = new Alert(AlertType.ERROR);
|
||||
Alert.setTitle("Error");
|
||||
Alert.setHeaderText("Invalid Prefix");
|
||||
Alert.setContentText("Please input valid prefix or scan QR Code");
|
||||
Alert.showAndWait();
|
||||
}
|
||||
} else {
|
||||
Alert Alert = new Alert(AlertType.ERROR);
|
||||
Alert.setTitle("Error");
|
||||
Alert.setHeaderText("Invalid Directory");
|
||||
Alert.setContentText("Please select valid directory");
|
||||
Alert.showAndWait();
|
||||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void initialize(){
|
||||
audio_posisikan_muka = ExtractResource("/satu.wav");
|
||||
audio_posisi_diam = ExtractResource("/dua.wav");
|
||||
audio_foto_selesai = ExtractResource("/tiga.wav");
|
||||
audio_ke_ruangtunggu = ExtractResource("/empat.wav");
|
||||
|
||||
audioPlayer = new AudioPlayer(1,48000);
|
||||
Logger.info("Audio Player : "+(audioPlayer.isInited()? "Inited" : "Not Inited"));
|
||||
|
||||
cams = null;
|
||||
try{
|
||||
String[] xxx = VideoInputFrameGrabber.getDeviceDescriptions();
|
||||
if (xxx!=null && xxx.length>0){
|
||||
cams = Arrays.asList(xxx);
|
||||
}
|
||||
} catch (Exception e){
|
||||
Logger.error("Error getting camera list: "+e.getMessage());
|
||||
}
|
||||
|
||||
LoadCameraDetail(cam1, 1, CameraConfigEnum.CameraConfigLeft90);
|
||||
LoadCameraDetail(cam2, 2, CameraConfigEnum.CameraConfigLeft45);
|
||||
LoadCameraDetail(cam3, 3, CameraConfigEnum.CameraConfigCenter);
|
||||
LoadCameraDetail(cam4, 4, CameraConfigEnum.CameraConfigRight45);
|
||||
LoadCameraDetail(cam5, 5, CameraConfigEnum.CameraConfigRight90);
|
||||
|
||||
Platform.runLater(()->{
|
||||
int indexleft90=-1;
|
||||
int indexleft45=-1;
|
||||
int indexcenter=-1;
|
||||
int indexright45=-1;
|
||||
int indexright90;
|
||||
if (cams!=null && !cams.isEmpty()){
|
||||
String camleft90 = config.getCameraLeft90();
|
||||
if (ValidString(camleft90)){
|
||||
int[] indexes = FindIndexes(cams, camleft90);
|
||||
if (indexes.length>0){
|
||||
indexleft90 = indexes[0];
|
||||
if (indexleft90!=1){
|
||||
final int finalindex = indexleft90;
|
||||
new Thread(()-> SetupCameraWithController(image1, camleft90, finalindex)).start();
|
||||
}
|
||||
}
|
||||
}
|
||||
String camleft45 = config.getCameraLeft45();
|
||||
if (ValidString(camleft45)){
|
||||
int[] indexes = FindIndexes(cams, camleft45);
|
||||
if (indexes.length>0){
|
||||
indexleft45 = FindFirstIndex(cams, camleft45, indexleft90);
|
||||
if (indexleft45!=-1) {
|
||||
final int finalindex = indexleft45;
|
||||
new Thread(()-> SetupCameraWithController(image2, camleft45, finalindex)).start();
|
||||
}
|
||||
}
|
||||
}
|
||||
String camcenter = config.getCameraCenter();
|
||||
if (ValidString(camcenter)){
|
||||
int[] indexes = FindIndexes(cams, camcenter);
|
||||
if (indexes.length>0){
|
||||
indexcenter = FindFirstIndex(cams, camcenter, indexleft90, indexleft45);
|
||||
if (indexcenter!=-1) {
|
||||
final int finalindex = indexcenter;
|
||||
new Thread(()-> SetupCameraWithController(image3, camcenter, finalindex)).start();
|
||||
}
|
||||
}
|
||||
}
|
||||
String camright45 = config.getCameraRight45();
|
||||
if (ValidString(camright45)){
|
||||
int[] indexes = FindIndexes(cams, camright45);
|
||||
if (indexes.length>0){
|
||||
indexright45 = FindFirstIndex(cams, camright45, indexleft90, indexleft45, indexcenter);
|
||||
if (indexright45!=-1) {
|
||||
final int finalindex = indexright45;
|
||||
new Thread(()-> SetupCameraWithController(image4, camright45, finalindex)).start();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
String camright90 = config.getCameraRight90();
|
||||
if (ValidString(camright90)){
|
||||
int[] indexes = FindIndexes(cams, camright90);
|
||||
if (indexes.length>0){
|
||||
indexright90 = FindFirstIndex(cams, camright90, indexleft90, indexleft45, indexcenter, indexright45);
|
||||
if (indexright90!=-1) {
|
||||
final int finalindex = indexright90;
|
||||
new Thread(()-> SetupCameraWithController(image5, camright90, finalindex)).start();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
directorypath.setText(config.getPhotoDirectory());
|
||||
|
||||
progressanchor.prefWidthProperty().bind(controlpane.widthProperty());
|
||||
});
|
||||
}
|
||||
|
||||
public void Unload(){
|
||||
|
||||
if (image1!=null) {
|
||||
image1.StopLiveView();
|
||||
}
|
||||
if (image2!=null) {
|
||||
image2.StopLiveView();
|
||||
}
|
||||
if (image3!=null) {
|
||||
image3.StopLiveView();
|
||||
}
|
||||
if (image4!=null) {
|
||||
image4.StopLiveView();
|
||||
}
|
||||
if (image5!=null) {
|
||||
image5.StopLiveView();
|
||||
}
|
||||
config.Save();
|
||||
}
|
||||
|
||||
final PlaybackStatus ps = new PlaybackStatus(){
|
||||
|
||||
@Override
|
||||
public void onPlaybackStarted(String filename) {
|
||||
if (filename.contains(audio_posisikan_muka)){
|
||||
Logger.info("Audio Positikan Muka Started");
|
||||
} else if (filename.contains(audio_posisi_diam)){
|
||||
Logger.info("Audio Posisi Diam Started");
|
||||
} else if (filename.contains(audio_foto_selesai)){
|
||||
Logger.info("Audio Foto Selesai Started");
|
||||
} else if (filename.contains(audio_ke_ruangtunggu)){
|
||||
Logger.info("Audio Ke Ruang Tunggu Started");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlaybackFinished(String filename) {
|
||||
if (filename.contains(audio_posisikan_muka)){
|
||||
Logger.info("Audio Positikan Muka Finished");
|
||||
} else if (filename.contains(audio_posisi_diam)){
|
||||
Logger.info("Audio Posisi Diam Finished");
|
||||
} else if (filename.contains(audio_foto_selesai)){
|
||||
Logger.info("Audio Foto Selesai Finished");
|
||||
} else if (filename.contains(audio_ke_ruangtunggu)){
|
||||
Logger.info("Audio Ke Ruang Tunggu Finished");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlaybackFailure(String filename) {
|
||||
if (filename.contains(audio_posisikan_muka)){
|
||||
Logger.info("Audio Positikan Muka Failure");
|
||||
} else if (filename.contains(audio_posisi_diam)){
|
||||
Logger.info("Audio Posisi Diam Failure");
|
||||
} else if (filename.contains(audio_foto_selesai)){
|
||||
Logger.info("Audio Foto Selesai Failure");
|
||||
} else if (filename.contains(audio_ke_ruangtunggu)){
|
||||
Logger.info("Audio Ke Ruang Tunggu Failure");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private void SetupCameraWithController(Cameradetail image, String cameraname, int devicenumber){
|
||||
if (image!=null){
|
||||
String title = switch(image.getCameraConfigEnum()){
|
||||
case CameraConfigCenter -> "Camera Center";
|
||||
case CameraConfigLeft45 -> "Camera Left 45";
|
||||
case CameraConfigLeft90 -> "Camera Left 90";
|
||||
case CameraConfigRight45 -> "Camera Right 45";
|
||||
case CameraConfigRight90 -> "Camera Right 90";
|
||||
};
|
||||
Platform.runLater(()-> image.setCameraTitle(title));
|
||||
if (devicenumber!=-1){
|
||||
OpenCVFrameGrabber grabber = new OpenCVFrameGrabber(devicenumber);
|
||||
// default
|
||||
int livewidth = 640;
|
||||
int liveheight = 480;
|
||||
int photowidth = 640;
|
||||
int photoheight = 480;
|
||||
|
||||
// mode1 selalu paling tinggi
|
||||
if (cameraname.contains("ACER QHD")){
|
||||
photowidth = AcerQHD.ModeBest.getWidth();
|
||||
photoheight = AcerQHD.ModeBest.getHeight();
|
||||
livewidth = AcerQHD.ModeLive.getWidth();
|
||||
liveheight = AcerQHD.ModeLive.getHeight();
|
||||
} else if (cameraname.contains("AVerVision M15W")){
|
||||
photowidth = AverVisionM15W.ModeBest.getWidth();
|
||||
photoheight = AverVisionM15W.ModeBest.getHeight();
|
||||
livewidth = AverVisionM15W.ModeLive.getWidth();
|
||||
liveheight = AverVisionM15W.ModeLive.getHeight();
|
||||
} else if (cameraname.contains("Arducam IMX477")){
|
||||
// mode1 terbaik 16:9
|
||||
// mode5 terbaik 4:3
|
||||
photowidth = ArducamIMX477.ModeBest.getWidth();
|
||||
photoheight = ArducamIMX477.ModeBest.getHeight();
|
||||
livewidth = ArducamIMX477.ModeLive.getWidth();
|
||||
liveheight = ArducamIMX477.ModeLive.getHeight();
|
||||
} else if (cameraname.contains("OBSBOT Meet 2")){
|
||||
photowidth = ObsbotMeet2.ModeBest.getWidth();
|
||||
photoheight = ObsbotMeet2.ModeBest.getHeight();
|
||||
livewidth = ObsbotMeet2.ModeLive.getWidth();
|
||||
liveheight = ObsbotMeet2.ModeLive.getHeight();
|
||||
}
|
||||
image.SetGrabber(grabber, livewidth,liveheight,photowidth,photoheight);
|
||||
|
||||
//TODO reconfirm requirement again
|
||||
boolean use_face_detector = true;
|
||||
boolean use_qr_detector = true;
|
||||
|
||||
|
||||
|
||||
LiveCamEvent lce = new LiveCamEvent() {
|
||||
@Override
|
||||
public void onDetectedQRCode(String qrCode) {
|
||||
Platform.runLater(()->prefixfile.setText(RemoveSpaces(qrCode)));
|
||||
if (ValidString(qrCode)) audioPlayer.PlayFile(audio_posisikan_muka, ps);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFaceDetector(boolean hasface, int width, int height) {
|
||||
Platform.runLater(()-> {
|
||||
String ss = hasface ? String.format("Camera Started, %dx%d@%d, Face Detected", width, height, image.getLiveFPS()) : String.format("Camera Started, %dx%d@%d", width, height, image.getLiveFPS());
|
||||
image.setCameraStatus(ss);
|
||||
//String qr = prefixfile.getText();
|
||||
//if (ValidString(qr) && hasface) audioPlayer.PlayFile(audio_posisikan_muka, ps);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLog(String log) {
|
||||
String ss = String.format("[%s] : %s", title, log);
|
||||
Logger.info(ss);
|
||||
}
|
||||
};
|
||||
|
||||
Platform.runLater(()-> image.setCameraStatus("Camera Starting"));
|
||||
if (image.StartLiveView(lce, title, use_qr_detector, use_face_detector)){
|
||||
//TODO Start Live View berhasil, apa lagi yang mau dikerjakan ?
|
||||
|
||||
} else Platform.runLater(()->image.setCameraStatus("Unable to Set Grabber"));
|
||||
} else Platform.runLater(()->image.setCameraStatus("Camera not found, please check setting"));
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadCameraDetail(AnchorPane cam, int camid, CameraConfigEnum cc){
|
||||
try{
|
||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("cameradetail.fxml"));
|
||||
AnchorPane child = loader.load();
|
||||
|
||||
AnchorPane.setTopAnchor(child, 0.0);
|
||||
AnchorPane.setBottomAnchor(child, 0.0);
|
||||
AnchorPane.setLeftAnchor(child, 0.0);
|
||||
AnchorPane.setRightAnchor(child, 0.0);
|
||||
|
||||
cam.getChildren().clear();
|
||||
cam.getChildren().add(child);
|
||||
|
||||
|
||||
switch(camid){
|
||||
case 1:
|
||||
image1 = loader.getController();
|
||||
image1.setCameraConfigEnum(cc);
|
||||
break;
|
||||
case 2:
|
||||
image2 = loader.getController();
|
||||
image2.setCameraConfigEnum(cc);
|
||||
break;
|
||||
case 3:
|
||||
image3 = loader.getController();
|
||||
image3.setCameraConfigEnum(cc);
|
||||
break;
|
||||
case 4:
|
||||
image4 = loader.getController();
|
||||
image4.setCameraConfigEnum(cc);
|
||||
break;
|
||||
case 5:
|
||||
image5 = loader.getController();
|
||||
image5.setCameraConfigEnum(cc);
|
||||
break;
|
||||
}
|
||||
|
||||
} catch (Exception e){
|
||||
Logger.error("Error LoadCameraDetail: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void UploadToFTP(String[] files){
|
||||
|
||||
final double uploadprogressheight = 50;
|
||||
Map<String, UploadProgress> progressmap = new HashMap<>();
|
||||
|
||||
for (String filetoupload : files){
|
||||
Task<AnchorPane> loadtask = new Task<>() {
|
||||
@Override
|
||||
protected AnchorPane call() throws Exception {
|
||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("uploadprogress.fxml"));
|
||||
AnchorPane pane = loader.load();
|
||||
pane.prefWidthProperty().bind(progressanchor.widthProperty());
|
||||
pane.setPrefHeight(uploadprogressheight);
|
||||
UploadProgress up = loader.getController();
|
||||
up.SetFile(filetoupload);
|
||||
up.SetStatus("Initialized");
|
||||
up.SetProgress(0,0);
|
||||
int ii = progressmap.size();
|
||||
AnchorPane.setTopAnchor(pane, (ii*uploadprogressheight)+10);
|
||||
progressmap.put(GetFileName(filetoupload), up);
|
||||
return pane;
|
||||
}
|
||||
};
|
||||
loadtask.setOnSucceeded(e-> progressanchor.getChildren().add(loadtask.getValue()));
|
||||
loadtask.setOnFailed(e-> Logger.error("Error LoadTask: {}",e.getSource().getMessage()));
|
||||
|
||||
new Thread(loadtask).start();
|
||||
}
|
||||
|
||||
FTPUpload ftp = new FTPUpload(config.getFTPHost(), toInt(config.getFTPPort()), config.getFTPUser(), config.getFTPPass(), config.getFTPPath());
|
||||
ftp.UploadFile(new FTPUploadEvent() {
|
||||
@Override
|
||||
public void onUploadSuccess(String file) {
|
||||
Logger.info("Upload Success: {}" ,file);
|
||||
UploadProgress up = progressmap.get(GetFileName(file));
|
||||
if (up!=null){
|
||||
Platform.runLater(()->{
|
||||
up.SetStatus("Success");
|
||||
up.SetProgress(1,1);
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUploadFailed(String file) {
|
||||
Logger.info("Upload Failed: {}",file);
|
||||
UploadProgress up = progressmap.get(GetFileName(file));
|
||||
if (up!=null){
|
||||
Platform.runLater(()->{
|
||||
up.SetStatus("Failed");
|
||||
up.SetProgress(0,1);
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUploadProgress(String file, long bytes, long total) {
|
||||
UploadProgress up = progressmap.get(GetFileName(file));
|
||||
if (up!=null){
|
||||
Platform.runLater(()->up.SetProgress(bytes, total));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUploadStarted(String file) {
|
||||
Logger.info("Upload Started: {}",file);
|
||||
UploadProgress up = progressmap.get(GetFileName(file));
|
||||
if (up!=null){
|
||||
Platform.runLater(()->{
|
||||
up.SetStatus("Started");
|
||||
up.SetProgress(0,0);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uploadLog(String msg) {
|
||||
Logger.info("Upload Log: {}",msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUploadFinished(int total, int success, int failed, String[] files) {
|
||||
Logger.info("Upload Finished, Total: {}, Success: {}, Failed: {}", total, success, failed);
|
||||
Platform.runLater(()->{
|
||||
audioPlayer.PlayFile(audio_ke_ruangtunggu, ps);
|
||||
Alert Alert = new Alert(AlertType.INFORMATION);
|
||||
Alert.setTitle("Upload Finished");
|
||||
Alert.setHeaderText("Upload Finished");
|
||||
Alert.setContentText("Total: "+total+"\nSuccess: "+success+"\nFailed: "+failed);
|
||||
Alert.showAndWait();
|
||||
});
|
||||
}
|
||||
}, files);
|
||||
}
|
||||
|
||||
// private void Load_UploadProgress(Map<String, UploadProgress> progressmap, String filename, double uploadprogressheight){
|
||||
// try{
|
||||
// FXMLLoader loader = new FXMLLoader(getClass().getResource("uploadprogress.fxml"));
|
||||
// AnchorPane pane = loader.load();
|
||||
// pane.prefWidthProperty().bind(progressanchor.widthProperty());
|
||||
// pane.setPrefHeight(uploadprogressheight);
|
||||
// UploadProgress up = loader.getController();
|
||||
// up.SetFile(filename);
|
||||
// up.SetStatus("Started");
|
||||
// up.SetProgress(0,0);
|
||||
// int ii = progressmap.size();
|
||||
// AnchorPane.setTopAnchor(pane, (ii*uploadprogressheight)+10);
|
||||
// progressanchor.getChildren().add(pane);
|
||||
// progressmap.put(filename, up);
|
||||
//
|
||||
// } catch (Exception e){
|
||||
// Logger.error("Error loading uploadprogress.fxml: "+e.getMessage());
|
||||
// }
|
||||
// }
|
||||
|
||||
private void InsertSQL(PhotoReviewClass prc){
|
||||
Sqlite sql = new Sqlite();
|
||||
sql.Insert(prc);
|
||||
}
|
||||
}
|
||||
143
src/main/java/id/co/gtc/erhacam/LogsView.java
Normal file
143
src/main/java/id/co/gtc/erhacam/LogsView.java
Normal file
@@ -0,0 +1,143 @@
|
||||
package id.co.gtc.erhacam;
|
||||
|
||||
import Database.TinyLogRow;
|
||||
import javafx.application.Platform;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.control.cell.PropertyValueFactory;
|
||||
import lombok.val;
|
||||
import org.tinylog.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import static Config.SomeCodes.GetLogsPath;
|
||||
|
||||
public class LogsView {
|
||||
|
||||
@FXML
|
||||
private ComboBox<String> datePicker;
|
||||
|
||||
@FXML
|
||||
private TextField searchField;
|
||||
|
||||
@FXML
|
||||
private TableView<TinyLogRow> logTable;
|
||||
|
||||
@FXML
|
||||
private Button PopulateButton;
|
||||
|
||||
private ObservableList<TinyLogRow> tablerows ;
|
||||
|
||||
@FXML
|
||||
private void initialize(){
|
||||
tablerows = FXCollections.observableArrayList();
|
||||
logTable.setItems(tablerows);
|
||||
initialize_tableview();
|
||||
|
||||
|
||||
datePicker.onActionProperty().set(e->{
|
||||
String selected = datePicker.getValue();
|
||||
tablerows.clear();
|
||||
try {
|
||||
AtomicInteger index = new AtomicInteger(1);
|
||||
Files.lines(GetLogsPath().resolve(selected+".log"))
|
||||
.forEachOrdered(l->{
|
||||
TinyLogRow row = TinyLogRow.Regex(l);
|
||||
if (row != null && row.HaveContent()) {
|
||||
row.setIndex(index.getAndIncrement());
|
||||
tablerows.add(row);
|
||||
}
|
||||
});
|
||||
} catch (IOException ex) {
|
||||
Logger.error("datePicker error: {}", ex.getMessage());
|
||||
}
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
PopulateButton.onActionProperty().set(e->{
|
||||
datePicker.getItems().clear();
|
||||
try {
|
||||
Files.list(GetLogsPath())
|
||||
.filter(p -> p.toFile().isFile())
|
||||
.filter(p -> p.getFileName().toString().endsWith(".log"))
|
||||
.forEachOrdered(p->{
|
||||
String ss = p.getFileName().toString();
|
||||
datePicker.getItems().add(ss.substring(0, ss.lastIndexOf('.')));
|
||||
});
|
||||
|
||||
} catch (IOException ex) {
|
||||
Logger.error("PopulateButton error: {}", ex.getMessage());
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
searchField.onKeyTypedProperty().set(e->{
|
||||
String search = searchField.getText().toLowerCase();
|
||||
if (search.length() > 0){
|
||||
ObservableList<TinyLogRow> filtered = FXCollections.observableArrayList();
|
||||
tablerows.forEach(r->{
|
||||
if (r.getMessage().toLowerCase().contains(search)){
|
||||
filtered.add(r);
|
||||
}
|
||||
});
|
||||
logTable.setItems(filtered);
|
||||
} else {
|
||||
logTable.setItems(tablerows);
|
||||
}
|
||||
});
|
||||
|
||||
Platform.runLater(()->{
|
||||
PopulateButton.fire(); // trigger PopulateButton on show
|
||||
});
|
||||
}
|
||||
|
||||
private void initialize_tableview(){
|
||||
logTable.getColumns().clear();
|
||||
|
||||
TableColumn<TinyLogRow,Integer> indexCol = new TableColumn<>("No");
|
||||
indexCol.setCellValueFactory(new PropertyValueFactory<>("index"));
|
||||
|
||||
TableColumn<TinyLogRow,String> datetimeCol = new TableColumn<>("DateTime");
|
||||
datetimeCol.setCellValueFactory(new PropertyValueFactory<>("DateTime"));
|
||||
|
||||
TableColumn<TinyLogRow,String> categoryCol = new TableColumn<>("Category");
|
||||
categoryCol.setCellValueFactory(new PropertyValueFactory<>("Category"));
|
||||
|
||||
TableColumn<TinyLogRow,String> messageCol = new TableColumn<>("Message");
|
||||
messageCol.setCellValueFactory(new PropertyValueFactory<>("Message"));
|
||||
|
||||
|
||||
logTable.getColumns().add(indexCol);
|
||||
logTable.getColumns().add(datetimeCol);
|
||||
logTable.getColumns().add(categoryCol);
|
||||
logTable.getColumns().add(messageCol);
|
||||
|
||||
logTable.widthProperty().addListener((obs, oldVal, newVal)->{
|
||||
double width = (double)newVal;
|
||||
if (width > (75+150+75+100)){
|
||||
// cukup besar, pake patokan
|
||||
indexCol.setPrefWidth(75);
|
||||
datetimeCol.setPrefWidth(150);
|
||||
categoryCol.setPrefWidth(75);
|
||||
messageCol.setPrefWidth(width-300);
|
||||
} else {
|
||||
// kecil, pake persen
|
||||
indexCol.setPrefWidth(width*0.075);
|
||||
datetimeCol.setPrefWidth(width*0.15);
|
||||
categoryCol.setPrefWidth(width*0.075);
|
||||
messageCol.setPrefWidth(width*0.7);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
public void Unload(){
|
||||
|
||||
}
|
||||
}
|
||||
45
src/main/java/id/co/gtc/erhacam/MainApplication.java
Normal file
45
src/main/java/id/co/gtc/erhacam/MainApplication.java
Normal file
@@ -0,0 +1,45 @@
|
||||
package id.co.gtc.erhacam;
|
||||
|
||||
import Config.SomeCodes;
|
||||
import javafx.application.Application;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.geometry.Rectangle2D;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Screen;
|
||||
import javafx.stage.Stage;
|
||||
import org.tinylog.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static Config.SomeCodes.config;
|
||||
|
||||
|
||||
public class MainApplication extends Application {
|
||||
@Override
|
||||
public void start(Stage stage) throws IOException {
|
||||
FXMLLoader fxmlLoader = new FXMLLoader(MainApplication.class.getResource("main-view.fxml"));
|
||||
Screen screen = Screen.getPrimary();
|
||||
Rectangle2D screenbound = screen.getVisualBounds();
|
||||
Scene scene = new Scene(fxmlLoader.load(), screenbound.getWidth(), screenbound.getHeight());
|
||||
stage.setTitle("MultiCam Capture App for ERHA");
|
||||
stage.setScene(scene);
|
||||
stage.setResizable(false);
|
||||
stage.setMaximized(true);
|
||||
stage.setOnCloseRequest(e->{
|
||||
config.Save();
|
||||
MainView mainView = fxmlLoader.getController();
|
||||
mainView.Unload();
|
||||
Logger.info("Application closed");
|
||||
});
|
||||
SomeCodes.LoadQRReader();
|
||||
SomeCodes.LoadFaceDetector();
|
||||
stage.show();
|
||||
Logger.info("Application started");
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
SomeCodes.ExtractResource("/tinylog.properties");
|
||||
launch();
|
||||
|
||||
}
|
||||
}
|
||||
99
src/main/java/id/co/gtc/erhacam/MainView.java
Normal file
99
src/main/java/id/co/gtc/erhacam/MainView.java
Normal file
@@ -0,0 +1,99 @@
|
||||
package id.co.gtc.erhacam;
|
||||
|
||||
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import javafx.scene.layout.Pane;
|
||||
import org.tinylog.Logger;
|
||||
|
||||
import static Config.SomeCodes.ValidString;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class MainView {
|
||||
|
||||
private String currentselected = "";
|
||||
|
||||
@FXML
|
||||
private Pane mainpane;
|
||||
|
||||
@FXML
|
||||
private Button ReviewButton;
|
||||
|
||||
@FXML
|
||||
private Button CaptureButton;
|
||||
|
||||
@FXML
|
||||
private Button SettingButton;
|
||||
|
||||
@FXML
|
||||
private Button LogsButton;
|
||||
|
||||
private Object currentcontroller;
|
||||
|
||||
@FXML
|
||||
private void ReviewClick(ActionEvent event){
|
||||
if (currentselected.equals("review-view.fxml")) return;
|
||||
loadContent("review-view.fxml");
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void CaptureClick(ActionEvent event){
|
||||
if (currentselected.equals("capture-view.fxml")) return;
|
||||
loadContent("capture-view.fxml");
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void SettingClick(ActionEvent event){
|
||||
if (currentselected.equals("setting-view.fxml")) return;
|
||||
loadContent("setting-view.fxml");
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void LogsClick(ActionEvent event){
|
||||
if (currentselected.equals("logs-view.fxml")) return;
|
||||
loadContent("logs-view.fxml");
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void initialize(){
|
||||
ReviewClick(null);
|
||||
}
|
||||
|
||||
public void Unload(){
|
||||
loadContent("");
|
||||
}
|
||||
|
||||
private void loadContent(String fxmlfile){
|
||||
if (currentcontroller!=null){
|
||||
switch (currentcontroller) {
|
||||
case CaptureView captureView -> captureView.Unload();
|
||||
case SettingView settingView -> settingView.Unload();
|
||||
case ReviewView reviewView -> reviewView.Unload();
|
||||
case LogsView logsView -> logsView.Unload();
|
||||
default -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ValidString(fxmlfile)){
|
||||
try {
|
||||
FXMLLoader loader = new FXMLLoader(getClass().getResource(fxmlfile));
|
||||
AnchorPane child = loader.load();
|
||||
AnchorPane.setTopAnchor(child, 0.0);
|
||||
AnchorPane.setRightAnchor(child, 0.0);
|
||||
AnchorPane.setLeftAnchor(child, 0.0);
|
||||
AnchorPane.setBottomAnchor(child, 0.0);
|
||||
mainpane.getChildren().clear();
|
||||
mainpane.getChildren().add(child);
|
||||
currentselected = fxmlfile;
|
||||
currentcontroller = loader.getController();
|
||||
|
||||
} catch (Exception e) {
|
||||
Logger.error("Unable to load " + fxmlfile + ", exception : " + e.getMessage());
|
||||
}
|
||||
} else Logger.info("Not loading empty fxml file");
|
||||
}
|
||||
}
|
||||
91
src/main/java/id/co/gtc/erhacam/PhotoRow.java
Normal file
91
src/main/java/id/co/gtc/erhacam/PhotoRow.java
Normal file
@@ -0,0 +1,91 @@
|
||||
package id.co.gtc.erhacam;
|
||||
|
||||
import Config.SomeCodes;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.layout.HBox;
|
||||
import org.bytedeco.opencv.global.opencv_imgcodecs;
|
||||
import org.bytedeco.opencv.opencv_core.Mat;
|
||||
import org.tinylog.Logger;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static Config.SomeCodes.config;
|
||||
|
||||
public class PhotoRow {
|
||||
@FXML
|
||||
private Label datetime;
|
||||
@FXML
|
||||
private Label prefix;
|
||||
@FXML
|
||||
private HBox photos;
|
||||
|
||||
private final String borderstyle = "-fx-border-color: black; -fx-border-width: 1px;";
|
||||
|
||||
public void setDatetime(String datetime){
|
||||
this.datetime.setText(datetime);
|
||||
this.datetime.setStyle(borderstyle);
|
||||
}
|
||||
|
||||
public void setPrefix(String prefix){
|
||||
this.prefix.setText(prefix);
|
||||
this.prefix.setStyle(borderstyle);
|
||||
}
|
||||
|
||||
public void setPhotos(int width, int height, String... thumbnails){
|
||||
photos.setSpacing(10);
|
||||
for(String photopath : thumbnails){
|
||||
ImageView imgview = createImageView(loadImage(photopath), width, height);
|
||||
if (imgview!=null){
|
||||
photos.getChildren().add(imgview);
|
||||
//HBox.setMargin(imgview, new Insets(5, 5, 5, 5));
|
||||
imgview.setStyle(borderstyle);
|
||||
imgview.setOnMouseClicked(e->{
|
||||
if (e.getClickCount()>=2){
|
||||
File ff = new File(photopath);
|
||||
String hires = Path.of(config.getPhotoDirectory(), ff.getName()).toString();
|
||||
File hiresfile = new File(hires);
|
||||
if (hiresfile.isFile()){
|
||||
SomeCodes.OpenPictureInDefaultViewer(hires);
|
||||
} else {
|
||||
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||
alert.setTitle("Error");
|
||||
alert.setHeaderText("File not found");
|
||||
alert.setContentText("File not found: "+hires);
|
||||
alert.showAndWait();
|
||||
}
|
||||
e.consume();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ImageView createImageView(Image img, int width, int height){
|
||||
if (img!=null){
|
||||
ImageView imgview = new ImageView(img);
|
||||
imgview.prefWidth(width);
|
||||
imgview.prefHeight(height);
|
||||
imgview.setFitHeight(height);
|
||||
imgview.setFitWidth(width);
|
||||
imgview.setPreserveRatio(true);
|
||||
return imgview;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Image loadImage(String photopath){
|
||||
try{
|
||||
Mat mat = opencv_imgcodecs.imread(photopath);
|
||||
return SomeCodes.ConvertToImage(mat, 640,480);
|
||||
} catch (Exception e){
|
||||
Logger.error("Error loading image: " + photopath + ", Msg : " + e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
83
src/main/java/id/co/gtc/erhacam/ReviewView.java
Normal file
83
src/main/java/id/co/gtc/erhacam/ReviewView.java
Normal file
@@ -0,0 +1,83 @@
|
||||
package id.co.gtc.erhacam;
|
||||
|
||||
import Database.PhotoReviewClass;
|
||||
import Database.Sqlite;
|
||||
import javafx.application.Platform;
|
||||
import javafx.concurrent.Task;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import org.tinylog.Logger;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class ReviewView {
|
||||
|
||||
@FXML
|
||||
private AnchorPane mainpane;
|
||||
|
||||
@FXML
|
||||
private AnchorPane reviewpane;
|
||||
|
||||
@FXML
|
||||
public void initialize(){
|
||||
Platform.runLater(()->{
|
||||
reviewpane.prefWidthProperty().bind(mainpane.widthProperty());
|
||||
int height = 120;
|
||||
double factor = 4.0/3.0;
|
||||
Sqlite sql = new Sqlite();
|
||||
PhotoReviewClass[] prcs = sql.GetAll();
|
||||
if (prcs!=null){
|
||||
ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||
for(int ii=0;ii<prcs.length;ii++){
|
||||
PhotoReviewClass prc = prcs[ii];
|
||||
Thumbloader tl = new Thumbloader(prc,ii,height,factor);
|
||||
tl.setOnSucceeded(e->{
|
||||
AnchorPane row = tl.getValue();
|
||||
if (row!=null) reviewpane.getChildren().add(row);
|
||||
});
|
||||
tl.setOnFailed(e-> Logger.error("Thumbloader for "+prc.getPrefix()+" failed, error: "+e.getSource().getException().getMessage()));
|
||||
executor.submit(tl);
|
||||
}
|
||||
executor.shutdown();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// somehow this code is not working, it's not showing the thumbnails
|
||||
private static class Thumbloader extends Task<AnchorPane> {
|
||||
private final PhotoReviewClass prc;
|
||||
private final int height;
|
||||
private final double factor;
|
||||
private final int ii;
|
||||
public Thumbloader(PhotoReviewClass prc, int ii, int height, double factor){
|
||||
this.prc = prc;
|
||||
this.height = height;
|
||||
this.factor = factor;
|
||||
this.ii = ii;
|
||||
|
||||
}
|
||||
@Override
|
||||
protected AnchorPane call() {
|
||||
try{
|
||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("PhotoRow.fxml"));
|
||||
AnchorPane row = loader.load();
|
||||
row.setPrefHeight(height);
|
||||
PhotoRow pr = loader.getController();
|
||||
AnchorPane.setTopAnchor(row, (1.0*ii*height)+5.0);
|
||||
pr.setDatetime(prc.getDateTime());
|
||||
pr.setPrefix(prc.getPrefix());
|
||||
pr.setPhotos((int)(factor*height), height, prc.thumbnails());
|
||||
return row;
|
||||
} catch (Exception e) {
|
||||
System.out.println("Error loading PhotoRow.fxml, error: "+e.getMessage());
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void Unload(){
|
||||
}
|
||||
}
|
||||
215
src/main/java/id/co/gtc/erhacam/SettingView.java
Normal file
215
src/main/java/id/co/gtc/erhacam/SettingView.java
Normal file
@@ -0,0 +1,215 @@
|
||||
package id.co.gtc.erhacam;
|
||||
|
||||
import FTP.FTPCheck;
|
||||
import javafx.application.Platform;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.ComboBox;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.stage.FileChooser;
|
||||
import lombok.val;
|
||||
import org.bytedeco.javacv.VideoInputFrameGrabber;
|
||||
import org.tinylog.Logger;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import static Config.SomeCodes.config;
|
||||
|
||||
public class SettingView {
|
||||
@FXML
|
||||
private TextField AudioPhase1;
|
||||
@FXML
|
||||
private TextField AudioPhase2;
|
||||
@FXML
|
||||
private TextField AudioPhase3;
|
||||
@FXML
|
||||
private TextField AudioPhase4;
|
||||
@FXML
|
||||
private TextField AudioPhase5;
|
||||
|
||||
@FXML
|
||||
private ComboBox<String> CameraLeft90;
|
||||
@FXML
|
||||
private ComboBox<String> CameraLeft45;
|
||||
@FXML
|
||||
private ComboBox<String> CameraCenter;
|
||||
@FXML
|
||||
private ComboBox<String> CameraRight45;
|
||||
@FXML
|
||||
private ComboBox<String> CameraRight90;
|
||||
|
||||
@FXML
|
||||
private TextField FTPHost;
|
||||
@FXML
|
||||
private TextField FTPPort;
|
||||
@FXML
|
||||
private TextField FTPUser;
|
||||
@FXML
|
||||
private TextField FTPPass;
|
||||
@FXML
|
||||
private TextField FTPPath;
|
||||
|
||||
final FileChooser jfc = new FileChooser();
|
||||
|
||||
String[] cameranames = null;
|
||||
|
||||
@FXML
|
||||
public void initialize(){
|
||||
FileChooser.ExtensionFilter filter = new FileChooser.ExtensionFilter("Audio File", "wav","mp3");
|
||||
jfc.setSelectedExtensionFilter(filter);
|
||||
jfc.setTitle("Select Audio File");
|
||||
|
||||
try{
|
||||
cameranames = VideoInputFrameGrabber.getDeviceDescriptions();
|
||||
Logger.info("Found "+cameranames.length+" Cameras");
|
||||
} catch (Exception e){
|
||||
Logger.error("Unable to detect Cameras, Msg : "+e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Platform.runLater(()->{
|
||||
AudioPhase1.setText(config.getAudioPhase1());
|
||||
AudioPhase2.setText(config.getAudioPhase2());
|
||||
AudioPhase3.setText(config.getAudioPhase3());
|
||||
AudioPhase4.setText(config.getAudioPhase4());
|
||||
AudioPhase5.setText(config.getAudioPhase5());
|
||||
|
||||
CameraLeft90.getItems().clear();
|
||||
CameraLeft45.getItems().clear();
|
||||
CameraCenter.getItems().clear();
|
||||
CameraRight45.getItems().clear();
|
||||
CameraRight90.getItems().clear();
|
||||
|
||||
CameraLeft90.getItems().add("");
|
||||
CameraLeft45.getItems().add("");
|
||||
CameraCenter.getItems().add("");
|
||||
CameraRight45.getItems().add("");
|
||||
CameraRight90.getItems().add("");
|
||||
|
||||
for(String camera: cameranames){
|
||||
Logger.info("adding camera : "+camera+" to camera list");
|
||||
CameraLeft90.getItems().add(camera);
|
||||
CameraLeft45.getItems().add(camera);
|
||||
CameraCenter.getItems().add(camera);
|
||||
CameraRight45.getItems().add(camera);
|
||||
CameraRight90.getItems().add(camera);
|
||||
}
|
||||
|
||||
CameraLeft90.setValue(config.getCameraLeft90());
|
||||
CameraLeft45.setValue(config.getCameraLeft45());
|
||||
CameraCenter.setValue(config.getCameraCenter());
|
||||
CameraRight45.setValue(config.getCameraRight45());
|
||||
CameraRight90.setValue(config.getCameraRight90());
|
||||
|
||||
FTPHost.setText(config.getFTPHost());
|
||||
FTPPort.setText(config.getFTPPort());
|
||||
FTPUser.setText(config.getFTPUser());
|
||||
FTPPass.setText(config.getFTPPass());
|
||||
FTPPath.setText(config.getFTPPath());
|
||||
});
|
||||
}
|
||||
|
||||
public void Unload(){
|
||||
config.Save();
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void BrowseAudioPhase1(){
|
||||
File file = jfc.showOpenDialog(null);
|
||||
if (file!=null){
|
||||
config.SetAudioPhase1(file.getAbsolutePath());
|
||||
AudioPhase1.setText(config.getAudioPhase1());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void BrowseAudioPhase2(){
|
||||
File file = jfc.showOpenDialog(null);
|
||||
if (file!=null){
|
||||
config.SetAudioPhase2(file.getAbsolutePath());
|
||||
AudioPhase2.setText(config.getAudioPhase2());
|
||||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void BrowseAudioPhase3(){
|
||||
File file = jfc.showOpenDialog(null);
|
||||
if (file!=null){
|
||||
config.SetAudioPhase3(file.getAbsolutePath());
|
||||
AudioPhase3.setText(config.getAudioPhase3());
|
||||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void BrowseAudioPhase4(){
|
||||
File file = jfc.showOpenDialog(null);
|
||||
if (file!=null){
|
||||
config.SetAudioPhase4(file.getAbsolutePath());
|
||||
AudioPhase4.setText(config.getAudioPhase4());
|
||||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void BrowseAudioPhase5(){
|
||||
File file = jfc.showOpenDialog(null);
|
||||
if (file!=null){
|
||||
config.SetAudioPhase5(file.getAbsolutePath());
|
||||
AudioPhase5.setText(config.getAudioPhase5());
|
||||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void ApplyCameraLeft90(){
|
||||
config.SetCameraLeft90(CameraLeft90.getValue());
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void ApplyCameraLeft45(){
|
||||
config.SetCameraLeft45(CameraLeft45.getValue());
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void ApplyCameraFront(){
|
||||
config.SetCameraCenter(CameraCenter.getValue());
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void ApplyCameraRight45(){
|
||||
config.SetCameraRight45(CameraRight45.getValue());
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void ApplyCameraRight90(){
|
||||
config.SetCameraRight90(CameraRight90.getValue());
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void SaveFTP(){
|
||||
boolean passive = false;
|
||||
FTPCheck ftp = new FTPCheck(FTPHost.getText(),Integer.parseInt(FTPPort.getText()),FTPUser.getText(),FTPPass.getText(),FTPPath.getText(), passive);
|
||||
if (ftp.IsCorrect()){
|
||||
|
||||
config.SetFTPHost(FTPHost.getText());
|
||||
config.SetFTPPort(FTPPort.getText());
|
||||
config.SetFTPUser(FTPUser.getText());
|
||||
config.SetFTPPass(FTPPass.getText());
|
||||
config.SetFTPPath(FTPPath.getText());
|
||||
|
||||
val alert = new Alert(Alert.AlertType.INFORMATION);
|
||||
alert.setTitle("FTP Configuration");
|
||||
alert.setHeaderText("FTP Configuration Saved");
|
||||
alert.setContentText("FTP Configuration Saved Successfully");
|
||||
alert.showAndWait();
|
||||
} else {
|
||||
val alert = new Alert(Alert.AlertType.ERROR);
|
||||
alert.setTitle("FTP Error");
|
||||
alert.setHeaderText("FTP Configuration Error");
|
||||
alert.setContentText("FTP Configuration is incorrect, please check your FTP Configuration");
|
||||
alert.showAndWait();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
60
src/main/java/id/co/gtc/erhacam/UploadProgress.java
Normal file
60
src/main/java/id/co/gtc/erhacam/UploadProgress.java
Normal file
@@ -0,0 +1,60 @@
|
||||
package id.co.gtc.erhacam;
|
||||
|
||||
import javafx.beans.property.DoubleProperty;
|
||||
import javafx.beans.property.SimpleDoubleProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ProgressBar;
|
||||
|
||||
import static Config.SomeCodes.ValidString;
|
||||
|
||||
public class UploadProgress {
|
||||
@FXML
|
||||
private Label labelfile;
|
||||
|
||||
@FXML
|
||||
private Label labelstatus;
|
||||
|
||||
@FXML
|
||||
private ProgressBar progressbar;
|
||||
|
||||
@FXML
|
||||
public void initialize(){
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the filename to be displayed
|
||||
* @param filename the filename to be displayed
|
||||
*/
|
||||
public void SetFile(String filename){
|
||||
if (ValidString(filename)){
|
||||
labelfile.setText(filename);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the status to be displayed
|
||||
* @param status the status to be displayed
|
||||
*/
|
||||
public void SetStatus(String status){
|
||||
if (ValidString(status)){
|
||||
labelstatus.setText(status);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the progress of the upload
|
||||
* @param current the current progress in Bytes
|
||||
* @param total the total progress in Bytes
|
||||
*/
|
||||
public void SetProgress(long current, long total){
|
||||
if (total > 0){
|
||||
progressbar.setProgress((double)current / (double)total);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user