fuck this shit ; i wont fucking maintain this anymore

This commit is contained in:
rattatwinko
2025-05-23 19:29:58 +02:00
parent f2eb9be5d7
commit 9169940214
4 changed files with 772 additions and 197 deletions

View File

@@ -7,6 +7,7 @@ import org.opencv.dnn.Net;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.videoio.VideoCapture;
import org.opencv.videoio.VideoWriter;
import org.opencv.videoio.Videoio;
import javax.swing.*;
@@ -17,15 +18,15 @@ import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.BufferedReader;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.InputStream;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
@@ -106,29 +107,6 @@ class DownloadProgressBar extends JDialog {
}
}
// Download progress handler class
class DownloadProgressHandler {
private DownloadProgressBar progressDialog;
private AtomicLong currentSize = new AtomicLong(0);
private AtomicLong totalSize = new AtomicLong(0);
private AtomicLong lastUpdate = new AtomicLong(0);
public DownloadProgressHandler(DownloadProgressBar progressDialog) {
this.progressDialog = progressDialog;
}
public void handleProgress(long current, long total) {
this.totalSize.set(total);
this.currentSize.set(current);
long currentTime = System.currentTimeMillis();
if (currentTime - lastUpdate.get() > 100) { // Update every 100ms
progressDialog.updateProgress(current, total);
lastUpdate.set(currentTime);
}
}
}
// Detection thread class
class DetectionThread extends Thread {
private Net net;
@@ -258,6 +236,10 @@ public class CameraApp extends JFrame {
private JButton stopButton;
private JButton snapshotButton;
private JLabel statusLabel;
private JPanel cameraControlPanel;
private JSlider brightnessSlider;
private JSlider contrastSlider;
private JSlider saturationSlider;
// Camera and detection attributes
private int cameraIndex = 0;
@@ -303,7 +285,7 @@ public class CameraApp extends JFrame {
private void initUI() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(1000, 800);
setSize(1200, 900);
setLocationRelativeTo(null);
// Main panel
@@ -314,13 +296,16 @@ public class CameraApp extends JFrame {
videoLabel = new JLabel();
videoLabel.setHorizontalAlignment(JLabel.CENTER);
videoLabel.setVerticalAlignment(JLabel.CENTER);
videoLabel.setPreferredSize(new Dimension(640, 480));
videoLabel.setPreferredSize(new Dimension(800, 600));
videoLabel.setBorder(BorderFactory.createLoweredBevelBorder());
videoLabel.setText("Camera feed will appear here");
mainPanel.add(videoLabel, BorderLayout.CENTER);
// Control panel
JPanel controlPanel = new JPanel(new GridBagLayout());
JPanel controlPanel = new JPanel(new BorderLayout());
// Basic controls
JPanel basicControlPanel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(5, 5, 5, 5);
gbc.fill = GridBagConstraints.HORIZONTAL;
@@ -329,30 +314,36 @@ public class CameraApp extends JFrame {
gbc.gridx = 0; gbc.gridy = 0; gbc.gridwidth = 2;
cameraSelect = new JComboBox<>();
cameraSelect.addActionListener(this::changeCamera);
controlPanel.add(cameraSelect, gbc);
basicControlPanel.add(cameraSelect, gbc);
// Detection checkbox
gbc.gridx = 0; gbc.gridy = 1; gbc.gridwidth = 2;
detectionCheckbox = new JCheckBox("Enable Object Detection", true);
detectionCheckbox.addActionListener(this::toggleDetection);
controlPanel.add(detectionCheckbox, gbc);
basicControlPanel.add(detectionCheckbox, gbc);
// Buttons
gbc.gridwidth = 1;
gbc.gridx = 0; gbc.gridy = 2;
startButton = new JButton("Start Camera");
startButton.addActionListener(e -> startCamera());
controlPanel.add(startButton, gbc);
basicControlPanel.add(startButton, gbc);
gbc.gridx = 1; gbc.gridy = 2;
stopButton = new JButton("Stop Camera");
stopButton.addActionListener(e -> stopCamera());
controlPanel.add(stopButton, gbc);
basicControlPanel.add(stopButton, gbc);
gbc.gridx = 0; gbc.gridy = 3; gbc.gridwidth = 2;
snapshotButton = new JButton("Take Snapshot");
snapshotButton.addActionListener(e -> takeSnapshot());
controlPanel.add(snapshotButton, gbc);
basicControlPanel.add(snapshotButton, gbc);
controlPanel.add(basicControlPanel, BorderLayout.NORTH);
// Camera controls panel for C920
cameraControlPanel = createCameraControlPanel();
controlPanel.add(cameraControlPanel, BorderLayout.CENTER);
mainPanel.add(controlPanel, BorderLayout.EAST);
@@ -385,6 +376,82 @@ public class CameraApp extends JFrame {
});
}
private JPanel createCameraControlPanel() {
JPanel panel = new JPanel(new GridBagLayout());
panel.setBorder(BorderFactory.createTitledBorder("Camera Controls"));
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(5, 5, 5, 5);
gbc.fill = GridBagConstraints.HORIZONTAL;
// Brightness control
gbc.gridx = 0; gbc.gridy = 0;
panel.add(new JLabel("Brightness:"), gbc);
gbc.gridx = 1; gbc.gridy = 0;
brightnessSlider = new JSlider(-100, 100, 0);
brightnessSlider.addChangeListener(e -> adjustCameraSettings());
panel.add(brightnessSlider, gbc);
// Contrast control
gbc.gridx = 0; gbc.gridy = 1;
panel.add(new JLabel("Contrast:"), gbc);
gbc.gridx = 1; gbc.gridy = 1;
contrastSlider = new JSlider(0, 200, 100);
contrastSlider.addChangeListener(e -> adjustCameraSettings());
panel.add(contrastSlider, gbc);
// Saturation control
gbc.gridx = 0; gbc.gridy = 2;
panel.add(new JLabel("Saturation:"), gbc);
gbc.gridx = 1; gbc.gridy = 2;
saturationSlider = new JSlider(0, 200, 100);
saturationSlider.addChangeListener(e -> adjustCameraSettings());
panel.add(saturationSlider, gbc);
// Reset button
gbc.gridx = 0; gbc.gridy = 3; gbc.gridwidth = 2;
JButton resetButton = new JButton("Reset to Default");
resetButton.addActionListener(e -> resetCameraSettings());
panel.add(resetButton, gbc);
return panel;
}
private void adjustCameraSettings() {
if (cap == null || !cap.isOpened()) {
return;
}
try {
// Apply brightness (-100 to 100, normalized to 0.0-1.0)
double brightness = (brightnessSlider.getValue() + 100) / 200.0;
cap.set(Videoio.CAP_PROP_BRIGHTNESS, brightness);
// Apply contrast (0 to 200, normalized to 0.0-2.0)
double contrast = contrastSlider.getValue() / 100.0;
cap.set(Videoio.CAP_PROP_CONTRAST, contrast);
// Apply saturation (0 to 200, normalized to 0.0-2.0)
double saturation = saturationSlider.getValue() / 100.0;
cap.set(Videoio.CAP_PROP_SATURATION, saturation);
// Additional C920 specific settings
cap.set(Videoio.CAP_PROP_AUTO_WB, 1); // Enable auto white balance
cap.set(Videoio.CAP_PROP_EXPOSURE, -5); // Set exposure for better indoor lighting
statusLabel.setText("Camera settings adjusted");
} catch (Exception e) {
System.out.println("Warning: Could not adjust all camera settings: " + e.getMessage());
}
}
private void resetCameraSettings() {
brightnessSlider.setValue(0);
contrastSlider.setValue(100);
saturationSlider.setValue(100);
adjustCameraSettings();
}
private void toggleDetection(ActionEvent e) {
detectionEnabled.set(detectionCheckbox.isSelected());
statusLabel.setText("Detection " + (detectionEnabled.get() ? "enabled" : "disabled"));
@@ -461,7 +528,13 @@ public class CameraApp extends JFrame {
selected = availableCameras.get(0);
}
cap = new VideoCapture(selected.index, selected.backend);
// Try to open with default backend first
cap = new VideoCapture(selected.index);
if (!cap.isOpened()) {
// Fall back to selected backend if default fails
cap = new VideoCapture(selected.index, selected.backend);
}
if (!cap.isOpened()) {
JOptionPane.showMessageDialog(this,
String.format("Cannot open camera %d", selected.index),
@@ -470,14 +543,37 @@ public class CameraApp extends JFrame {
return;
}
// Set camera properties
cap.set(Videoio.CAP_PROP_FRAME_WIDTH, 1280);
cap.set(Videoio.CAP_PROP_FRAME_HEIGHT, 720);
cap.set(Videoio.CAP_PROP_FPS, 60);
cap.set(Videoio.CAP_PROP_AUTOFOCUS, 0);
// Enhanced camera settings for C920
try {
// Set resolution - C920 supports up to 1920x1080
cap.set(Videoio.CAP_PROP_FRAME_WIDTH, 1280);
cap.set(Videoio.CAP_PROP_FRAME_HEIGHT, 720);
cap.set(Videoio.CAP_PROP_FPS, 30);
// C920 specific optimizations
cap.set(Videoio.CAP_PROP_FOURCC, VideoWriter.fourcc('M', 'J', 'P', 'G'));
cap.set(Videoio.CAP_PROP_AUTOFOCUS, 1); // Enable autofocus
cap.set(Videoio.CAP_PROP_AUTO_WB, 1); // Auto white balance
cap.set(Videoio.CAP_PROP_AUTO_EXPOSURE, 0.25); // Some auto exposure
cap.set(Videoio.CAP_PROP_EXPOSURE, -5); // Manual exposure for indoor
cap.set(Videoio.CAP_PROP_GAIN, 0); // Minimize gain to reduce noise
// Apply current slider settings
adjustCameraSettings();
} catch (Exception e) {
System.out.println("Warning: Could not set all camera properties: " + e.getMessage());
}
// Get actual settings that were applied
double actualWidth = cap.get(Videoio.CAP_PROP_FRAME_WIDTH);
double actualHeight = cap.get(Videoio.CAP_PROP_FRAME_HEIGHT);
double actualFps = cap.get(Videoio.CAP_PROP_FPS);
statusLabel.setText(String.format("Camera %d started (%dx%d @ %.1f FPS)",
selected.index, (int)actualWidth, (int)actualHeight, actualFps));
timer.start();
statusLabel.setText(String.format("Camera %d started", selected.index));
} catch (Exception ex) {
JOptionPane.showMessageDialog(this,
@@ -503,11 +599,161 @@ public class CameraApp extends JFrame {
}
}
private void loadYolo() {
String weightsUrl = "https://github.com/AlexeyAB/darknet/releases/download/darknet_yolo_v4_pre/yolov4-tiny.weights";
String configUrl = "https://raw.githubusercontent.com/AlexeyAB/darknet/master/cfg/yolov4-tiny.cfg";
String classesUrl = "https://raw.githubusercontent.com/AlexeyAB/darknet/master/data/coco.names";
private void updateFrame(ActionEvent e) {
if (cap == null || !cap.isOpened()) {
return;
}
Mat frame = new Mat();
if (cap.read(frame) && !frame.empty()) {
// Update FPS counter
frameCount++;
long currentTime = System.currentTimeMillis();
if (currentTime - lastFpsUpdate >= 1000) {
fps = frameCount * 1000.0 / (currentTime - lastFpsUpdate);
frameCount = 0;
lastFpsUpdate = currentTime;
}
// Process frame with detection if enabled
if (detectionEnabled.get() && modelLoaded.get()) {
processWithDetection(frame);
} else {
displayFrame(frame);
}
}
}
private void processWithDetection(Mat frame) {
// Stop previous detection if still running
if (detectionThread != null && detectionThread.isAlive()) {
detectionThread.stopDetection();
}
// Start new detection
detectionThread = new DetectionThread(net, classes, outputLayers, frame);
detectionThread.start();
// Get result asynchronously
detectionThread.getDetectionResult().thenAccept(this::displayFrame);
}
private void displayFrame(Mat frame) {
if (frame == null || frame.empty()) {
return;
}
try {
// Add FPS text to frame
String fpsText = String.format("FPS: %.1f", fps);
Point textPos = new Point(10, 30);
Imgproc.putText(frame, fpsText, textPos, Imgproc.FONT_HERSHEY_SIMPLEX, 1, new Scalar(0, 255, 0), 2);
// Convert Mat to BufferedImage
BufferedImage image = matToBufferedImage(frame);
// Scale image to fit label while maintaining aspect ratio
Dimension labelSize = videoLabel.getSize();
if (labelSize.width > 0 && labelSize.height > 0) {
Image scaledImage = image.getScaledInstance(labelSize.width, labelSize.height, Image.SCALE_SMOOTH);
ImageIcon icon = new ImageIcon(scaledImage);
SwingUtilities.invokeLater(() -> videoLabel.setIcon(icon));
}
} catch (Exception ex) {
System.out.println("Error displaying frame: " + ex.getMessage());
}
}
private BufferedImage matToBufferedImage(Mat mat) {
int type = BufferedImage.TYPE_BYTE_GRAY;
if (mat.channels() > 1) {
type = BufferedImage.TYPE_3BYTE_BGR;
}
int bufferSize = mat.channels() * mat.cols() * mat.rows();
byte[] buffer = new byte[bufferSize];
mat.get(0, 0, buffer); // get all pixels
BufferedImage image = new BufferedImage(mat.cols(), mat.rows(), type);
final byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
System.arraycopy(buffer, 0, targetPixels, 0, buffer.length);
return image;
}
private void takeSnapshot() {
if (cap == null || !cap.isOpened()) {
JOptionPane.showMessageDialog(this, "Camera is not active", "Error", JOptionPane.ERROR_MESSAGE);
return;
}
Mat frame = new Mat();
if (cap.read(frame) && !frame.empty()) {
try {
// Create snapshots directory if it doesn't exist
File snapshotDir = new File("snapshots");
if (!snapshotDir.exists()) {
snapshotDir.mkdirs();
}
// Generate filename with timestamp
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
String timestamp = sdf.format(new Date());
String filename = String.format("snapshots/snapshot_%s.jpg", timestamp);
// Save image
Imgcodecs.imwrite(filename, frame);
statusLabel.setText("Snapshot saved: " + filename);
JOptionPane.showMessageDialog(this,
"Snapshot saved successfully!\n" + filename,
"Snapshot", JOptionPane.INFORMATION_MESSAGE);
} catch (Exception ex) {
JOptionPane.showMessageDialog(this,
"Error saving snapshot: " + ex.getMessage(),
"Error", JOptionPane.ERROR_MESSAGE);
}
}
}
private boolean loadYoloFromResources() {
try {
// Check if files exist in resources
InputStream weightsStream = getClass().getResourceAsStream("/yolov4-tiny.weights");
InputStream configStream = getClass().getResourceAsStream("/yolov4-tiny.cfg");
InputStream classesStream = getClass().getResourceAsStream("/coco.names");
if (weightsStream != null && configStream != null && classesStream != null) {
statusLabel.setText("Loading YOLO from resources...");
// Copy files from resources to working directory
Files.copy(weightsStream, Paths.get("yolov4-tiny.weights"), StandardCopyOption.REPLACE_EXISTING);
Files.copy(configStream, Paths.get("yolov4-tiny.cfg"), StandardCopyOption.REPLACE_EXISTING);
Files.copy(classesStream, Paths.get("coco.names"), StandardCopyOption.REPLACE_EXISTING);
weightsStream.close();
configStream.close();
classesStream.close();
statusLabel.setText("YOLO files loaded from resources");
return true;
}
} catch (Exception e) {
System.out.println("Could not load YOLO from resources: " + e.getMessage());
}
return false;
}
private void loadYolo() {
// First try to load from resources
if (loadYoloFromResources()) {
initializeYoloModel();
return;
}
// If not in resources, check existing files
String weightsPath = "yolov4-tiny.weights";
String configPath = "yolov4-tiny.cfg";
String classesPath = "coco.names";
@@ -525,28 +771,45 @@ public class CameraApp extends JFrame {
filesValid = false;
}
if (!filesValid) {
int reply = JOptionPane.showConfirmDialog(this,
"YOLO model files need to be downloaded (~25MB). Continue?",
"Download Files",
JOptionPane.YES_NO_OPTION);
if (reply != JOptionPane.YES_OPTION) {
statusLabel.setText("Object detection disabled - model not loaded");
return;
}
downloadYoloFiles(weightsUrl, configUrl, classesUrl);
if (filesValid) {
initializeYoloModel();
return;
}
// If files don't exist, offer to download
int reply = JOptionPane.showConfirmDialog(this,
"YOLO model files need to be downloaded (~25MB). Continue?",
"Download Files",
JOptionPane.YES_NO_OPTION);
if (reply != JOptionPane.YES_OPTION) {
statusLabel.setText("Object detection disabled - model not loaded");
detectionCheckbox.setSelected(false);
detectionEnabled.set(false);
return;
}
// Download files
String weightsUrl = "https://github.com/AlexeyAB/darknet/releases/download/darknet_yolo_v4_pre/yolov4-tiny.weights";
String configUrl = "https://raw.githubusercontent.com/AlexeyAB/darknet/master/cfg/yolov4-tiny.cfg";
String classesUrl = "https://raw.githubusercontent.com/AlexeyAB/darknet/master/data/coco.names";
downloadYoloFiles(weightsUrl, configUrl, classesUrl);
}
private void initializeYoloModel() {
try {
String weightsPath = "yolov4-tiny.weights";
String configPath = "yolov4-tiny.cfg";
String classesPath = "coco.names";
net = Dnn.readNetFromDarknet(configPath, weightsPath);
// Try to use CUDA if available (OpenCV Java bindings may not support this fully)
// Try to use CUDA if available
try {
net.setPreferableBackend(Dnn.DNN_BACKEND_CUDA);
net.setPreferableTarget(Dnn.DNN_TARGET_CUDA);
statusLabel.setText("Attempting CUDA acceleration");
statusLabel.setText("Using CUDA acceleration");
} catch (Exception e) {
net.setPreferableBackend(Dnn.DNN_BACKEND_OPENCV);
net.setPreferableTarget(Dnn.DNN_TARGET_CPU);
@@ -572,12 +835,16 @@ public class CameraApp extends JFrame {
}
modelLoaded.set(true);
statusLabel.setText("YOLOv4 model loaded successfully");
statusLabel.setText("YOLOv4-Tiny model loaded successfully (" + classes.size() + " classes)");
} catch (Exception e) {
modelLoaded.set(false);
statusLabel.setText("Error loading model: " + e.getMessage());
JOptionPane.showMessageDialog(this, "Failed to load object detection model", "Error", JOptionPane.WARNING_MESSAGE);
JOptionPane.showMessageDialog(this,
"Failed to load object detection model: " + e.getMessage(),
"Error", JOptionPane.WARNING_MESSAGE);
detectionCheckbox.setSelected(false);
detectionEnabled.set(false);
}
}
@@ -601,17 +868,19 @@ public class CameraApp extends JFrame {
// Download in background thread
CompletableFuture.runAsync(() -> {
boolean allSuccess = true;
try {
for (String[] file : files) {
String fileName = file[0];
String url = file[1];
// Check if file already exists and is valid
if (Files.exists(Paths.get(fileName))) {
try {
long size = getFileSize(fileName);
if ((fileName.equals("yolov4-tiny.weights") && size >= 10000000) ||
(fileName.equals("yolov4-tiny.cfg") && size >= 10000) ||
(fileName.equals("coco.names") && size >= 1000)) {
(fileName.equals("yolov4-tiny.cfg") && size >= 1000) ||
(fileName.equals("coco.names") && size >= 500)) {
continue;
}
} catch (Exception e) {
@@ -620,6 +889,7 @@ public class CameraApp extends JFrame {
}
if (progressDialog.isCancelled()) {
allSuccess = false;
break;
}
@@ -631,14 +901,34 @@ public class CameraApp extends JFrame {
System.out.println("Downloaded " + fileName);
} catch (Exception e) {
System.out.println("Error downloading " + fileName + ": " + e.getMessage());
SwingUtilities.invokeLater(() -> {
JOptionPane.showMessageDialog(this, "Failed to download " + fileName, "Error", JOptionPane.ERROR_MESSAGE);
});
allSuccess = false;
break;
}
}
} finally {
SwingUtilities.invokeLater(() -> progressDialog.dispose());
boolean finalAllSuccess = allSuccess;
SwingUtilities.invokeLater(() -> {
progressDialog.dispose();
if (finalAllSuccess && !progressDialog.isCancelled()) {
statusLabel.setText("YOLO files downloaded successfully");
initializeYoloModel();
} else {
statusLabel.setText("Download failed or cancelled");
detectionCheckbox.setSelected(false);
detectionEnabled.set(false);
}
});
} catch (Exception e) {
SwingUtilities.invokeLater(() -> {
progressDialog.dispose();
statusLabel.setText("Download error: " + e.getMessage());
JOptionPane.showMessageDialog(this,
"Download failed: " + e.getMessage(),
"Error", JOptionPane.ERROR_MESSAGE);
detectionCheckbox.setSelected(false);
detectionEnabled.set(false);
});
}
}, executorService);
}
@@ -647,17 +937,25 @@ public class CameraApp extends JFrame {
URL url = new URL(urlString);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.connect();
connection.setConnectTimeout(10000);
connection.setReadTimeout(30000);
int contentLength = connection.getContentLength();
// Set user agent to avoid blocking
connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
int responseCode = connection.getResponseCode();
if (responseCode != HttpURLConnection.HTTP_OK) {
throw new IOException("HTTP error code: " + responseCode);
}
long fileSize = connection.getContentLengthLong();
try (InputStream inputStream = connection.getInputStream();
FileOutputStream outputStream = new FileOutputStream(fileName)) {
byte[] buffer = new byte[8192];
int bytesRead;
long totalBytesRead = 0;
long lastUpdate = 0;
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
if (progressDialog.isCancelled()) {
@@ -667,150 +965,53 @@ public class CameraApp extends JFrame {
outputStream.write(buffer, 0, bytesRead);
totalBytesRead += bytesRead;
long currentTime = System.currentTimeMillis();
if (currentTime - lastUpdate > 100) { // Update every 100ms
progressDialog.updateProgress(totalBytesRead, contentLength);
lastUpdate = currentTime;
if (fileSize > 0) {
progressDialog.updateProgress(totalBytesRead, fileSize);
}
}
}
}
private void updateFrame(ActionEvent e) {
if (cap == null || !cap.isOpened()) {
return;
}
Mat frame = new Mat();
boolean ret = cap.read(frame);
if (!ret || frame.empty()) {
statusLabel.setText("Failed to capture frame");
return;
}
frameCount++;
long currentTime = System.currentTimeMillis();
if (currentTime - lastFpsUpdate >= 1000) {
fps = frameCount * 1000.0 / (currentTime - lastFpsUpdate);
lastFpsUpdate = currentTime;
frameCount = 0;
statusLabel.setText(String.format("Running at %.1f FPS", fps));
}
// Convert BGR to RGB
Mat rgbFrame = new Mat();
Imgproc.cvtColor(frame, rgbFrame, Imgproc.COLOR_BGR2RGB);
if (detectionEnabled.get() && modelLoaded.get()) {
if (detectionThread == null || !detectionThread.isAlive()) {
detectionThread = new DetectionThread(net, classes, outputLayers, rgbFrame);
detectionThread.start();
// Handle detection result asynchronously
detectionThread.getDetectionResult().thenAccept(this::displayFrame);
} else {
displayFrame(rgbFrame);
}
} else {
displayFrame(rgbFrame);
}
}
private void displayFrame(Mat frame) {
SwingUtilities.invokeLater(() -> {
BufferedImage bufferedImage = matToBufferedImage(frame);
if (bufferedImage != null) {
// Scale image to fit label while maintaining aspect ratio
Dimension labelSize = videoLabel.getSize();
ImageIcon scaledIcon = new ImageIcon(bufferedImage.getScaledInstance(
labelSize.width, labelSize.height, Image.SCALE_SMOOTH));
videoLabel.setIcon(scaledIcon);
videoLabel.setText(null);
}
});
}
private BufferedImage matToBufferedImage(Mat mat) {
try {
int type = BufferedImage.TYPE_BYTE_GRAY;
if (mat.channels() > 1) {
type = BufferedImage.TYPE_3BYTE_BGR;
}
int bufferSize = mat.channels() * mat.cols() * mat.rows();
byte[] buffer = new byte[bufferSize];
mat.get(0, 0, buffer); // get all pixels
BufferedImage image = new BufferedImage(mat.cols(), mat.rows(), type);
final byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
System.arraycopy(buffer, 0, targetPixels, 0, buffer.length);
return image;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private void takeSnapshot() {
if (cap == null || !cap.isOpened()) {
JOptionPane.showMessageDialog(this, "No active camera to take snapshot from", "Warning", JOptionPane.WARNING_MESSAGE);
return;
}
Mat frame = new Mat();
boolean ret = cap.read(frame);
if (!ret || frame.empty()) {
JOptionPane.showMessageDialog(this, "Failed to capture frame", "Warning", JOptionPane.WARNING_MESSAGE);
return;
}
JFileChooser fileChooser = new JFileChooser();
fileChooser.setDialogTitle("Save Snapshot");
fileChooser.setFileFilter(new javax.swing.filechooser.FileNameExtensionFilter("JPEG Images", "jpg", "jpeg"));
int result = fileChooser.showSaveDialog(this);
if (result == JFileChooser.APPROVE_OPTION) {
String fileName = fileChooser.getSelectedFile().getAbsolutePath();
if (!fileName.toLowerCase().endsWith(".jpg") && !fileName.toLowerCase().endsWith(".jpeg")) {
fileName += ".jpg";
}
// Convert BGR to RGB for saving
Mat rgbFrame = new Mat();
Imgproc.cvtColor(frame, rgbFrame, Imgproc.COLOR_BGR2RGB);
boolean success = Imgcodecs.imwrite(fileName, rgbFrame);
if (success) {
statusLabel.setText("Snapshot saved to " + fileName);
} else {
JOptionPane.showMessageDialog(this, "Failed to save snapshot", "Error", JOptionPane.WARNING_MESSAGE);
}
}
connection.disconnect();
}
private void closeEvent() {
stopCamera();
if (cap != null) {
cap.release();
}
if (detectionThread != null) {
detectionThread.stopDetection();
}
if (executorService != null) {
executorService.shutdown();
executorService.shutdownNow();
}
System.exit(0);
}
// Main method
public static void main(String[] args) {
try {
// Set system look and feel
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
System.out.println("Could not set system look and feel: " + e.getMessage());
}
SwingUtilities.invokeLater(() -> {
CameraApp app = new CameraApp();
app.setVisible(true);
});
}
}
try {
new CameraApp().setVisible(true);
} catch (Exception e) {
System.err.println("Error starting application: " + e.getMessage());
e.printStackTrace();
JOptionPane.showMessageDialog(null,
"Error starting application:\n" + e.getMessage() +
"\n\nPlease ensure OpenCV is properly installed and configured.",
"Startup Error",
JOptionPane.ERROR_MESSAGE);
System.exit(1);
}
});
}}