package id.co.gtc.erhacam; import Config.SomeCodes; import lombok.NonNull; import org.bytedeco.opencv.opencv_core.*; import org.bytedeco.opencv.opencv_objdetect.CascadeClassifier; import org.tinylog.Logger; import java.util.ArrayList; import java.util.List; public class Detectors { public CascadeClassifier frontalfaceDetector; private CascadeClassifier eyeDetector; private CascadeClassifier profilefaceDetector; private double scaleFactor = 1.05; // revisi 09/05/2025, dari nilai 1.05 private final int minNeighbors = 3; // revisi 09/05/2025, dari nilai 3 private final int flags = 0; private Size FaceminSize; private Size FacemaxSize; public Detectors(){ LoadFrontalFaceDetector(); LoadEyeDetector(); LoadProfileFaceDetector(); } private void LoadFrontalFaceDetector(){ // revisi 09/05/2025, dari filename = SomeCodes.ExtractResource("/haarcascade_frontalface_default.xml"); String filename = SomeCodes.ExtractResource("/haarcascade_frontalface_alt.xml"); if (filename!=null) { try{ frontalfaceDetector = new CascadeClassifier(filename); } catch (Exception e){ Logger.error("Exception on loading FaceDetector : " + e.getMessage()); } } else Logger.error("Unable to extract face detector file"); } private void LoadProfileFaceDetector(){ String filename = SomeCodes.ExtractResource("/haarcascade_profileface.xml"); if (filename!=null) { try{ profilefaceDetector = new CascadeClassifier(filename); } catch (Exception e){ Logger.error("Exception on loading ProfileFaceDetector : " + e.getMessage()); } } else Logger.error("Unable to extract profile face detector file"); } private void LoadEyeDetector(){ String filename = SomeCodes.ExtractResource("/haarcascade_eye.xml"); if (filename!=null) { try{ eyeDetector = new CascadeClassifier(filename); } catch (Exception e){ Logger.error("Exception on loading EyeDetector : " + e.getMessage()); } } else Logger.error("Unable to extract eye detector file"); } /** * Detect if there is a frontal face, containing 2 eyes * @param graymat Mat in Gray Scale * @return List of Rect if face detected, otherwise empty list */ public @NonNull List HaveFrontalFace(Mat graymat){ List result = new ArrayList<>(); //System.out.println("Detecting frontal from "+ graymat.size().width() + "x" + graymat.size().height()); RectVector faces = DetectFrontalFace(graymat); if (faces!=null && faces.size()>0){ //System.out.println("faces size = " + faces.size()); for(Rect face : faces.get()){ RectVector eyes = DetectEye(graymat, face.width()); DetectorResult dr = new DetectorResult(); dr.setFace(face); //System.out.println("eyes size = " + eyes.size()); if (eyes.size()>=2){ for(Rect eye : eyes.get()){ if (SomeCodes.IsInsideRect(eye, face)) { dr.AddEye(eye); } } } result.add(dr); } } //else System.out.println("faces size = 0"); return result; } public @NonNull List HaveLeft45Face(Mat graymat){ List result = new ArrayList<>(); RectVector faces = DetectProfileFace(graymat); if (faces!=null && faces.size()>0){ for(Rect face : faces.get()){ RectVector eyes = DetectEye(graymat, face.width()); DetectorResult dr = new DetectorResult(); dr.setFace(face); if (eyes.size()>0){ for(Rect eye : eyes.get()){ if (SomeCodes.IsInsideRect(eye, face)) dr.AddEye(eye); } } result.add(dr); } } return result; } public void setScaleFactor(double value){ if (scaleFactor!=value) scaleFactor = value; } public void setFaceMinSize(int value){ if (FaceminSize!=null){ if (FaceminSize.width()!=value || FaceminSize.height()!=value) { FaceminSize = new Size(value, value); Logger.info("FaceMinSize changed to : " + FaceminSize.width()); } } else { FaceminSize = new Size(value, value); Logger.info("FaceMinSize created with value : " + FaceminSize.width()); } } public void setFaceMaxSize(int value){ if (FacemaxSize!=null){ if (FacemaxSize.width()!=value || FacemaxSize.height()!=value) { FacemaxSize = new Size(value, value); Logger.info("FaceMaxSize changed to : " + FacemaxSize.width()); } } else { FacemaxSize = new Size(value, value); Logger.info("FaceMaxSize created with value : " + FacemaxSize.width()); } } public RectVector DetectProfileFace(Mat graymat){ return Detect(graymat, profilefaceDetector, scaleFactor, minNeighbors, flags, FaceminSize, FacemaxSize); } /** * Detect Face from Mat * @param graymat Mat in Gray Scale * @return RectVector if face detected, otherwise null */ public RectVector DetectFrontalFace(Mat graymat){ return Detect(graymat, frontalfaceDetector, scaleFactor, minNeighbors, flags, FaceminSize, FacemaxSize); } /** * Detect Eye from Mat * If Eye detected, it will return RectVector with size is number of eyes detected * @param graymat Mat in Gray Scale * @return RectVector if eye detected, otherwise null */ public RectVector DetectEye(Mat graymat, int facewidth){ //return Detect(graymat, eyeDetector); int minwidth = (int)(facewidth*0.2); int maxwidth = (int)(facewidth*0.4); Size minsize = new Size(minwidth, minwidth); Size maxsize = new Size(maxwidth, maxwidth); //System.out.println("Detecting Eye with minsize = " + minsize.width() + "x" + minsize.height() + ", maxsize = " + maxsize.width() + "x" + maxsize.height()); return Detect(graymat, eyeDetector, scaleFactor, minNeighbors, flags, minsize, maxsize); } @SuppressWarnings("SameParameterValue") private RectVector Detect(Mat graymat, CascadeClassifier detector, double scaleFactor, int minNeighbors, int flags, Size minSize, Size maxSize){ if (detector!=null && !detector.empty()){ if (graymat!=null && graymat.channels()==1 && !graymat.empty()){ if (minSize!=null && maxSize!=null){ if (minSize.width()< maxSize.width() && minSize.height() < maxSize.height()){ if (graymat.cols()> minSize.width() && graymat.rows() > minSize.height()) { try { RectVector detected = new RectVector(); // try defaulting minSize and maxSize detector.detectMultiScale(graymat, detected, scaleFactor, minNeighbors, flags, minSize, new Size()); return detected; } catch (Exception e) { System.out.println("Detectors Detect Error, Message : " + e.getMessage()); } } else System.out.println("graymat is smaller than minSize"); } else System.out.println("minSize is larger than maxSize"); } else System.out.println("minSize or maxSize is null"); } else System.out.println("graymat is null, not 1 channel, or empty"); } else System.out.println("detector empty"); return null; } }