Skip to content
This repository has been archived by the owner on Feb 21, 2021. It is now read-only.

Commit

Permalink
update to Java 8 and improve the conversion between Mat and Image
Browse files Browse the repository at this point in the history
  • Loading branch information
luigidr committed Mar 10, 2017
1 parent 3569a0e commit 1ff61b2
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 29 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

*Computer Vision course - [Politecnico di Torino](http://www.polito.it)*

A project, made in Eclipse (Mars), for capturing a video from a webcam and manipulating its frames: add a logo in the corner of the video player, convert the video in grayscale, and show the histogram of each frame.
A project, made in Eclipse (Neon), for capturing a video from a webcam and manipulating its frames: add a logo in the corner of the video player, convert the video in grayscale, and show the histogram of each frame.

Please, note that the project is an Eclipse project, made for teaching purposes. Before using it, you need to install the OpenCV library (version 3.0) and JavaFX (version 2 or superior) and create a `User Library` named `opencv` that links to the OpenCV jar and native libraries.
Please, note that the project is an Eclipse project, made for teaching purposes. Before using it, you need to install the OpenCV library (version 3.x) and JavaFX 8 and create a `User Library` named `opencv` that links to the OpenCV jar and native libraries.

A guide for getting started with OpenCV and Java is available at [http://opencv-java-tutorials.readthedocs.org/en/latest/index.html](http://opencv-java-tutorials.readthedocs.org/en/latest/index.html).
89 changes: 89 additions & 0 deletions src/it/polito/elite/teaching/cv/utils/Utils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package it.polito.elite.teaching.cv.utils;

import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;

import org.opencv.core.Mat;

import javafx.application.Platform;
import javafx.beans.property.ObjectProperty;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.image.Image;

/**
* Provide general purpose methods for handling OpenCV-JavaFX data conversion.
* Moreover, expose some "low level" methods for matching few JavaFX behavior.
*
* @author <a href="mailto:luigi.derussis@polito.it">Luigi De Russis</a>
* @author <a href="http://max-z.de">Maximilian Zuleger</a>
* @version 1.0 (2016-09-17)
* @since 1.0
*
*/
public final class Utils
{
/**
* Convert a Mat object (OpenCV) in the corresponding Image for JavaFX
*
* @param frame
* the {@link Mat} representing the current frame
* @return the {@link Image} to show
*/
public static Image mat2Image(Mat frame)
{
try
{
return SwingFXUtils.toFXImage(matToBufferedImage(frame), null);
}
catch (Exception e)
{
System.err.println("Cannot convert the Mat obejct: " + e);
return null;
}
}

/**
* Generic method for putting element running on a non-JavaFX thread on the
* JavaFX thread, to properly update the UI
*
* @param property
* a {@link ObjectProperty}
* @param value
* the value to set for the given {@link ObjectProperty}
*/
public static <T> void onFXThread(final ObjectProperty<T> property, final T value)
{
Platform.runLater(() -> {
property.set(value);
});
}

/**
* Support for the {@link mat2image()} method
*
* @param original
* the {@link Mat} object in BGR or grayscale
* @return the corresponding {@link BufferedImage}
*/
private static BufferedImage matToBufferedImage(Mat original)
{
// init
BufferedImage image = null;
int width = original.width(), height = original.height(), channels = original.channels();
byte[] sourcePixels = new byte[width * height * channels];
original.get(0, 0, sourcePixels);

if (original.channels() > 1)
{
image = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
}
else
{
image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
}
final byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
System.arraycopy(sourcePixels, 0, targetPixels, 0, sourcePixels.length);

return image;
}
}
13 changes: 12 additions & 1 deletion src/it/polito/teaching/cv/Video.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package it.polito.teaching.cv;

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;

import org.opencv.core.Core;

Expand All @@ -17,7 +19,7 @@
* histogram and it is possible to add a logo in a corner of the video.
*
* @author <a href="mailto:luigi.derussis@polito.it">Luigi De Russis</a>
* @version 1.1 (2015-10-20)
* @version 2.0 (2017-03-10)
* @since 1.0 (2013-11-20)
*
*/
Expand All @@ -42,6 +44,15 @@ public void start(Stage primaryStage)
// show the GUI
primaryStage.show();

// set the proper behavior on closing the application
VideoController controller = loader.getController();
primaryStage.setOnCloseRequest((new EventHandler<WindowEvent>() {
public void handle(WindowEvent we)
{
controller.setClosed();
}
}));

}
catch (Exception e)
{
Expand Down
79 changes: 53 additions & 26 deletions src/it/polito/teaching/cv/VideoController.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package it.polito.teaching.cv;

import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
Expand All @@ -10,7 +9,6 @@
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.core.MatOfFloat;
import org.opencv.core.MatOfInt;
import org.opencv.core.Point;
Expand All @@ -20,6 +18,7 @@
import org.opencv.imgproc.Imgproc;
import org.opencv.videoio.VideoCapture;

import it.polito.elite.teaching.cv.utils.Utils;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
Expand All @@ -33,7 +32,7 @@
* controls and the histogram creation.
*
* @author <a href="mailto:luigi.derussis@polito.it">Luigi De Russis</a>
* @version 1.1 (2015-10-20)
* @version 2.0 (2017-03-10)
* @since 1.0 (2013-11-20)
*
*/
Expand Down Expand Up @@ -100,8 +99,11 @@ protected void startCamera()
@Override
public void run()
{
Image imageToShow = grabFrame();
currentFrame.setImage(imageToShow);
// effectively grab and process a single frame
Mat frame = grabFrame();
// convert and show the frame
Image imageToShow = Utils.mat2Image(frame);
updateImageView(currentFrame, imageToShow);
}
};

Expand Down Expand Up @@ -161,10 +163,8 @@ protected void loadLogo()
*
* @return the {@link Image} to show
*/
private Image grabFrame()
private Mat grabFrame()
{
// init everything
Image imageToShow = null;
Mat frame = new Mat();

// check if the capture is open
Expand Down Expand Up @@ -200,9 +200,6 @@ private Image grabFrame()

// show the histogram
this.showHistogram(frame, grayscale.isSelected());

// convert the Mat object (OpenCV) to Image (JavaFX)
imageToShow = mat2Image(frame);
}

}
Expand All @@ -213,7 +210,7 @@ private Image grabFrame()
}
}

