Files
ErhaCam/src/main/java/id/co/gtc/erhacam/Detectors.java
2025-08-18 16:27:27 +07:00

206 lines
7.9 KiB
Java

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<DetectorResult> HaveFrontalFace(Mat graymat){
List<DetectorResult> 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<DetectorResult> HaveLeft45Face(Mat graymat){
List<DetectorResult> 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;
}
}