0

I am building a application which can show live feed from my webcam. So I have been searching for sample codes as there was no webcam support in JavaFX and finally I found the code (javaFX+ OpenCV). But I am using fxml for my application and the sample code I found is a Non-Fxml.

The following code is the sample code which I am not able to break it into FXML and its controller From here I find 2 ways 1:To break the non-fxml code 2:To use the non-fxml sample code in my application. So is it possible to use the non-FXML java code with the FXML application? or is there any other way?

For those who require webcam support in javaFX this snippet works perfectly fine. The only requirement is OPENCV libraries. Though I cannot take credit for the code. Thank You in advance

package test;

import java.io.ByteArrayInputStream;

import javafx.animation.AnimationTimer; 
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.image.Image;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.videoio.VideoCapture;

public class Camera2 extends Application {

public static void main(String[] args) {
    launch(args);
}
private static final int SCENE_W = 640;
private static final int SCENE_H = 480;


VideoCapture videoCapture;

Canvas canvas;
GraphicsContext g2d;
Stage stage;
AnimationTimer timer;

@Override
public void start(Stage stage) {

    this.stage = stage;

    initOpenCv();

    canvas = new Canvas(SCENE_W, SCENE_H);
    g2d = canvas.getGraphicsContext2D();
    g2d.setStroke(Color.GREEN);

    Group group = new Group(canvas);

    Scene scene = new Scene(group, SCENE_W, SCENE_H);

    stage.setScene(scene);
    stage.setResizable(false);
    stage.show();

    timer = new AnimationTimer() {

        Mat mat = new Mat();

        @Override
        public void handle(long now) {

            videoCapture.read(mat);

            Image image = mat2Image(mat);

            g2d.drawImage(image, 0, 0);

        }
    };
    timer.start();

}

private void initOpenCv() {

    //setLibraryPath();
    System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

    videoCapture = new VideoCapture();
    videoCapture.open(0);

    System.out.println("Camera open: " + videoCapture.isOpened());

    stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
        public void handle(WindowEvent we) {

            timer.stop();
            videoCapture.release();

            System.out.println("Camera released");

        }
    });

}

public static Image mat2Image(Mat mat) {
    MatOfByte buffer = new MatOfByte();
    Imgcodecs.imencode(".png", mat, buffer);
    return new Image(new ByteArrayInputStream(buffer.toArray()));
}

}

I tried using the above code in mycontroller file

public class FXMLDocumentController implements Initializable {

@FXML
private Canvas canvas;

@FXML
private Button button_start;
private static final int SCENE_W = 640;
private static final int SCENE_H = 480;

VideoCapture videoCapture;
GraphicsContext g2d;
Stage stage;
AnimationTimer timer;


@FXML
private void handleButtonAction(ActionEvent event) {

}

@Override
public void initialize(URL url, ResourceBundle rb) {

    //   this.stage = stage;
    initOpenCv();

    canvas = new Canvas(SCENE_W, SCENE_H);
    g2d = canvas.getGraphicsContext2D();
    g2d.setStroke(Color.GREEN);

    Group group = new Group(canvas);

    Scene scene = new Scene(group, SCENE_W, SCENE_H);

    stage.setScene(scene);
    stage.setResizable(false);
    stage.show();

    timer = new AnimationTimer() {

        Mat mat = new Mat();

        @Override
        public void handle(long now) {

            videoCapture.read(mat);

            Image image = mat2Image(mat);

            g2d.drawImage(image, 0, 0);

        }
    };
    timer.start();

}

private void initOpenCv() {

    //setLibraryPath();
    System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

    videoCapture = new VideoCapture();
    videoCapture.open(0);

    System.out.println("Camera open: " + videoCapture.isOpened());

    stage.setOnCloseRequest((WindowEvent we) -> {
        timer.stop();
        videoCapture.release();

        System.out.println("Camera released");
    });

}

But I got the following error

Exception in Application start method
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:389)
at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:328)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767)
Caused by: java.lang.RuntimeException: Exception in Application start method
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:917)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$155(LauncherImpl.java:182)
at java.lang.Thread.run(Thread.java:745)
Caused by: javafx.fxml.LoadException: 
file:/home/anurag/NetBeansProjects/Test2/dist/run1986258874/Test2.jar!/test2/FXMLDocument.fxml

at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2601)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2579)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2441)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3214)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3175)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3148)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3124)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3104)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:3097)
at test2.Test2.start(Test2.java:22)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$162(LauncherImpl.java:863)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$175(PlatformImpl.java:326)
at com.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(PlatformImpl.java:294)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
at com.sun.glass.ui.gtk.GtkApplication.lambda$null$49(GtkApplication.java:139)
... 1 more
Caused by: java.lang.NullPointerException
at test2.FXMLDocumentController.initOpenCv(FXMLDocumentController.java:104)
at test2.FXMLDocumentController.initialize(FXMLDocumentController.java:61)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2548)
... 17 more
Exception running application test2.Test2
  • 1
    You can add non-fxml code in the controller inside `initialize()` method. – ItachiUchiha Dec 22 '15 at 05:37
  • Still I want to try the same code by having a controller and FXML file. Can it be done? If I add it in Initialize() it still uses scene and stage... Though it solves the problem.. but I still want to know for learning purposes. – Anurag Patil Dec 22 '15 at 12:57

1 Answers1

1

I am not sure of what you exactly want, but I guess you can adapt the code you exposed as it is just a Group with a Canvas. For instance :

groupwithcanvas.fxml

<?import javafx.scene.Group?>
<?import javafx.scene.canvas.Canvas?>

<Group xmlns:fx="http://javafx.com/fxml/1" fx:controller="GroupWithCanvasController">
    <Canvas fx:id="myCanvas"></Canvas>
</Group>

GroupWithCanvasController.java

import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.canvas.Canvas;

import java.net.URL;
import java.util.ResourceBundle;

public class GroupWithCanvasController implements Initializable {


    @FXML
    private Canvas myCanvas;


    @Override
    public void initialize(URL location, ResourceBundle resources) {

        // DO STUFFS

    }
}

MainApp.java

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.stage.Stage;


public class MainApp extends Application {


    @Override
    public void start(Stage primaryStage) throws Exception {

        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(MainApp.class.getClassLoader().getResource("groupwithcanvas.fxml"));
        Group group = loader.load();
        Scene scene = new Scene(group);
        primaryStage.setScene(scene);
        primaryStage.show();

    }


    public static void main(String[] args) {
        launch(args);
    }
}

You will have to adapt all the OpenCV logic in initialize() but It should be feasible.

pwillemet
  • 613
  • 5
  • 21