return imageToShow;
return frame;
}

/**
Expand Down Expand Up @@ -287,27 +284,57 @@ private void showHistogram(Mat frame, boolean gray)
}

// display the histogram...
Image histImg = mat2Image(histImage);
this.histogram.setImage(histImg);
Image histImg = Utils.mat2Image(histImage);
updateImageView(histogram, histImg);

}

/**
* Convert a Mat object (OpenCV) in the corresponding Image for JavaFX
* Stop the acquisition from the camera and release all the resources
*/
private void stopAcquisition()
{
if (this.timer!=null && !this.timer.isShutdown())
{
try
{
// stop the timer
this.timer.shutdown();
this.timer.awaitTermination(33, TimeUnit.MILLISECONDS);
}
catch (InterruptedException e)
{
// log any exception
System.err.println("Exception in stopping the frame capture, trying to release the camera now... " + e);
}
}

if (this.capture.isOpened())
{
// release the camera
this.capture.release();
}
}

/**
* Update the {@link ImageView} in the JavaFX main thread
*
* @param frame
* the {@link Mat} representing the current frame
* @return the {@link Image} to show
* @param view
* the {@link ImageView} to update
* @param image
* the {@link Image} to show
*/
private void updateImageView(ImageView view, Image image)
{
Utils.onFXThread(view.imageProperty(), image);
}

/**
* On application close, stop the acquisition from the camera
*/
private Image mat2Image(Mat frame)
protected void setClosed()
{
// create a temporary buffer
MatOfByte buffer = new MatOfByte();
// encode the frame in the buffer, according to the PNG format
Imgcodecs.imencode(".png", frame, buffer);
// build and return an Image created from the image encoded in the
// buffer
return new Image(new ByteArrayInputStream(buffer.toArray()));
this.stopAcquisition();
}


Expand Down

0 comments on commit 1ff61b2

Please sign in to comment.