diff --git a/src/main/java/org/jdetect/CameraApp.java b/src/main/java/org/jdetect/CameraApp.java index 64bfb31..ad54282 100644 --- a/src/main/java/org/jdetect/CameraApp.java +++ b/src/main/java/org/jdetect/CameraApp.java @@ -15,6 +15,7 @@ import java.util.ArrayList; import java.util.List; import javax.swing.*; import javax.swing.filechooser.FileNameExtensionFilter; + import org.opencv.core.*; import org.opencv.core.Point; import org.opencv.dnn.Dnn; @@ -47,7 +48,7 @@ public class CameraApp extends JFrame { private List outputLayers; private boolean detectionEnabled = true; private boolean modelLoaded = false; - private int frameCount = 0; + private final int frameCount = 0; private long lastFpsUpdate = System.currentTimeMillis(); public CameraApp() { @@ -245,6 +246,12 @@ public class CameraApp extends JFrame { } private void loadYolo() { + // Try to load from resources first + if (loadYoloFromResources()) { + return; + } + + // Fall back to downloading if not found in resources 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"; @@ -253,47 +260,40 @@ public class CameraApp extends JFrame { String configPath = "./yolov4-tiny.cfg"; String classesPath = "./coco.names"; - boolean filesValid = true; + // Rest of your download logic... + } + + private boolean loadYoloFromResources() { try { - Path path = Paths.get(weightsPath); - if (!Files.exists(path) || Files.size(path) < 10000000) { - filesValid = false; - } - final Path path1 = Paths.get(configPath); - if (!Files.exists(path1) || Files.size(path1) < 10000) { - filesValid = false; - } - final Path path2 = Paths.get(classesPath); - if (!Files.exists(path2) || Files.size(path2) < 1000) { - filesValid = false; - } - } catch (IOException e) { - filesValid = false; - } - if (!filesValid) { - int reply = JOptionPane.showConfirmDialog(this, - "YOLO model files need to be downloaded (~25MB). Continue?", - "Download Files", JOptionPane.YES_NO_OPTION); + // Load the model files from resources + byte[] weights = readResourceToByteArray("/yolov4-tiny.weights"); + byte[] config = readResourceToByteArray("/yolov4-tiny.cfg"); - if (reply == JOptionPane.NO_OPTION) { - statusLabel.setText("Object detection disabled - model not loaded"); - return; + if (weights == null || config == null) { + statusLabel.setText("Model files not found in resources"); + return false; } - downloadYoloFiles(weightsUrl, configUrl, classesUrl); - } + // Create temp files with proper extensions + File weightsFile = File.createTempFile("yolov4-tiny", ".weights"); + File configFile = File.createTempFile("yolov4-tiny", ".cfg"); - try { - net = Dnn.readNetFromDarknet(configPath, weightsPath); + // Write bytes to temp files + Files.write(weightsFile.toPath(), weights); + Files.write(configFile.toPath(), config); - // Try to use GPU if available (OpenCV Java doesn't have CUDA detection, so we'll use CPU) - net.setPreferableBackend(Dnn.DNN_BACKEND_OPENCV); - net.setPreferableTarget(Dnn.DNN_TARGET_CPU); - statusLabel.setText("Using CPU backend"); + // Load the network + net = Dnn.readNetFromDarknet(configFile.getAbsolutePath(), weightsFile.getAbsolutePath()); + + if (net.empty()) { + statusLabel.setText("Failed to load model from resources"); + return false; + } // Load class names classes = new ArrayList<>(); - try (BufferedReader br = new BufferedReader(new FileReader(classesPath))) { + try (InputStream classesStream = getClass().getResourceAsStream("/coco.names"); + BufferedReader br = new BufferedReader(new InputStreamReader(classesStream))) { String line; while ((line = br.readLine()) != null) { classes.add(line.trim()); @@ -302,8 +302,7 @@ public class CameraApp extends JFrame { // Get output layer names List layerNames = net.getLayerNames(); - MatOfInt unconnectedOutLayers = new MatOfInt(); - net.getUnconnectedOutLayers(); + MatOfInt unconnectedOutLayers = net.getUnconnectedOutLayers(); int[] indices = unconnectedOutLayers.toArray(); outputLayers = new ArrayList<>(); @@ -312,15 +311,41 @@ public class CameraApp extends JFrame { } modelLoaded = true; - statusLabel.setText("YOLOv4 model loaded successfully"); + statusLabel.setText("YOLOv4 model loaded from resources"); + return true; } catch (Exception e) { - modelLoaded = false; - statusLabel.setText(String.format("Error loading model: %s", e.getMessage())); - JOptionPane.showMessageDialog(this, "Failed to load object detection model", "Error", JOptionPane.WARNING_MESSAGE); + statusLabel.setText("Error loading model: " + e.getMessage()); + e.printStackTrace(); + return false; } } + private byte [] readResourceToByteArray(String resourcePath) throws IOException { + try (InputStream is = getClass().getResourceAsStream(resourcePath)) { + if (is == null) return null; + return is.readAllBytes(); + } + } + + private boolean validateModel() { + if (net == null || net.empty()) { + statusLabel.setText("Model is empty or not loaded"); + return false; + } + + try { + // Create a dummy blob to test the network + Mat blob = Dnn.blobFromImage(new Mat(416, 416, CvType.CV_8UC3), 1.0/255.0); + net.setInput(blob); + List outs = new ArrayList<>(); + net.forward(outs, outputLayers); + return !outs.isEmpty(); + } catch (Exception e) { + statusLabel.setText("Model validation failed: " + e.getMessage()); + return false; + } + } private void downloadYoloFiles(String weightsUrl, String configUrl, String classesUrl) { String[][] files = { {"yolov4-tiny.weights", weightsUrl}, @@ -437,8 +462,16 @@ public class CameraApp extends JFrame { } public void displayFrame(Mat frame) { + if (frame == null || frame.empty()) { + return; + } + SwingUtilities.invokeLater(() -> { BufferedImage bufferedImage = matToBufferedImage(frame); + if (bufferedImage == null) { + return; + } + ImageIcon imageIcon = new ImageIcon(bufferedImage); // Scale to fit label