Commit 19022025

This commit is contained in:
2025-02-19 10:14:10 +07:00
parent 64f5b619b7
commit b248c59e32
8 changed files with 24886 additions and 251 deletions

View File

@@ -4,7 +4,6 @@ import Camera.CameraProperty;
import Camera.LiveCamEvent;
import Camera.ObsbotMeet2Preset;
import Config.CameraConfigEnum;
import Config.SomeCodes;
import ErhaAPI.PhotoResult;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.NotFoundException;
@@ -102,22 +101,20 @@ 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();
private @Getter final UMat BestMat = new UMat();
private @Getter final UMat LiveMat = new UMat();
private @Getter final UMat ReducedMat = new UMat();
private @Getter Rect BestMatROI;
private @Getter Rect ReducedMatROI;
private @Getter Rect LiveMatROI;
// private Size LiveSize = new Size(640, 360);
// private Size ReducedSize = new Size(1280, 720);
// private Size BestSize = new Size(1920, 1080);
private boolean IsPortrait = false;
// putar portrait
private Size LiveSize = new Size(360, 640);
private Size ReducedSize = new Size(720, 1280);
private Size BestSize = new Size(2160, 3840);
private @Getter Size LiveSize = new Size(360, 640);
private @Getter Size ReducedSize = new Size(720, 1280);
private @Getter Size BestSize = new Size(2160, 3840);
//TODO ini angka dari Erha, cek apakah masih cocok atau tidak
private @Getter @Setter Size FullCropSize = new Size(1036,1036);
@@ -130,6 +127,8 @@ public class Cameradetail {
return BestSize.height();
}
int[] paramjpeg = {opencv_imgcodecs.IMWRITE_JPEG_QUALITY, 100};
int[] parampng = {opencv_imgcodecs.IMWRITE_PNG_COMPRESSION, 0};
private void setSliderValue(Slider sld, CameraProperty prop, double value){
@@ -358,7 +357,9 @@ public class Cameradetail {
StopLiveView();
}
if (isPotrait){
IsPortrait = isPotrait;
if (IsPortrait){
// putar portrait
LiveSize = new Size(liveheight, livewidth);
BestSize = new Size(photoheight, photowidth);
@@ -554,17 +555,85 @@ public class Cameradetail {
return 0;
}
public boolean PutText(String filename, String text, double fontScale, Scalar textColor, int thickness){
if (ValidString(filename)){
Mat mat = opencv_imgcodecs.imread(filename);
if (PutText(mat, text, fontScale, textColor, thickness)){
return opencv_imgcodecs.imwrite(filename, mat);
}
}
return false;
}
public boolean PutText(UMat Mat, String text, double fontScale, Scalar textColor, int thickness){
if (!Mat.empty()){
if (text!=null && !text.isEmpty()){
//String timestamp = prefix+" "+SomeCodes.GetDateTimeString();
int fontFace = FONT_HERSHEY_SIMPLEX;
//double fontScale = 4.0;
//int thickness = 2;
//Scalar textColor = new Scalar(255, 255, 255, 0); // white color in BGR format
int[] baseline = {0};
Size textSize = getTextSize(text, fontFace, fontScale, thickness, baseline);
// position of the text in the bottom right corner
int textX = Mat.cols() - textSize.width() - 10; // 10 pixels from the right
int textY = Mat.rows() - 10; // 10 pixels from the bottom
opencv_imgproc.putText(Mat, text, new Point(textX, textY), fontFace, fontScale, textColor, thickness, LINE_8, false);
return true;
}
}
return false;
}
public boolean PutText(Mat Mat, String text, double fontScale, Scalar textColor, int thickness){
if (!Mat.empty()){
if (text!=null && !text.isEmpty()){
//String timestamp = prefix+" "+SomeCodes.GetDateTimeString();
int fontFace = FONT_HERSHEY_SIMPLEX;
//double fontScale = 4.0;
//int thickness = 2;
//Scalar textColor = new Scalar(255, 255, 255, 0); // white color in BGR format
int[] baseline = {0};
Size textSize = getTextSize(text, fontFace, fontScale, thickness, baseline);
// position of the text in the bottom right corner
int textX = Mat.cols() - textSize.width() - 10; // 10 pixels from the right
int textY = Mat.rows() - 10; // 10 pixels from the bottom
opencv_imgproc.putText(Mat, text, new Point(textX, textY), fontFace, fontScale, textColor, thickness, LINE_8, false);
return true;
}
}
return false;
}
public String GetFullQualityPhotoPath(String directory, String prefix){
if (!ValidDirectory(directory)) directory = currentDirectory;
return Path.of(directory, "FullQuality", makeFileName(prefix,".png")).toString();
}
public String GetReducedPhotoPath(String directory, String prefix){
if (!ValidDirectory(directory)) directory = currentDirectory;
return Path.of(directory, "Compressed", makeReducedFileName(prefix,".jpg")).toString();
}
public String GetFullQualityCropPhotoPath(String directory, String prefix){
if (!ValidDirectory(directory)) directory = currentDirectory;
return Path.of(directory, "FullQualityCrop", makeFileName(prefix,".png")).toString();
}
public String GetReducedCropPhotoPath(String directory, String prefix){
if (!ValidDirectory(directory)) directory = currentDirectory;
return Path.of(directory, "CompressedCrop", makeReducedFileName(prefix,".jpg")).toString();
}
/**
* Take Photo from Camera
* @param directory directory to save the photo, if null, will use default directory
* @param prefix filename prefix
* @param ROI_Full Region of Interest for Full Quality Photo. If Null, will not save cropped photo
* @param ROI_Compressed Region of Interest for Compressed Photo. If Null, will not save cropped photo
* @return filename path of the saved photo, or null if failed
*/
public PhotoResult TakePhoto(String directory, String prefix, Rect ROI_Full, Rect ROI_Compressed) throws InterruptedException {
public PhotoResult TakePhoto(String directory, String prefix) throws InterruptedException {
PhotoResult result = new PhotoResult(cameratitle.getText());
if (!ValidDirectory(directory)) directory = currentDirectory;
@@ -577,50 +646,64 @@ public class Cameradetail {
Size sz = BestMat.size();
raise_log("TakePhoto got frame with width: " + sz.width() + " and height: " + sz.height());
String timestamp = prefix+" "+SomeCodes.GetDateTimeString();
int fontFace = FONT_HERSHEY_SIMPLEX;
double fontScale = 4.0;
int thickness = 2;
Scalar textColor = new Scalar(255, 255, 255, 0); // white color in BGR format
int[] baseline = {0};
Size textSize = getTextSize(timestamp, fontFace, fontScale, thickness, baseline);
// position of the text in the bottom right corner
int textX = BestMat.cols() - textSize.width() - 10; // 10 pixels from the right
int textY = BestMat.rows() - 10; // 10 pixels from the bottom
opencv_imgproc.putText(BestMat, timestamp, new Point(textX, textY), fontFace, fontScale, textColor, thickness, opencv_imgproc.LINE_AA, false);
// String timestamp = prefix+" "+SomeCodes.GetDateTimeString();
// Scalar color = new Scalar(255, 255, 255, 0); // white
// PutText(BestMat, timestamp, 4.0, color, 2);
int[] paramjpeg = {opencv_imgcodecs.IMWRITE_JPEG_QUALITY, 100};
int[] parampng = {opencv_imgcodecs.IMWRITE_PNG_COMPRESSION, 0};
// save BestMat at quality 9 PNG
String filename = Path.of(directory, "FullQuality", makeFileName(prefix,".png")).toString();
if (imwrite(filename, BestMat, parampng)){
String filename = GetFullQualityCropPhotoPath(directory, prefix);
//String filename = Path.of(directory, "FullQuality", makeFileName(prefix,".png")).toString();
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());
UMat FullCrop = CropUMat(BestMat, ROI_Full);
if (FullCrop!=null){
String roifilename = Path.of(directory, "FullQualityCrop", makeFileName(prefix,".png")).toString();
if (!imwrite(roifilename, FullCrop, parampng)){
System.out.println("TakePhoto failed, Unable to Save FullQUalityCrop for camera "+cameratitle.getText());
} else result.setFullcrop(roifilename);
String xx = CropBestMat(directory, prefix, BestMatROI);
if (ValidFile(xx)) {
result.setFullcrop(xx);
result.setBestROI(new Rect(BestMatROI.x(), BestMatROI.y(), BestMatROI.width(), BestMatROI.height()));
}
// if (BestMatROI!=null){
// UMat FullCrop = CropUMat(BestMat, BestMatROI);
// if (FullCrop!=null){
// //String roifilename = Path.of(directory, "FullQualityCrop", makeFileName(prefix,".png")).toString();
// String roifilename = GetFullQualityCropPhotoPath(directory, prefix);
// if (!opencv_imgcodecs.imwrite(roifilename, FullCrop, parampng)){
// System.out.println("TakePhoto failed, Unable to Save FullQUalityCrop for camera "+cameratitle.getText());
// } else {
// result.setFullcrop(roifilename);
// result.setBestROI(new Rect(BestMatROI.x(), BestMatROI.y(), BestMatROI.width(), BestMatROI.height()));
// }
// }
// }
// save ReducedMat at 100% JPEG
String reducedfilename = Path.of(directory, "Compressed", makeReducedFileName(prefix,".jpg")).toString();
//String reducedfilename = Path.of(directory, "Compressed", makeReducedFileName(prefix,".jpg")).toString();
String reducedfilename = GetReducedPhotoPath(directory, prefix);
opencv_imgproc.resize(BestMat, ReducedMat, ReducedSize);
if (!imwrite(reducedfilename, ReducedMat, paramjpeg)){
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);
UMat CompressedCrop = CropUMat(ReducedMat, ROI_Compressed);
if (CompressedCrop!=null){
String roifilename = Path.of(directory, "CompressedCrop", makeReducedFileName(prefix,".jpg")).toString();
if (!imwrite(roifilename, CompressedCrop, paramjpeg)){
System.out.println("TakePhoto failed, Unable to Save CompressedCrop for camera "+cameratitle.getText());
} else result.setCompressedcrop(roifilename);
String xy = CropReducedMat(directory, prefix, ReducedMatROI);
if (ValidFile(xy)){
result.setCompressedcrop(xy);
result.setReducedROI(new Rect(ReducedMatROI.x(), ReducedMatROI.y(), ReducedMatROI.width(), ReducedMatROI.height()));
}
// if (ReducedMatROI!=null){
// UMat ReducedCrop = CropUMat(ReducedMat, ReducedMatROI);
// if (ReducedCrop!=null){
// //String roifilename = Path.of(directory, "CompressedCrop", makeReducedFileName(prefix,".jpg")).toString();
// String roifilename = GetReducedCropPhotoPath(directory, prefix);
// if (!opencv_imgcodecs.imwrite(roifilename, ReducedCrop, paramjpeg)){
// System.out.println("TakePhoto failed, Unable to Save CompressedCrop for camera "+cameratitle.getText());
// } else {
// result.setCompressedcrop(roifilename);
// 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");
@@ -628,6 +711,44 @@ public class Cameradetail {
return result;
}
public String CropBestMat(String directory, String prefix, Rect ROI){
if (!BestMat.empty()) {
if (ValidROI(ROI)){
if (ROIInsideUMat(ROI, BestMat)){
UMat cropped = CropUMat(BestMat, ROI);
if (cropped != null) {
String filename = GetFullQualityCropPhotoPath(directory, prefix);
if (opencv_imgcodecs.imwrite(filename, cropped, parampng)) {
System.out.println("CropBestMat success, saved as " + filename);
Wait(500);
return filename;
} //else System.out.println("CropBestMat failed, Unable to Save BestMat");
} //else System.out.println("CropBestMat failed, Unable to Crop BestMat");
} //else System.out.println("CropBestMat failed, ROI is outside BestMat");
} //else System.out.println("CropBestMat failed, ROI is invalid");
} //else System.out.println("CropBestMat failed, BestMat is empty");
return null;
}
public String CropReducedMat(String directory, String prefix, Rect ROI){
if (!ReducedMat.empty()){
if (ValidROI(ROI)){
if (ROIInsideUMat(ROI,ReducedMat)){
UMat cropped = CropUMat(ReducedMat, ROI);
if (cropped!=null){
String filename = GetReducedCropPhotoPath(directory, prefix);
if (opencv_imgcodecs.imwrite(filename, cropped, paramjpeg)){
System.out.println("CropReducedMat success, saved as "+filename);
Wait(100);
return filename;
} //else System.out.println("CropReducedMat failed, Unable to Save ReducedMat");
} //else System.out.println("CropReducedMat failed, Unable to Crop ReducedMat");
} //else System.out.println("CropReducedMat failed, ROI is outside ReducedMat");
} //else System.out.println("CropReducedMat failed, ROI is invalid");
} //else System.out.println("CropReducedMat failed, ReducedMat is empty");
return null;
}
@@ -660,6 +781,33 @@ public class Cameradetail {
IsGrabbingLiveView.set(false);
}
public Rect GetFace(UMat mat, boolean isfrontal){
if (!mat.empty()){
Mat originalmat = new Mat();
mat.copyTo(originalmat);
Mat graymat = new Mat();
opencv_imgproc.cvtColor(originalmat,graymat, COLOR_BGR2GRAY); // convert to grayscale
int size = Math.min(graymat.cols(), graymat.rows());
int minsize = (int) (size * 0.4);
int maxsize = (int) (size * 0.9);
System.out.println("GetFace size = "+size+" minsize = "+minsize+" maxsize = "+maxsize);
RectVector faces = isfrontal ? Detectors.DetectFrontalFace(graymat, minsize, maxsize) : Detectors.DetectProfileFace(graymat, minsize, maxsize);
if (faces.size()>0){
Rect result = null;
for(Rect xx : faces.get()){
if (result==null){
result = xx;
} else {
if (xx.area()>result.area()){
result = xx;
}
}
}
return result;
}
} else raise_log("GetFace failed, Mat is empty");
return null;
}
public boolean StartLiveView(LiveCamEvent event, String cameratitle, final boolean use_qr , final boolean use_face) {
this.event = event;
@@ -669,8 +817,13 @@ public class Cameradetail {
if (use_qr) raise_log("QR Reader loaded");
if (use_face) raise_log("Face detector loaded");
// capture with best resolution
setFrameHeight(BestSize.height());
setFrameWidth(BestSize.width());
if (IsPortrait){
setFrameHeight(BestSize.width());
setFrameWidth(BestSize.height());
} else {
setFrameHeight(BestSize.height());
setFrameWidth(BestSize.width());
}
LiveFPS = 0;
mGrabber.start();
@@ -749,10 +902,8 @@ public class Cameradetail {
if (use_qr){
String qr = DetectQRFromMat(graymat);
if (ValidBarCode(qr)){
if (!qr.equals(qrtext)){
qrtext = qr;
if (event!=null) event.onDetectedQRCode(qrtext);
}
qrtext = qr;
if (event!=null) event.onDetectedQRCode(qrtext);
}
}
if (use_face){
@@ -803,7 +954,12 @@ public class Cameradetail {
no_face_counter = 0;
if (event!=null) event.onFrontalFaceDetector(true, _face_width, _face_height);
LiveMatROI = theface.getFace();
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 (eye_state==0){
@@ -838,12 +994,8 @@ public class Cameradetail {
} else if (have_left_45_face ){
no_face_counter = 0;
LiveMatROI = theface.getFace();
if (event!=null) event.onProfileFaceDetector(true, _face_width, _face_height);
} else {
// no face detected, but let's not cancel the previous state immediately
@@ -917,30 +1069,58 @@ public class Cameradetail {
/**
* Remap LiveMatROI to BestMatROI and ReducedMatROI Resolution
* @param scale scale factor, 1.0 for 100%, 0.5 for 50%, etc
* @param scaleX scale factor for width
* @param scaleY scale factor for height
*/
public void RemapROI(double scale){
public void RemapROI(double scaleX, double scaleY){
BestMatROI = null;
ReducedMatROI = null;
if (ValidROI(LiveMatROI)){
if (ROIInsideUMat(LiveMatROI, LiveMat)){
System.out.println("LiveMatROI camera "+cameratitle.getText()+" = "+RectToString(LiveMatROI));
double scaleXBest = scale*BestSize.width()/LiveSize.width();
double scaleYBest = scale*BestSize.height()/LiveSize.height();
double scaleXBest = 1.0*BestSize.width()/LiveSize.width();
double scaleYBest = 1.0*BestSize.height()/LiveSize.height();
int XBest = (int) (LiveMatROI.x()*scaleXBest);
int YBest = (int) (LiveMatROI.y()*scaleYBest);
int WBest = (int) (LiveMatROI.width()*scaleXBest);
int HBest = (int) (LiveMatROI.height()*scaleYBest);
int deltaWBest = (int) (BestSize.width() * scaleX);
int deltaHBest = (int) (BestSize.height() * scaleY);
XBest = XBest - deltaWBest/2;
if (XBest<0) XBest = 0;
YBest = YBest - deltaHBest/2;
if (YBest<0) YBest = 0;
WBest = WBest + deltaWBest;
if (WBest>BestSize.width()) WBest = BestSize.width();
HBest = HBest + deltaHBest;
if (HBest>BestSize.height()) HBest = BestSize.height();
BestMatROI = new Rect(XBest, YBest, WBest, HBest);
System.out.println("scaleXBest = "+scaleXBest+" scaleYBest = "+scaleYBest);
double scaleXReduced = scale*ReducedSize.width()/LiveSize.width();
double scaleYReduced = scale*ReducedSize.height()/LiveSize.height();
System.out.println("scaleXReduced = "+scaleXReduced+" scaleYReduced = "+scaleYReduced);
BestMatROI = ResizeRect(LiveMatROI, scaleXBest, scaleYBest, 50,250);
System.out.println("BestMatROI camera "+cameratitle.getText()+" = "+RectToString(BestMatROI));
ReducedMatROI = ResizeRect(LiveMatROI, scaleXReduced, scaleYReduced, 50,250);
double scaleXReduced = 1.0*ReducedSize.width()/LiveSize.width();
double scaleYReduced = 1.0*ReducedSize.height()/LiveSize.height();
int XReduced = (int) (LiveMatROI.x()*scaleXReduced);
int YReduced = (int) (LiveMatROI.y()*scaleYReduced);
int WReduced = (int) (LiveMatROI.width()*scaleXReduced);
int HReduced = (int) (LiveMatROI.height()*scaleYReduced);
int deltaWReduced = (int) (ReducedSize.width() * scaleX);
int deltaHReduced = (int) (ReducedSize.height() * scaleY);
XReduced = XReduced - deltaWReduced/2;
if (XReduced<0) XReduced = 0;
YReduced = YReduced - deltaHReduced/2;
if (YReduced<0) YReduced = 0;
WReduced = WReduced + deltaWReduced;
if (WReduced>ReducedSize.width()) WReduced = ReducedSize.width();
HReduced = HReduced + deltaHReduced;
if (HReduced>ReducedSize.height()) HReduced = ReducedSize.height();
ReducedMatROI = new Rect(XReduced, YReduced, WReduced, HReduced);
System.out.println("scaleXReduced = "+scaleXReduced+" scaleYReduced = "+scaleYReduced);
System.out.println("ReducedMatROI camera "+cameratitle.getText()+" = "+RectToString(ReducedMatROI));
} else {
System.out.println("LiveMatROI is Outside LiveMat for camera "+cameratitle.getText());
LiveMatROI = null;
}
} else System.out.println("LiveMatROI is invalid for camera "+cameratitle.getText());
} //else System.out.println("LiveMatROI is Outside LiveMat for camera "+cameratitle.getText());
} //else System.out.println("LiveMatROI is invalid for camera "+cameratitle.getText());
}