diff --git a/database.db b/database.db
index 27082bd..ca4b785 100644
Binary files a/database.db and b/database.db differ
diff --git a/haarcascades/fist.xml b/haarcascades/fist.xml
deleted file mode 100644
index 7f5b94a..0000000
--- a/haarcascades/fist.xml
+++ /dev/null
@@ -1,3527 +0,0 @@
-
-
-
-
diff --git a/haarcascades/rpalm.xml b/haarcascades/rpalm.xml
deleted file mode 100644
index 3bb96ba..0000000
--- a/haarcascades/rpalm.xml
+++ /dev/null
@@ -1,5211 +0,0 @@
-
-
-
-
diff --git a/out/artifacts/ErhaCam_jar/ErhaCam.jar b/out/artifacts/ErhaCam_jar/ErhaCam.jar
index 13a7a2a..fcfa969 100644
Binary files a/out/artifacts/ErhaCam_jar/ErhaCam.jar and b/out/artifacts/ErhaCam_jar/ErhaCam.jar differ
diff --git a/src/main/java/id/co/gtc/erhacam/AutoCloseAlert.java b/src/main/java/id/co/gtc/erhacam/AutoCloseAlert.java
index 1444bb1..bf0766c 100644
--- a/src/main/java/id/co/gtc/erhacam/AutoCloseAlert.java
+++ b/src/main/java/id/co/gtc/erhacam/AutoCloseAlert.java
@@ -182,19 +182,16 @@ public class AutoCloseAlert {
Timeline timeline = new Timeline();
timeline.getKeyFrames().add(new KeyFrame(Duration.seconds(0), event -> {
- System.out.println("First timeline, showing the alertstage");
alertStage.show();
}));
for(int xx = 0; xx < pictures.length; xx++){
final int index = xx;
timeline.getKeyFrames().add(new KeyFrame(Duration.seconds(seconds*(index+1)), event -> {
- System.out.println("showpicture timeline keyframe "+index);
imageView.setImage(pictures[index]);
}));
}
timeline.getKeyFrames().add(new KeyFrame(Duration.seconds(seconds* (pictures.length+1)), event -> {
- System.out.println("showpicture timeline finished");
alertStage.close();
if (currentAlertStage == alertStage) {
currentAlertStage = null;
@@ -203,11 +200,6 @@ public class AutoCloseAlert {
clear();
}));
timeline.play();
- System.out.println("showpicture timeline play");
-
-
-
-
currentAlertStage = alertStage;
shownTitle = "";
diff --git a/src/main/java/id/co/gtc/erhacam/Cameradetail.java b/src/main/java/id/co/gtc/erhacam/Cameradetail.java
index 9eacd70..447bc47 100644
--- a/src/main/java/id/co/gtc/erhacam/Cameradetail.java
+++ b/src/main/java/id/co/gtc/erhacam/Cameradetail.java
@@ -12,7 +12,6 @@ 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.Slider;
import javafx.scene.image.Image;
@@ -25,6 +24,7 @@ import lombok.Getter;
import lombok.Setter;
import org.bytedeco.javacv.Frame;
+import org.bytedeco.javacv.FrameGrabber;
import org.bytedeco.javacv.OpenCVFrameGrabber;
import org.bytedeco.opencv.global.opencv_core;
import org.bytedeco.opencv.global.opencv_imgcodecs;
@@ -42,13 +42,15 @@ import java.time.LocalDateTime;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
import static Config.SomeCodes.*;
import static id.co.gtc.erhacam.Detectors.*;
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_imgproc.*;
@SuppressWarnings({"unused"})
@@ -65,17 +67,14 @@ 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 CountDownLatch TakingPhoto = null;
+ private final Semaphore IsGrabbingLiveView = new Semaphore(0);
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;
@@ -145,12 +144,27 @@ public class Cameradetail {
int[] paramjpeg = {opencv_imgcodecs.IMWRITE_JPEG_QUALITY, 100};
int[] parampng = {opencv_imgcodecs.IMWRITE_PNG_COMPRESSION, 0};
+ private boolean use_qr = false;
+ private boolean use_face = false;
+
private void setSliderValue(Slider sld, CameraProperty prop, double value){
+
if (sld!=null){
- sld.setMin(prop.Min);
- sld.setMax(prop.Max);
- sld.setValue(value);
+ if (prop!=null){
+ if (Platform.isFxApplicationThread()){
+ sld.setMin(prop.Min);
+ sld.setMax(prop.Max);
+ sld.setValue(value);
+ } else {
+ Platform.runLater(()->{
+ sld.setMin(prop.Min);
+ sld.setMax(prop.Max);
+ sld.setValue(value);
+ });
+ }
+ }
+
}
}
@@ -664,42 +678,49 @@ public class Cameradetail {
if (!ValidDirectory(directory)) directory = currentDirectory;
if (mGrabber!=null){
- while(IsGrabbingLiveView.get()){
- Wait(10);
+ try{
+ // wait if the camera is still capturing
+ IsGrabbingLiveView.acquire();
+ TakingPhoto = new CountDownLatch(1);
+
+
+ if (!BestMat.empty()){
+
+ // save BestMat at quality 9 PNG
+ String filename = GetFullQualityPhotoPath(directory, prefix);
+
+ if (opencv_imgcodecs.imwrite(filename, BestMat, parampng)){
+ result.setFullres(filename);
+ } else System.out.println("TakePhoto failed, Unable to Save FullQUality Photo for camera "+cameratitle.getText());
+
+ String xx = CropBestMat(directory, prefix, BestMatROI);
+ if (ValidFile(xx)) {
+ result.setFullcrop(xx);
+ result.setBestROI(new Rect(BestMatROI.x(), BestMatROI.y(), BestMatROI.width(), BestMatROI.height()));
+ }
+
+
+ // save ReducedMat at 100% JPEG
+ String reducedfilename = GetReducedPhotoPath(directory, prefix);
+ opencv_imgproc.resize(BestMat, ReducedMat, ReducedSize);
+ if (!opencv_imgcodecs.imwrite(reducedfilename, ReducedMat, paramjpeg)){
+ System.out.println("TakePhoto failed, Unable to Save Reduced Photo for camera "+cameratitle.getText());
+ } else result.setCompressedfile(reducedfilename);
+
+ String xy = CropReducedMat(directory, prefix, ReducedMatROI);
+ if (ValidFile(xy)){
+ result.setCompressedcrop(xy);
+ result.setReducedROI(new Rect(ReducedMatROI.x(), ReducedMatROI.y(), ReducedMatROI.width(), ReducedMatROI.height()));
+ }
+
+ } else raise_log("TakePhoto failed, Live View is Empty");
+ } catch (InterruptedException e){
+ System.out.println("TakePhoto IsGrabbingLiveView interrupted");
}
- TakingPhoto.set(true);
- if (!BestMat.empty()){
- // save BestMat at quality 9 PNG
- String filename = GetFullQualityPhotoPath(directory, prefix);
+ TakingPhoto.countDown();
- if (opencv_imgcodecs.imwrite(filename, BestMat, parampng)){
- result.setFullres(filename);
- } else System.out.println("TakePhoto failed, Unable to Save FullQUality Photo for camera "+cameratitle.getText());
-
- String xx = CropBestMat(directory, prefix, BestMatROI);
- if (ValidFile(xx)) {
- result.setFullcrop(xx);
- result.setBestROI(new Rect(BestMatROI.x(), BestMatROI.y(), BestMatROI.width(), BestMatROI.height()));
- }
-
-
- // save ReducedMat at 100% JPEG
- String reducedfilename = GetReducedPhotoPath(directory, prefix);
- opencv_imgproc.resize(BestMat, ReducedMat, ReducedSize);
- if (!opencv_imgcodecs.imwrite(reducedfilename, ReducedMat, paramjpeg)){
- System.out.println("TakePhoto failed, Unable to Save Reduced Photo for camera "+cameratitle.getText());
- } else result.setCompressedfile(reducedfilename);
-
- String xy = CropReducedMat(directory, prefix, ReducedMatROI);
- if (ValidFile(xy)){
- result.setCompressedcrop(xy);
- result.setReducedROI(new Rect(ReducedMatROI.x(), ReducedMatROI.y(), ReducedMatROI.width(), ReducedMatROI.height()));
- }
-
- } else raise_log("TakePhoto failed, Live View is Empty");
} else raise_log("TakePhoto failed, Grabber is null");
- TakingPhoto.set(false);
return result;
}
@@ -766,17 +787,320 @@ public class Cameradetail {
try{
mGrabber.close();
System.out.println("Camera "+cameratitle.getText()+" stopped");
- Platform.runLater(()->setCameraStatus("Camera Stopped"));
+ setCameraStatus("Camera Stopped");
} catch (Exception e){
raise_log("StopLiveView failed, Unable to Stop Camera, Error: " + e.getMessage());
}
}
- TakingPhoto.set(false);
- IsGrabbingLiveView.set(false);
+ TakingPhoto = null;
+ IsGrabbingLiveView.drainPermits();
+
+ // stop FPS calculation
+ timer.cancel();
+ // stop camera capture thread
+ cam_capture.interrupt();
+ // stop qr detection thread
+ qr_detect.interrupt();
+ // stop face detection thread
+ face_detect.interrupt();
}
- public boolean StartLiveView(LiveCamEvent event, String cameratitle, final boolean use_qr , final boolean use_face) {
+ Timer timer = new java.util.Timer();
+ // FPS Calculator
+ AtomicInteger fps = new AtomicInteger(0);
+
+ // use for locking
+ final Object lockObject = new Object();
+
+
+
+ // QR Detection Thread
+ Semaphore qr_semaphore = new Semaphore(0);
+ Thread qr_detect = new Thread(()->{
+ while(Capturing.get()){
+ try {
+ qr_semaphore.acquire();
+ UMat gray;
+ synchronized (lockObject){
+ gray = GrayMat;
+ }
+ String qr = DetectQRFromMat(gray);
+ if (ValidBarCode(qr)){
+ if (event!=null) event.onDetectedQRCode(qr);
+ }
+ } catch (InterruptedException e) {
+ System.out.println(Thread.currentThread().getName()+" interrupted");
+ }
+ }
+ });
+
+ // Face Detection Thread
+ Semaphore face_semaphore = new Semaphore(0);
+ Thread face_detect = new Thread(()->{
+ // eye state = -1 means unknown, 0 means closed, 1 means open
+ final AtomicInteger eye_state = new AtomicInteger(-1);
+ final AtomicBoolean waiting_for_second_blink = new AtomicBoolean(false);
+ final AtomicLong last_blink = new AtomicLong(0);
+ final AtomicInteger no_face_counter = new AtomicInteger(0);
+ final AtomicInteger face_counter = new AtomicInteger(0);
+ final AtomicInteger blink_counter = new AtomicInteger(0);
+ final AtomicInteger no_eye_counter = new AtomicInteger(0);
+ final AtomicInteger have_eye_counter = new AtomicInteger(0);
+ while(Capturing.get()){
+ try {
+ face_semaphore.acquire();
+ UMat gray;
+ synchronized (lockObject){
+ gray = GrayMat;
+ }
+
+ DetectorResult theface = null;
+ boolean have_frontal_face = false;
+ boolean have_left_45_face = false;
+ int _face_width = 0;
+ int _face_height = 0;
+
+ List frontalfaces = HaveFrontalFace(gray);
+ if (!frontalfaces.isEmpty()){
+ for(DetectorResult rect : frontalfaces){
+ if (rect.haveFace() ){
+ rect.FaceRectangle(LiveMat);
+ if (rect.getFaceWidth()>_face_width) _face_width = rect.getFaceWidth();
+ if (rect.getFaceHeight()>_face_height) _face_height = rect.getFaceHeight();
+ theface = rect;
+ have_frontal_face = true;
+ if (rect.haveEyes()){
+ rect.EyesRectangle(LiveMat);
+ }
+ }
+ }
+ } else {
+ // gak punya frontal face
+ // coba cek punya profile left face 45 gak
+ List Left45Faces = HaveLeft45Face(gray);
+ if (!Left45Faces.isEmpty()){
+ for(DetectorResult rect : Left45Faces){
+ if (rect.haveFace()){
+ rect.FaceRectangle(LiveMat);
+ if (rect.getFaceWidth()>_face_width) _face_width = rect.getFaceWidth();
+ if (rect.getFaceHeight()>_face_height) _face_height = rect.getFaceHeight();
+ have_left_45_face = true;
+ if (rect.haveEyes()){
+ rect.EyesRectangle(LiveMat);
+ }
+ }
+ }
+ }
+ }
+
+ if (have_frontal_face){
+ if (face_counter.incrementAndGet()<5) continue;
+ no_face_counter.set(0);
+ if (event!=null) event.onFrontalFaceDetector(true, _face_width, _face_height);
+ LabelVisible(face_indicator,true);
+
+ if (theface.getFace()!=null){
+ LiveMatROI = new Rect(theface.getFace().x(), theface.getFace().y(), theface.getFace().width(), theface.getFace().height());
+ //System.out.println("Frontal Face Detected from camera "+cameratitle+" "+RectToString(LiveMatROI));
+ }
+
+ if (theface.getEyesCount()>=2){
+ // ada mata (buka mata)
+ if (have_eye_counter.incrementAndGet()<5) continue;
+ no_eye_counter.set(0);
+
+ if (event!=null) event.onEyeDetector(true);
+ LabelVisible(eye_indicator,true);
+
+ //System.out.println("Valid Eye Detected from camera "+cameratitle);
+ // Valid eye condition
+
+ if (eye_state.get()!=1){
+ // transisi dari tutup mata ke buka mata
+ if (eye_state.get()==-1) {
+ System.out.println("First Eye Detected from camera "+cameratitle.getText());
+ eye_state.set(1);
+ } else {
+ System.out.println("Transition from close to open eyes");
+ eye_state.set(1);
+
+ blink_counter.incrementAndGet();
+ if (event!=null) event.onBlink(blink_counter.get());
+ LabelSetText(BlinkCounterLabel, String.valueOf(blink_counter.get()),null);
+
+ long now = System.currentTimeMillis();
+ if (waiting_for_second_blink.get()){
+ long diff = now - last_blink.get();
+ // kalau beda waktu antara blink 1 dan blink 2 kurang dari 3 detik
+ if (diff<=3000){
+ System.out.println("Double Blink Detected from camera "+cameratitle.getText());
+ if (event!=null) event.onDoubleBlink((int)diff);
+ }
+ waiting_for_second_blink.set(false);
+ } else {
+ waiting_for_second_blink.set(true);
+ System.out.println("First Blink Detected from camera "+cameratitle.getText());
+ }
+ last_blink.set(now);
+ }
+
+ }
+ } else {
+ // ada muka, tidak ada mata
+ // transisi dari buka mata ke tutup mata
+ if (no_eye_counter.incrementAndGet()<5) continue;
+ have_eye_counter.set(0);
+
+ if (event!=null) event.onEyeDetector(false);
+ LabelVisible(eye_indicator,false);
+ // Valid no eye condition
+
+
+ if (eye_state.get()!=0){
+ System.out.println("Transition from open to close eyes");
+ eye_state.set(0);
+
+ }
+ }
+
+ } else if (have_left_45_face ){
+ if (event!=null) event.onProfileFaceDetector(true, _face_width, _face_height);
+ LabelVisible(face_indicator,true);
+
+
+ } else {
+ // no face detected, but let's not cancel the previous state immediately
+ if (no_face_counter.incrementAndGet()<30) continue;
+ // beneran dianggap no face detected
+ eye_state.set(-1);
+ last_blink.set(0);
+ waiting_for_second_blink.set(false);
+ face_counter.set(0);
+ blink_counter.set(0);
+ no_eye_counter.set(0);
+ have_eye_counter.set(0);
+
+ if (event!=null) {
+ event.onFrontalFaceDetector(false, _face_width, _face_height);
+ event.onProfileFaceDetector(false, _face_width, _face_height);
+ event.onEyeDetector(false);
+ event.onBlink(blink_counter.get());
+
+ LabelSetText(BlinkCounterLabel, "",null);
+ LabelVisible(face_indicator,false);
+ LabelVisible(eye_indicator,false);
+ }
+
+
+ }
+ 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
+ setCameraStream(matToWritableImage(imgmat));
+ //updateValue(matToWritableImage(imgmat));
+ } catch (InterruptedException e) {
+ System.out.println(Thread.currentThread().getName()+" interrupted");
+ }
+ }
+ });
+
+ // Camera Capture Thread
+ Thread cam_capture = new Thread(()->{
+ while (Capturing.get()) {
+ try {
+ // selama proses pengambilan foto, jangan ambil frame
+ if (TakingPhoto!=null) TakingPhoto.await();
+
+ IsGrabbingLiveView.drainPermits();
+ IsGrabbingLiveView.release();
+ //IsGrabbingLiveView.set(true);
+ Frame frame = null;
+ if (Capturing.get()) {
+ try{
+ frame = mGrabber.grab(); // grab frame
+ } catch (FrameGrabber.Exception e){
+ if (Capturing.get()){
+ // kalau ada exception padahal masih capturing. Kalau sudah tidak capturing, tidak peduli
+ if (ValidString(e.getMessage())){
+ String msg = e.getMessage();
+ System.out.println("Exception on "+Thread.currentThread().getName()+" :"+msg);
+ if (msg.contains("start() been called")){
+ if (Capturing.get()){
+ System.out.println("Camera "+Thread.currentThread().getName()+" has been stopped, restarting");
+ mGrabber.close();
+ //Wait(100);
+ mGrabber.start();
+ mGrabber.flush();
+ } else {
+ System.out.println("Camera "+Thread.currentThread().getName()+" has been stopped, not restarting");
+ }
+ }
+ }
+ }
+
+ }
+ }
+
+ //IsGrabbingLiveView.set(false);
+ if (frame==null) continue;
+ Mat mat = matconverter.convert(frame); // convert to Mat
+ fps.incrementAndGet();
+
+ UMat originalmat = new UMat();
+ mat.copyTo(originalmat); // copy to originalmat for using OpenCL
+ if (config.isMirrorCamera()){
+ // revisi 18/03/2025
+ UMat flippedmat = new UMat();
+ opencv_core.flip(originalmat, flippedmat, 0); // flip vertical
+ flippedmat.copyTo(originalmat);
+ flippedmat.close();
+ }
+ if (config.isFlipCamera()){
+ // revisi 18/03/2025
+ UMat flippedmat = new UMat();
+ opencv_core.flip(originalmat, flippedmat, 1); // flip horizontal
+ flippedmat.copyTo(originalmat);
+ flippedmat.close();
+ }
+
+ // rotate 90 degree counter clockwise karena kamera potrait
+ opencv_core.rotate(originalmat, BestMat, opencv_core.ROTATE_90_COUNTERCLOCKWISE);
+
+
+
+ if (!BestMat.empty()) {
+
+ // LiveMat and GrayMat are synchronized
+ synchronized (lockObject){
+ opencv_imgproc.resize(BestMat, LiveMat, LiveSize); // resize to LiveSize
+ opencv_imgproc.cvtColor(LiveMat,GrayMat, COLOR_BGR2GRAY); // convert to grayscale
+ }
+
+ if (use_qr){
+ qr_semaphore.release();
+ }
+ if (use_face){
+ face_semaphore.release();
+ }
+
+
+ }
+ } catch ( FrameGrabber.Exception fe){
+ System.out.println("FrameGrabber Exception in" + Thread.currentThread().getName() + " : " + fe.getMessage());
+ } catch (InterruptedException e) {
+ System.out.println(Thread.currentThread().getName()+" interrupted");
+ } catch (Exception e){
+ System.out.println(Thread.currentThread().getName()+" exception : "+e.getMessage());
+ }
+
+ }
+ });
+
+ public boolean StartLiveView(LiveCamEvent event, String cameratitle, boolean use_qr , boolean use_face) {
this.event = event;
if (mGrabber != null) {
try {
@@ -800,310 +1124,51 @@ public class Cameradetail {
Capturing.set(true);
if (event!=null) event.onStartCapturing();
- Task task = new Task<>() {
+
+
+ TimerTask fpsTask = new TimerTask() {
@Override
- protected Image call() {
- // repeat until capturing is false
- AtomicInteger fps = new AtomicInteger(0);
- // eye state = -1 means unknown, 0 means closed, 1 means open
- final int[] eye_state = {-1};
- final boolean[] waiting_for_second_blink = {false};
- final long[] last_blink = {0};
- final int[] no_face_counter = {0};
- final int[] face_counter = {0};
- final int[] blink_counter = {0};
-
-
- TimerTask fpsTask = new TimerTask() {
- @Override
- public void run() {
- int fpsval = fps.getAndSet(0);
- if (fpsval!=LiveFPS){
- LiveFPS = fpsval;
- if (event!=null) event.onIntervalUpdate();
- AutoCloseAlert.ChangeCamStatus(switch (cameratitle){
- case "01" -> 1;
- case "02" -> 2;
- case "03" -> 3;
- case "04" -> 4;
- case "05" -> 5;
- default -> 0;
- }, LiveFPS>0 );
- }
-
- }
- };
-
-
-
-
-
- Timer timer = new java.util.Timer();
- timer.scheduleAtFixedRate(fpsTask, 1000, 1000);
-
-
-
-
-
-
- while (Capturing.get()) {
- try {
- // selama proses pengambilan foto, jangan ambil frame
- while(TakingPhoto.get() && Capturing.get()){
- Wait(10);
- }
-
- if (!Capturing.get()) return null;
- IsGrabbingLiveView.set(true);
- Frame frame;
- try{
- frame = mGrabber.grab(); // grab frame
- } catch (Exception e){
- frame = null;
-
- if (e.getMessage()!=null && !e.getMessage().isBlank()){
- String msg = e.getMessage();
- if (msg.contains("start() been called")){
- if (Capturing.get()){
- System.out.println("Camera "+cameratitle+" has been stopped, restarting");
- mGrabber.close();
- Wait(100);
- mGrabber.start();
- mGrabber.flush();
- } else {
- System.out.println("Camera "+cameratitle+" has been stopped, not restarting");
- }
- } else System.out.println("Exception on grab frame from camera "+cameratitle+", Message : "+e.getMessage());
- }
- }
- if (frame==null) continue;
- Mat mat = matconverter.convert(frame); // convert to Mat
- fps.incrementAndGet();
-
- UMat originalmat = new UMat();
- mat.copyTo(originalmat); // copy to originalmat for using OpenCL
- if (config.isMirrorCamera()){
- // revisi 18/03/2025
- UMat flippedmat = new UMat();
- opencv_core.flip(originalmat, flippedmat, 0); // flip vertical
- flippedmat.copyTo(originalmat);
- flippedmat.close();
- }
- if (config.isFlipCamera()){
- // revisi 18/03/2025
- UMat flippedmat = new UMat();
- opencv_core.flip(originalmat, flippedmat, 1); // flip horizontal
- flippedmat.copyTo(originalmat);
- flippedmat.close();
- }
-
- // rotate 90 degree counter clockwise karena kamera potrait
- opencv_core.rotate(originalmat, BestMat, opencv_core.ROTATE_90_COUNTERCLOCKWISE);
-
- IsGrabbingLiveView.set(false);
-
- if (!BestMat.empty()) {
- opencv_imgproc.resize(BestMat, LiveMat, LiveSize); // resize to LiveSize
- opencv_imgproc.cvtColor(LiveMat,GrayMat, COLOR_BGR2GRAY); // convert to grayscale
-
- if (use_qr){
- String qr = DetectQRFromMat(GrayMat);
- if (ValidBarCode(qr)){
- qrtext = qr;
- if (event!=null) event.onDetectedQRCode(qrtext);
- }
- }
- if (use_face){
-
- DetectorResult theface = null;
- boolean have_frontal_face = false;
- boolean have_left_45_face = false;
- int _face_width = 0;
- int _face_height = 0;
-
- List frontalfaces = HaveFrontalFace(GrayMat);
- if (!frontalfaces.isEmpty()){
- for(DetectorResult rect : frontalfaces){
- if (rect.haveFace() ){
- rect.FaceRectangle(LiveMat);
- if (rect.getFaceWidth()>_face_width) _face_width = rect.getFaceWidth();
- if (rect.getFaceHeight()>_face_height) _face_height = rect.getFaceHeight();
- theface = rect;
- have_frontal_face = true;
- if (rect.haveEyes()){
- rect.EyesRectangle(LiveMat);
- }
- }
- }
- } else {
- // gak punya frontal face
- // coba cek punya profile left face 45 gak
- List Left45Faces = HaveLeft45Face(GrayMat);
- if (!Left45Faces.isEmpty()){
- for(DetectorResult rect : Left45Faces){
- if (rect.haveFace()){
- if (rect.haveEyes()){
- rect.FaceRectangle(LiveMat);
- rect.EyesRectangle(LiveMat);
- if (rect.getFaceWidth()>_face_width) _face_width = rect.getFaceWidth();
- if (rect.getFaceHeight()>_face_height) _face_height = rect.getFaceHeight();
- have_left_45_face = true;
- }
- }
- }
- }
- }
-
- if (have_frontal_face){
-
- if (face_counter[0]<5){
- face_counter[0]++;
- //System.out.println("Frontal Face Counter = "+face_counter+ " from camera "+cameratitle+" eye count = "+theface.getEyesCount());
- //continue;
- } else {
- no_face_counter[0] = 0;
- if (event!=null) event.onFrontalFaceDetector(true, _face_width, _face_height);
- //LabelVisible(face_indicator,true);
- Platform.runLater(()-> face_indicator.setVisible(true));
-
- if (theface.getFace()!=null){
- LiveMatROI = new Rect(theface.getFace().x(), theface.getFace().y(), theface.getFace().width(), theface.getFace().height());
- //System.out.println("Frontal Face Detected from camera "+cameratitle+" "+RectToString(LiveMatROI));
- }
-
- if (theface.haveEyes()){
- // ada mata (buka mata)
-
- if (event!=null) event.onEyeDetector(true);
- //LabelVisible(eye_indicator,true);
- Platform.runLater(()-> eye_indicator.setVisible(true));
-
- //System.out.println("Valid Eye Detected from camera "+cameratitle);
- // Valid eye condition
-
- if (eye_state[0]!=1){
- // transisi dari tutup mata ke buka mata
- if (eye_state[0]==-1) {
- System.out.println("First Eye Detected from camera "+cameratitle);
- eye_state[0]=1;
- continue;
- } else {
- System.out.println("Transition from close to open eyes");
- eye_state[0] = 1;
-
- blink_counter[0]++;
- if (event!=null) event.onBlink(blink_counter[0]);
- Platform.runLater(()-> BlinkCounterLabel.setText(blink_counter[0]+""));
- //LabelSetText(BlinkCounterLabel, String.valueOf(blink_counter[0]),null);
-
- long now = System.currentTimeMillis();
- if (waiting_for_second_blink[0]){
- long diff = now - last_blink[0];
- // kalau beda waktu antara blink 1 dan blink 2 kurang dari 3 detik
- if (diff<=3000){
- System.out.println("Double Blink Detected from camera "+cameratitle);
- if (event!=null) event.onDoubleBlink((int)diff);
- }
- waiting_for_second_blink[0] = false;
- } else {
- waiting_for_second_blink[0] = true;
- System.out.println("First Blink Detected from camera "+cameratitle);
- }
- last_blink[0] = now;
- }
-
- }
- } else {
- // ada muka, tidak ada mata
- // transisi dari buka mata ke tutup mata
-
- if (event!=null) event.onEyeDetector(false);
- //LabelVisible(eye_indicator,false);
- Platform.runLater(()-> eye_indicator.setVisible(false));
- // Valid no eye condition
-
-
- if (eye_state[0]!=0){
- System.out.println("Transition from open to close eyes");
- eye_state[0] = 0;
-
- }
- }
- }
-
-
- } else if (have_left_45_face ){
- if (event!=null) event.onProfileFaceDetector(true, _face_width, _face_height);
- //LabelVisible(face_indicator,true);
- Platform.runLater(()-> face_indicator.setVisible(true));
-
-
- } else {
- // no face detected, but let's not cancel the previous state immediately
-
- if (no_face_counter[0]<60){
- // toleransi no face selama 60 frame
- no_face_counter[0]++;
- continue;
- } else {
- // beneran dianggap no face detected
- eye_state[0] = -1;
- last_blink[0] = 0;
- waiting_for_second_blink[0] = false;
- face_counter[0] = 0;
- blink_counter[0] = 0;
-
- if (event!=null) {
- event.onFrontalFaceDetector(false, _face_width, _face_height);
- event.onProfileFaceDetector(false, _face_width, _face_height);
- event.onEyeDetector(false);
- event.onBlink(blink_counter[0]);
- Platform.runLater(()->{
- face_indicator.setVisible(false);
- eye_indicator.setVisible(false);
- BlinkCounterLabel.setText("");
- });
- //LabelSetText(BlinkCounterLabel, "",null);
- //LabelVisible(face_indicator,false);
- //LabelVisible(eye_indicator,false);
- }
- }
-
- }
-
- }
-
- 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));
- }
- } catch (Exception e) {
- if (ValidString(e.getMessage())){
- raise_log("Unable to Grab Frame, Error: " + e.getMessage());
- }
- //if (!Capturing.get()) Platform.runLater(this::StopLiveView);
+ public void run() {
+ if (Capturing.get()){
+ int fpsval = fps.getAndSet(0);
+ if (fpsval!=LiveFPS){
+ LiveFPS = fpsval;
+ if (event!=null) event.onIntervalUpdate();
+ AutoCloseAlert.ChangeCamStatus(switch (cameratitle){
+ case "01" -> 1;
+ case "02" -> 2;
+ case "03" -> 3;
+ case "04" -> 4;
+ case "05" -> 5;
+ default -> 0;
+ }, LiveFPS>0 );
}
+ } else {
+ fps.set(0);
+ this.cancel();
}
- timer.cancel();
- return null;
}
};
- // value dari task, yaitu image, akan diupdate ke camerastream
- task.valueProperty().addListener((obs, oldVal, newVal) -> {
- if (newVal != null) {
- setCameraStream(newVal);
- }
- });
+ timer.scheduleAtFixedRate(fpsTask, 1000, 1000);
- // start task
- Thread thread = new Thread(task);
- thread.setDaemon(true);
- thread.start();
+
+ this.use_qr = use_qr;
+ this.use_face = use_face;
+ cam_capture.setName("cam_capture "+cameratitle);
+ cam_capture.setDaemon(true);
+ cam_capture.start();
+ System.out.println("Starting cam_capture thread");
+
+ qr_detect.setName("qr_detect "+cameratitle);
+ qr_detect.setDaemon(true);
+ qr_detect.start();
+ System.out.println("Starting qr_detect thread");
+
+ face_detect.setName("face_detect "+cameratitle);
+ face_detect.setDaemon(true);
+ face_detect.start();
+ System.out.println("Starting face_detect thread");
return true;
} catch (Exception e) {
@@ -1204,14 +1269,6 @@ public class Cameradetail {
}
-
-
-
- private double getBrightnessFromGrayMat(Mat graymat){
- Scalar mean = mean(graymat);
- return mean.get(0);
- }
-
private WritableImage matToWritableImage(Mat mat){
int cols = mat.cols();
int rows = mat.rows();
diff --git a/src/main/java/id/co/gtc/erhacam/CaptureView.java b/src/main/java/id/co/gtc/erhacam/CaptureView.java
index 7a58a76..2c02fab 100644
--- a/src/main/java/id/co/gtc/erhacam/CaptureView.java
+++ b/src/main/java/id/co/gtc/erhacam/CaptureView.java
@@ -227,6 +227,35 @@ public class CaptureView {
}
+ static class CallablePhotoResult implements Callable {
+ private final String directory;
+ private final String prefix;
+ private final Cameradetail image;
+
+ public CallablePhotoResult(String directory, String prefix, Cameradetail image) {
+ this.directory = directory;
+ this.prefix = prefix;
+ this.image = image;
+ }
+
+ @Override
+ public PhotoResult call() {
+ if (image!=null){
+ image.RemapROI(0.1, 0.3, false);
+ double sharpness = CalculateSharpness(image.getGrayMat());
+ image.setSharpness_indicator(sharpness);
+ PhotoResult p = image.TakePhoto(directory, prefix);
+ p.setSharpscore(sharpness);
+ if (ValidFile(p.getFullres())){
+ if (ValidFile(p.getCompressedfile())){
+ return p;
+ }
+ }
+ }
+ return null;
+ }
+ }
+
private void take_photo_lanjutan(String directory, String prefix){
audioPlayer.PlayFile(audio_camera_shutter, null);
Size thumbsize = new Size(160,120);
@@ -238,91 +267,11 @@ public class CaptureView {
ExecutorService executor = Executors.newFixedThreadPool(5);
- Callable task1 = ()->{
- if (image1!=null) {
- image1.RemapROI(0.1,0.3, false);
-
- double sharpness = CalculateSharpness(image1.getGrayMat());
- image1.setSharpness_indicator(sharpness);
- PhotoResult p1 = image1.TakePhoto(directory,prefix);
- p1.setSharpscore(sharpness);
- if (ValidFile(p1.getFullres())){
- if (ValidFile(p1.getCompressedfile())){
- return p1;
- }
- }
- } else System.out.println("Image1 is null");
- return null;
- };
- Callable task2 = ()->{
- if (image2!=null) {
- image2.RemapROI(0.1,0.3, false);
- double sharpness = CalculateSharpness(image2.getGrayMat());
- image2.setSharpness_indicator(sharpness);
- PhotoResult p2 = image2.TakePhoto(directory,prefix);
- p2.setSharpscore(sharpness);
- if (ValidFile(p2.getFullres())){
- if (ValidFile(p2.getCompressedfile())){
- return p2;
- }
- }
- } else System.out.println("Image2 is null");
- return null;
- };
-
- Callable task3 = ()->{
- if (image3!=null) {
- image3.RemapROI(0.1,0.3, false);
- double sharpness = CalculateSharpness(image3.getGrayMat());
- image3.setSharpness_indicator(sharpness);
- PhotoResult p3 = image3.TakePhoto(directory,prefix);
- p3.setSharpscore(sharpness);
-
- if (ValidFile(p3.getFullres())){
- if (ValidFile(p3.getCompressedfile())){
- return p3;
- }
- }
-
- } else System.out.println("Image3 is null");
- return null;
- };
-
- Callable task4 = ()->{
- if (image4!=null) {
- image4.RemapROI(0.1,0.3, false);
- double sharpness = CalculateSharpness(image4.getGrayMat());
- image4.setSharpness_indicator(sharpness);
- PhotoResult p4 = image4.TakePhoto(directory,prefix);
- p4.setSharpscore(sharpness);
-
- if (ValidFile(p4.getFullres())){
- if (ValidFile(p4.getCompressedfile())){
- return p4;
- }
- }
-
- } else System.out.println("Image4 is null");
- return null;
- };
-
- Callable task5 = ()->{
- if (image5!=null) {
- image5.RemapROI(0.1,0.3, false);
- double sharpness = CalculateSharpness(image5.getGrayMat());
- image5.setSharpness_indicator(sharpness);
- PhotoResult p5 = image5.TakePhoto(directory,prefix);
- p5.setSharpscore(sharpness);
-
- if (ValidFile(p5.getFullres())){
- if (ValidFile(p5.getCompressedfile())){
- return p5;
- }
- }
-
- } else System.out.println("Image5 is null");
- return null;
- };
+ CallablePhotoResult task1 = new CallablePhotoResult(directory, prefix, image1);
+ CallablePhotoResult task2 = new CallablePhotoResult(directory, prefix, image2);
+ CallablePhotoResult task3 = new CallablePhotoResult(directory, prefix, image3);
+ CallablePhotoResult task4 = new CallablePhotoResult(directory, prefix, image4);
+ CallablePhotoResult task5 = new CallablePhotoResult(directory, prefix, image5);
PhotoResult p1 = null;
PhotoResult p2 = null;
@@ -943,7 +892,6 @@ public class CaptureView {
PatientRecord pr = checkpatientID.getValue();
if (pr!=null){
int medrecid = toInt(pr.medical_record_detail_id);
- System.out.println("checkpatientID.setOnSucceeded medrecid : "+medrecid);
TextAreaSetText(medicalRecordID,""+medrecid);
TextAreaSetText(PatientName, pr.name);
@@ -1051,25 +999,22 @@ public class CaptureView {
}
private void update_status(Cameradetail image){
- Platform.runLater(()-> {
- String sb = "Camera Started, " +
- image.getBestWidth() +
- "x" +
- image.getBestHeight() +
- "@" +
- image.getLiveFPS();
+ String sb = "Camera Started, " +
+ image.getBestWidth() +
+ "x" +
+ image.getBestHeight() +
+ "@" +
+ image.getLiveFPS();
- image.setCameraStatus(sb);
- });
+ image.setCameraStatus(sb);
}
};
-
- Platform.runLater(()-> image.setCameraStatus("Camera Starting"));
+ 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"));
+ } else image.setCameraStatus("Unable to Set Grabber");
+ } else image.setCameraStatus("Camera not found, please check setting");
}
}
diff --git a/src/main/java/id/co/gtc/erhacam/MainApplication.java b/src/main/java/id/co/gtc/erhacam/MainApplication.java
index b1d87aa..e5887b5 100644
--- a/src/main/java/id/co/gtc/erhacam/MainApplication.java
+++ b/src/main/java/id/co/gtc/erhacam/MainApplication.java
@@ -22,6 +22,9 @@ import static Config.SomeCodes.config;
public class MainApplication extends Application {
@Override
public void start(Stage stage) throws IOException {
+
+
+
SecureDongle sd = new SecureDongle((short)0x4B30, (short)0xA66C, (short)0x3109, (short)0x37B1);
if (sd.Find()){
if (sd.Open()){
@@ -34,7 +37,7 @@ public class MainApplication extends Application {
Screen screen = Screen.getPrimary();
Rectangle2D screenbound = screen.getBounds();
Scene scene = new Scene(fxmlLoader.load(), screenbound.getWidth(), screenbound.getHeight());
- stage.setTitle("MultiCam Capture App for ERHA 10042025-005");
+ stage.setTitle("MultiCam Capture App for ERHA 11042025-003");
stage.setScene(scene);
stage.setResizable(true);
stage.setMaximized(true);