Improvement 21/01/2025
This commit is contained in:
@@ -23,8 +23,10 @@ import javafx.scene.image.WritableImage;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import org.bytedeco.javacv.Frame;
|
||||
import org.bytedeco.javacv.OpenCVFrameGrabber;
|
||||
import org.bytedeco.opencv.global.opencv_core;
|
||||
import org.bytedeco.opencv.global.opencv_imgcodecs;
|
||||
import org.bytedeco.opencv.global.opencv_imgproc;
|
||||
import org.bytedeco.opencv.opencv_core.*;
|
||||
@@ -42,6 +44,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import static Config.SomeCodes.*;
|
||||
import static id.co.gtc.erhacam.Detectors.faceDetector;
|
||||
import static id.co.gtc.erhacam.Detectors.eyeDetector;
|
||||
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;
|
||||
@@ -49,6 +53,15 @@ import static org.bytedeco.opencv.global.opencv_imgproc.*;
|
||||
|
||||
@SuppressWarnings({"unused"})
|
||||
public class Cameradetail {
|
||||
private static final boolean isCudaAvailable ;
|
||||
static{
|
||||
isCudaAvailable = opencv_core.getCudaEnabledDeviceCount()>0;
|
||||
if (isCudaAvailable){
|
||||
System.out.println("CUDA is available");
|
||||
} else {
|
||||
System.out.println("CUDA is not available");
|
||||
}
|
||||
}
|
||||
private final AtomicBoolean Capturing = new AtomicBoolean(false);
|
||||
private final AtomicBoolean TakingPhoto = new AtomicBoolean(false);
|
||||
private final AtomicBoolean IsGrabbingLiveView = new AtomicBoolean(false);
|
||||
@@ -87,7 +100,6 @@ public class Cameradetail {
|
||||
@FXML
|
||||
private Slider exposureSlider;
|
||||
|
||||
|
||||
private final UMat BestMat = new UMat();
|
||||
private final UMat LiveMat = new UMat();
|
||||
private final UMat ReducedMat = new UMat();
|
||||
@@ -95,6 +107,14 @@ public class Cameradetail {
|
||||
private Size ReducedSize = new Size(1280, 720);
|
||||
private Size BestSize = new Size(1920, 1080);
|
||||
|
||||
public int getBestWidth(){
|
||||
return BestSize.width();
|
||||
}
|
||||
|
||||
public int getBestHeight(){
|
||||
return BestSize.height();
|
||||
}
|
||||
|
||||
private void setSliderValue(Slider sld, CameraProperty prop, double value){
|
||||
if (sld!=null){
|
||||
sld.setMin(prop.Min);
|
||||
@@ -621,6 +641,9 @@ public class Cameradetail {
|
||||
protected Image call() {
|
||||
// repeat until capturing is false
|
||||
AtomicInteger fps = new AtomicInteger(0);
|
||||
AtomicBoolean eye_was_closed = new AtomicBoolean(false);
|
||||
AtomicInteger blink_counter = new AtomicInteger(0);
|
||||
|
||||
TimerTask timerTask = new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -640,8 +663,8 @@ public class Cameradetail {
|
||||
IsGrabbingLiveView.set(true);
|
||||
Frame frame = mGrabber.grab(); // grab frame
|
||||
Mat mat = matconverter.convert(frame); // convert to Mat
|
||||
if (mat.empty()) continue; // kalau gak ada data, continue
|
||||
int counter = fps.incrementAndGet();
|
||||
if (mat.empty()) continue; // kalau gak ada data, continue
|
||||
if (counter % 5 != 0) continue; // frame skip to 6 fps
|
||||
|
||||
mat.copyTo(BestMat); // copy to BestMat for using OpenCL
|
||||
@@ -664,12 +687,47 @@ public class Cameradetail {
|
||||
if (use_face){
|
||||
RectVector face = DetectFace(graymat);
|
||||
if (face!=null && face.size()>0){
|
||||
// ada muka
|
||||
if (event!=null) event.onFaceDetector(true, BestSize.width(), BestSize.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, BestSize.width(), BestSize.height());
|
||||
|
||||
// kalau detect muka, baru coba detect mata
|
||||
RectVector eye = DetectEye(graymat);
|
||||
if (eye!=null && eye.size()>=2){
|
||||
// ada mata
|
||||
if (eye_was_closed.get()){
|
||||
eye_was_closed.set(false);
|
||||
if (blink_counter.get()>=2){
|
||||
blink_counter.set(0);
|
||||
if (event!=null) event.onBlink(blink_counter.get());
|
||||
}
|
||||
}
|
||||
|
||||
if (event!=null) event.onEyeDetector(true, BestSize.width(), BestSize.height());
|
||||
for(int i=0; i<eye.size(); i++){
|
||||
Rect rect = eye.get(i);
|
||||
rectangle(LiveMat, rect, Scalar.RED);
|
||||
}
|
||||
} else {
|
||||
// mata tidak ada
|
||||
if (!eye_was_closed.get()){
|
||||
eye_was_closed.set(true);
|
||||
blink_counter.incrementAndGet();
|
||||
}
|
||||
if (event!=null) event.onEyeDetector(false, BestSize.width(), BestSize.height());
|
||||
}
|
||||
|
||||
} else {
|
||||
eye_was_closed.set(false);
|
||||
blink_counter.set(0);
|
||||
// tidak ada muka, tidak ada mata
|
||||
if (event!=null) event.onFaceDetector(false, BestSize.width(), BestSize.height());
|
||||
if (event!=null) event.onEyeDetector(false, BestSize.width(), BestSize.height());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -747,6 +805,15 @@ public class Cameradetail {
|
||||
return null;
|
||||
}
|
||||
|
||||
private RectVector DetectEye(UMat graymat){
|
||||
if (eyeDetector!=null){
|
||||
RectVector eye = new RectVector();
|
||||
eyeDetector.detectMultiScale(graymat, eye);
|
||||
return eye;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private double getBrightnessFromGrayMat(Mat graymat){
|
||||
Scalar mean = mean(graymat);
|
||||
return mean.get(0);
|
||||
|
||||
@@ -68,6 +68,8 @@ public class CaptureView {
|
||||
private List<String> cams;
|
||||
|
||||
private final AtomicBoolean[] have_face = new AtomicBoolean[5];
|
||||
private final AtomicBoolean[] have_eyes = new AtomicBoolean[5];
|
||||
private final AtomicBoolean isTakingPhoto = new AtomicBoolean(false);
|
||||
|
||||
@FXML
|
||||
private void ChangeDirectory(){
|
||||
@@ -116,6 +118,7 @@ public class CaptureView {
|
||||
String prefix = RemoveSpaces(prefixfile.getText()) ;
|
||||
if (ValidDirectory(directory)){
|
||||
if (ValidString(prefix)){
|
||||
isTakingPhoto.set(true);
|
||||
//audioPlayer.PlayFile(audio_posisi_diam, ps);
|
||||
PhotoReviewClass prc = new PhotoReviewClass();
|
||||
prc.setPrefix(prefix);
|
||||
@@ -211,6 +214,8 @@ public class CaptureView {
|
||||
long duration = (System.nanoTime() - nanostart) / 1000000; // in milliseconds
|
||||
System.out.println("TakePhotos duration: "+duration+" ms");
|
||||
|
||||
// TODO test taruh sini
|
||||
isTakingPhoto.set(false);
|
||||
|
||||
audioPlayer.PlayFile(audio_foto_selesai, ps);
|
||||
String[] files = prc.files();
|
||||
@@ -458,6 +463,14 @@ public class CaptureView {
|
||||
case CameraConfigRight90 -> have_face[4];
|
||||
};
|
||||
|
||||
final AtomicBoolean _have_eye = switch (image.getCameraConfigEnum()){
|
||||
case CameraConfigCenter -> have_eyes[2];
|
||||
case CameraConfigLeft45 -> have_eyes[1];
|
||||
case CameraConfigLeft90 -> have_eyes[0];
|
||||
case CameraConfigRight45 -> have_eyes[3];
|
||||
case CameraConfigRight90 -> have_eyes[4];
|
||||
};
|
||||
|
||||
Platform.runLater(()-> image.setCameraTitle(title));
|
||||
if (devicenumber!=-1){
|
||||
OpenCVFrameGrabber grabber = new OpenCVFrameGrabber(devicenumber);
|
||||
@@ -497,13 +510,9 @@ public class CaptureView {
|
||||
}
|
||||
image.SetGrabber(grabber, livewidth,liveheight,photowidth,photoheight,reducewidth,reduceheight);
|
||||
|
||||
//TODO reconfirm requirement again
|
||||
boolean use_face_detector = true;
|
||||
boolean use_qr_detector = true;
|
||||
|
||||
|
||||
|
||||
|
||||
LiveCamEvent lce = new LiveCamEvent() {
|
||||
@Override
|
||||
public void onDetectedQRCode(String qrCode) {
|
||||
@@ -513,13 +522,14 @@ public class CaptureView {
|
||||
|
||||
@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);
|
||||
_have_face.set(hasface);
|
||||
_have_face.set(hasface);
|
||||
update_status(image);
|
||||
}
|
||||
|
||||
//if (ValidString(qr) && hasface) audioPlayer.PlayFile(audio_posisikan_muka, ps);
|
||||
});
|
||||
@Override
|
||||
public void onEyeDetector(boolean hasEye, int width, int height) {
|
||||
_have_eye.set(hasEye);
|
||||
update_status(image);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -527,6 +537,31 @@ public class CaptureView {
|
||||
String ss = String.format("[%s] : %s", title, log);
|
||||
Logger.info(ss);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlink(int counter) {
|
||||
String prefix = prefixfile.getText();
|
||||
if (!prefix.isEmpty()){
|
||||
if (isTakingPhoto.get()) return; // other camera already detect blinking
|
||||
btnTakePhoto.fire();
|
||||
}
|
||||
}
|
||||
|
||||
private void update_status(Cameradetail image){
|
||||
Platform.runLater(()-> {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Camera Started, ");
|
||||
sb.append(image.getBestWidth());
|
||||
sb.append("x");
|
||||
sb.append(image.getBestHeight());
|
||||
sb.append("@");
|
||||
sb.append(image.getLiveFPS());
|
||||
if (_have_face.get()) sb.append(", Face Detected");
|
||||
if (_have_eye.get()) sb.append(", Eye Detected");
|
||||
|
||||
image.setCameraStatus(sb.toString());
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Platform.runLater(()-> image.setCameraStatus("Camera Starting"));
|
||||
@@ -542,7 +577,7 @@ public class CaptureView {
|
||||
try{
|
||||
|
||||
have_face[camid-1] = new AtomicBoolean(false);
|
||||
|
||||
have_eyes[camid-1] = new AtomicBoolean(false);
|
||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("cameradetail.fxml"));
|
||||
AnchorPane child = loader.load();
|
||||
|
||||
|
||||
44
src/main/java/id/co/gtc/erhacam/Detectors.java
Normal file
44
src/main/java/id/co/gtc/erhacam/Detectors.java
Normal file
@@ -0,0 +1,44 @@
|
||||
package id.co.gtc.erhacam;
|
||||
|
||||
import Config.SomeCodes;
|
||||
import org.bytedeco.opencv.opencv_objdetect.CascadeClassifier;
|
||||
import org.bytedeco.opencv.opencv_objdetect.CvHaarClassifierCascade;
|
||||
import org.tinylog.Logger;
|
||||
|
||||
public class Detectors {
|
||||
public static CascadeClassifier faceDetector;
|
||||
public static CascadeClassifier eyeDetector;
|
||||
public static void LoadFaceDetector(){
|
||||
String filename = SomeCodes.ExtractResource("/haarcascade_profileface.xml");
|
||||
if (filename!=null) {
|
||||
System.out.println("Face Detector file : " + filename);
|
||||
if (faceDetector==null) {
|
||||
try{
|
||||
faceDetector = new CascadeClassifier(filename);
|
||||
Logger.info("FaceDetector loaded");
|
||||
} catch (Exception e){
|
||||
Logger.error("Exception on loading FaceDetector : " + e.getMessage());
|
||||
}
|
||||
|
||||
} else Logger.info("FaceDetector already loaded");
|
||||
} else Logger.error("Unable to extract face detector file");
|
||||
}
|
||||
|
||||
public static void LoadEyeDetector(){
|
||||
String filename = SomeCodes.ExtractResource("/haarcascade_eye_tree_eyeglasses.xml");
|
||||
if (filename!=null) {
|
||||
System.out.println("Eye Detector file : " + filename);
|
||||
if (eyeDetector==null) {
|
||||
try{
|
||||
|
||||
eyeDetector = new CascadeClassifier(filename);
|
||||
Logger.info("EyeDetector loaded");
|
||||
} catch (Exception e){
|
||||
Logger.error("Exception on loading EyeDetector : " + e.getMessage());
|
||||
}
|
||||
|
||||
} else Logger.info("EyeDetector already loaded");
|
||||
} else Logger.error("Unable to extract eye detector file");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -32,7 +32,8 @@ public class MainApplication extends Application {
|
||||
Logger.info("Application closed");
|
||||
});
|
||||
SomeCodes.LoadQRReader();
|
||||
SomeCodes.LoadFaceDetector();
|
||||
Detectors.LoadFaceDetector();
|
||||
Detectors.LoadEyeDetector();
|
||||
stage.show();
|
||||
Logger.info("Application started");
|
||||
}
|
||||
|
||||
8
src/main/java/id/co/gtc/erhacam/MatType.java
Normal file
8
src/main/java/id/co/gtc/erhacam/MatType.java
Normal file
@@ -0,0 +1,8 @@
|
||||
package id.co.gtc.erhacam;
|
||||
|
||||
import org.bytedeco.opencv.opencv_core.Mat;
|
||||
|
||||
public interface MatType {
|
||||
void CopyFrom(Mat src);
|
||||
void CopyTo(Mat dest);
|
||||
}
|
||||
Reference in New Issue
Block a user