I know, there are several posts handling with this problem here on Stackoverflow, but I didn´t get a solution for my problem. I have an ipcam and I want to capture the livestream using java. The problem is, that I can only access the cam via RTSP. There is no normal http://xxx.xxx.xxx:xx access.
I use the OpenCv library but unfortunately my program only works with the webcam of my laptop because it is the default device.
protected void init()
{
this.capture = new VideoCapture();
this.faceCascade = new CascadeClassifier();
this.absoluteFaceSize = 0;
}
/**
* The action triggered by pushing the button on the GUI
*/
#FXML
protected void startCamera()
{
// set a fixed width for the frame
originalFrame.setFitWidth(600);
// preserve image ratio
originalFrame.setPreserveRatio(true);
if (!this.cameraActive)
{
// disable setting checkboxes
this.haarClassifier.setDisable(true);
this.lbpClassifier.setDisable(true);
// start the video capture
//String URLName = "rtsp://username:password#rtsp:554/h264/ch1/main/av_stream";
this.capture.open("rtsp://192.168.178.161:554/onvif1");
// is the video stream available?
if (this.capture.isOpened())
{
this.cameraActive = true;
// grab a frame every 33 ms (30 frames/sec)
Runnable frameGrabber = new Runnable() {
#Override
public void run()
{
Image imageToShow = grabFrame();
originalFrame.setImage(imageToShow);
}
};
this.timer = Executors.newSingleThreadScheduledExecutor();
this.timer.scheduleAtFixedRate(frameGrabber, 0, 33, TimeUnit.MILLISECONDS);
// update the button content
this.cameraButton.setText("Stop Camera");
}
else
{
// log the error
System.err.println("Failed to open the camera connection...");
}
}
Related
I try to implement a GUI button so that when it is pressed, it performs two actions - the execution of the main code (2-3 seconds) and the display of the gif-preloader.
I used Task for this purpose, initializing and running it in the setOnAction method. Task itself, in turn, uses the showGif () method to launch the image.
Separately, they work correctly - showGif () opens GIF, Task displays a counter working in parallel with the main code in the console.
But when I put showGif () in the Task, the method does not work. It reaches the line "pane.setCenter (hb);" and stops. I thought that he didn’t have enough time to launch GIF and added a 5-second delay to the main code - that didn’t help either.
What I do wrong?
Besides Task, I also tried Platform.runLater(new Runnable) - the result is the same.
The button action:
btn_find.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
isStarted = true;
task = new Task<Object>() {
#Override protected Object call() throws Exception {
showGif();
return null;
}
};
new Thread(task).start();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}...
The Gif method:
protected static void showGif() {
System.out.println("opening GIF...");
File file = new File("/Users/user/Desktop/cat-preloader.gif");
String localUrl = null;
try {
localUrl = file.toURI().toURL().toString();
} catch (Exception e) {
e.printStackTrace();
}
Image image = new Image(localUrl, 200,200, false, true);
ImageView imageView = new ImageView(image);
hb = new HBox();
hb.setStyle("-fx-background-color: lightgrey");
hb.setOpacity(0.7);
hb.getChildren().add(imageView);
HBox.setMargin(imageView, new Insets(300, 100, 60, 200));
BorderPane.setMargin(hb, new Insets(0, 0,600, 0));
System.out.println("setting the pane");
// here thread execution stops
pane.setCenter(hb);
System.out.println("GIF started");
}
I am attempting to capture a video recording through an external camera, Logitec C922. Using java, I can make this possible through webcam api.
<dependency>
<groupId>com.github.sarxos</groupId>
<artifactId>webcam-capture</artifactId>
<version>0.3.10</version>
</dependency>
<dependency>
<groupId>xuggle</groupId>
<artifactId>xuggle-xuggler</artifactId>
<version>5.4</version>
</dependency>
However, for the life of me, I cannot make it record at 60FPS. The video randomly stutters when stored, and is not smooth at all.
I can connect to the camera, using the following details.
final List<Webcam> webcams = Webcam.getWebcams();
for (final Webcam cam : webcams) {
if (cam.getName().contains("C922")) {
System.out.println("### Logitec C922 cam found");
webcam = cam;
break;
}
}
I set the size of the cam to the following:
final Dimension[] nonStandardResolutions = new Dimension[] { WebcamResolution.HD720.getSize(), };
webcam.setCustomViewSizes(nonStandardResolutions);
webcam.setViewSize(WebcamResolution.HD720.getSize());
webcam.open(true);
And then I capture the images:
while (continueRecording) {
// capture the webcam image
final BufferedImage webcamImage = ConverterFactory.convertToType(webcam.getImage(),
BufferedImage.TYPE_3BYTE_BGR);
final Date timeOfCapture = new Date();
// convert the image and store
final IConverter converter = ConverterFactory.createConverter(webcamImage, IPixelFormat.Type.YUV420P);
final IVideoPicture frame = converter.toPicture(webcamImage,
(System.currentTimeMillis() - start) * 1000);
frame.setKeyFrame(false);
frame.setQuality(0);
writer.encodeVideo(0, frame);
}
My writer is defined as follows:
final Dimension size = WebcamResolution.HD720.getSize();
final IMediaWriter writer = ToolFactory.makeWriter(videoFile.getName());
writer.addVideoStream(0, 0, ICodec.ID.CODEC_ID_H264, size.width, size.height);
I am honestly not sure what in my code could be causing this. Given that I lower the resolution, I get no problems. ( 480p ) Could the issue be with the codes I am using?
As some of the comments mentioned, introducing queues does solve the problem. Here is the general logic to performs the needed steps. Note, I've setup my code for a lower resolution, as it allows me to capture 100FPS per sec. Adjust as needed.
Class to link the image/video capture and class to edit it :
public class WebcamRecorder {
final Dimension size = WebcamResolution.QVGA.getSize();
final Stopper stopper = new Stopper();
public void startRecording() throws Exception {
final Webcam webcam = Webcam.getDefault();
webcam.setViewSize(size);
webcam.open(true);
final BlockingQueue<CapturedFrame> queue = new LinkedBlockingQueue<CapturedFrame>();
final Thread recordingThread = new Thread(new RecordingThread(queue, webcam, stopper));
final Thread imageProcessingThread = new Thread(new ImageProcessingThread(queue, size));
recordingThread.start();
imageProcessingThread.start();
}
public void stopRecording() {
stopper.setStop(true);
}
}
RecordingThread :
public void run() {
try {
System.out.println("## capturing images began");
while (true) {
final BufferedImage webcamImage = ConverterFactory.convertToType(webcam.getImage(),
BufferedImage.TYPE_3BYTE_BGR);
final Date timeOfCapture = new Date();
queue.put(new CapturedFrame(webcamImage, timeOfCapture, false));
if (stopper.isStop()) {
System.out.println("### signal to stop capturing images received");
queue.put(new CapturedFrame(null, null, true));
break;
}
}
} catch (InterruptedException e) {
System.out.println("### threading issues during recording:: " + e.getMessage());
} finally {
System.out.println("## capturing images end");
if (webcam.isOpen()) {
webcam.close();
}
}
}
ImageProcessingThread:
public void run() {
writer.addVideoStream(0, 0, ICodec.ID.CODEC_ID_H264, size.width, size.height);
try {
int frameIdx = 0;
final long start = System.currentTimeMillis();
while (true) {
final CapturedFrame capturedFrame = queue.take();
if (capturedFrame.isEnd()) {
break;
}
final BufferedImage webcamImage = capturedFrame.getImage();
size.height);
// convert the image and store
final IConverter converter = ConverterFactory.createConverter(webcamImage, IPixelFormat.Type.YUV420P);
final long end = System.currentTimeMillis();
final IVideoPicture frame = converter.toPicture(webcamImage, (end - start) * 1000);
frame.setKeyFrame((frameIdx++ == 0));
frame.setQuality(0);
writer.encodeVideo(0, frame);
}
} catch (final InterruptedException e) {
System.out.println("### threading issues during image processing:: " + e.getMessage());
} finally {
if (writer != null) {
writer.close();
}
}
The way it works is pretty simple. The WebcamRecord class creates an instance of a queue that is shared between the video capture and the image processing. The RecordingThread sends bufferedImages to the queue ( in my case, it a pojo, called CapturedFrame ( which has a BufferedImage in it ) ). The ImageProcessingThread will listen and pull data from the queue. If it does not receive a signal that the writing should end, the loop never dies.
I am trying to overlay an image inside the rectangular region after detection of face and eyes. But I am unable to do so. Can you please guide me how to proceed.
I have searched a lot on google and tried Mat copy to src file but no result. Please help me in solving this issue.
public class FXController {
// FXML buttons
#FXML
private Button cameraButton;
// the FXML area for showing the current frame
#FXML
private ImageView originalFrame;
// checkboxes for enabling/disabling a classifier
#FXML
private CheckBox haarClassifier;
#FXML
private CheckBox lbpClassifier;
// a timer for acquiring the video stream
private ScheduledExecutorService timer;
// the OpenCV object that performs the video capture
private VideoCapture capture;
// a flag to change the button behavior
private boolean cameraActive;
// face cascade classifier
private CascadeClassifier faceCascade;
private int absoluteFaceSize;
/**
* Init the controller, at start time
*/
protected void init()
{
this.capture = new VideoCapture();
this.faceCascade = new CascadeClassifier();
this.absoluteFaceSize = 0;
// set a fixed width for the frame
originalFrame.setFitWidth(600);
// preserve image ratio
originalFrame.setPreserveRatio(true);
}
/**
* The action triggered by pushing the button on the GUI
*/
#FXML
protected void startCamera()
{
if (!this.cameraActive)
{
// disable setting checkboxes
this.haarClassifier.setDisable(true);
this.lbpClassifier.setDisable(true);
// start the video capture
this.capture.open(0);
// is the video stream available?
if (this.capture.isOpened())
{
this.cameraActive = true;
// grab a frame every 33 ms (30 frames/sec)
Runnable frameGrabber = new Runnable() {
#Override
public void run()
{
// effectively grab and process a single frame
Mat frame = grabFrame();
// convert and show the frame
Image imageToShow = Utils.mat2Image(frame);
updateImageView(originalFrame, imageToShow);
}
};
this.timer = Executors.newSingleThreadScheduledExecutor();
this.timer.scheduleAtFixedRate(frameGrabber, 0, 33, TimeUnit.MILLISECONDS);
// update the button content
this.cameraButton.setText("Stop Camera");
}
else
{
// log the error
System.err.println("Failed to open the camera connection...");
}
}
else
{
// the camera is not active at this point
this.cameraActive = false;
// update again the button content
this.cameraButton.setText("Start Camera");
// enable classifiers checkboxes
this.haarClassifier.setDisable(false);
this.lbpClassifier.setDisable(false);
// stop the timer
this.stopAcquisition();
}
}
/**
* Get a frame from the opened video stream (if any)
*
* #return the {#link Image} to show
*/
private Mat grabFrame()
{
Mat frame = new Mat();
// check if the capture is open
if (this.capture.isOpened())
{
try
{
// read the current frame
this.capture.read(frame);
// if the frame is not empty, process it
if (!frame.empty())
{
// face detection
this.detectAndDisplay(frame);
}
}
catch (Exception e)
{
// log the (full) error
System.err.println("Exception during the image elaboration: " + e);
}
}
return frame;
}
/**
* Method for face detection and tracking
*
* #param frame
* it looks for faces in this frame
*/
private void detectAndDisplay(Mat frame)
{
MatOfRect faces = new MatOfRect();
//Mat grayFrameSrc = new Mat();
Mat grayFrameDest=Imgcodecs.imread("images/face.png");
// convert the frame in gray scale
//Imgproc.cvtColor(frame, grayFrameSrc, Imgproc.COLOR_BGR2GRAY);
Imgproc.cvtColor(frame, grayFrameDest, Imgproc.COLOR_BGR2GRAY);
// equalize the frame histogram to improve the result
//Imgproc.equalizeHist(grayFrameSrc, grayFrameSrc);
Imgproc.equalizeHist(grayFrameDest, grayFrameDest);
//int height = grayFrameSrc.rows();
//int width = grayFrameSrc.width();
int height = grayFrameDest.rows();
// compute minimum face size (20% of the frame height, in our case)
if (this.absoluteFaceSize == 0)
{
//System.out.println("The height = "+width);
if (Math.round(height * 0.1f) > 0)
{
this.absoluteFaceSize = Math.round(height * 0.1f);
}
}
// detect faces
this.faceCascade.detectMultiScale(grayFrameDest, faces, 1.1, 2, 0 | Objdetect.CASCADE_SCALE_IMAGE,
new Size(this.absoluteFaceSize, this.absoluteFaceSize), new Size());
// each rectangle in faces is a face: draw them!
Rect[] facesArray = faces.toArray();
for (int i = 0; i < facesArray.length; i++){
int x=facesArray[i].x;
int y=facesArray[i].y;
int h=facesArray[i].height;
int w=facesArray[i].width;
Rect rect=facesArray[i];
Imgproc.rectangle(frame, facesArray[i].tl(), facesArray[i].br(), new Scalar(0, 255, 0), 3);
//Imgproc.putText(frame, "Hi Ankit", new Point(x, y), 0, 0, new Scalar(0, 255, 0));
Imgcodecs.imwrite("/home/ankit-mathur/Desktop/mask.png", frame);
Mat temp = new Mat();
Imgproc.cvtColor(grayFrameDest, temp, Imgproc.COLOR_BGRA2GRAY,0);
Mat temp_rgba = new Mat();
Imgproc.cvtColor(temp, temp_rgba, Imgproc.COLOR_GRAY2BGRA,0);
temp_rgba.copyTo(grayFrameDest);
}
}
#FXML
protected void haarSelected(Event event)
{
// check whether the lpb checkbox is selected and deselect it
if (this.lbpClassifier.isSelected())
this.lbpClassifier.setSelected(false);
this.checkboxSelection("resources/haarcascades/haarcascade_frontalface_alt.xml");
}
/**
* The action triggered by selecting the LBP Classifier checkbox. It loads
* the trained set to be used for frontal face detection.
*/
#FXML
protected void lbpSelected(Event event)
{
// check whether the haar checkbox is selected and deselect it
if (this.haarClassifier.isSelected())
this.haarClassifier.setSelected(false);
this.checkboxSelection("resources/lbpcascades/lbpcascade_frontalface.xml");
}
/**
* Method for loading a classifier trained set from disk
*
* #param classifierPath
* the path on disk where a classifier trained set is located
*/
private void checkboxSelection(String classifierPath)
{
// load the classifier(s)
//System.out.println(classifierPath);
if (this.faceCascade.load(classifierPath)) {
this.faceCascade.load(classifierPath);
}
else{
System.out.println("Unable To Load FaceCascade");
}
// now the video capture can start
this.cameraButton.setDisable(false);
}
/**
* 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 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
*/
protected void setClosed()
{
this.stopAcquisition();
}
}
I am working on the same thing on iOS. Here is how I am doing it
Mat image = imread("path/to/image");
//center.x and center.y are the location in the screen
cv::Rect roi( cv::Point( center.x, center.y), image.size() );
//if you want to save it in a Mat
image.copyTo( source( roi ));
//or if you want to write it on a file
imwrite("image.jpg", image);
Can anyone please tell me which is the best way to play video in a JPanel.I am currently working on a learning software for children where some learning videos will be played upon selection.Videos are stored in some folder.I have successfully done the job using JMF but the problem is its kinda slow.It takes some time to start the video, though the videos are not too large(2-4 MB).What can i do to make it quick-start,
Thank u
public class MediaPanel extends JPanel
{
public static boolean playing = false;
public static Player mediaPlayer;
public MediaPanel( URL mediaURL )
{
setLayout( new BorderLayout() ); // use a BorderLayout
// Use lightweight components for Swing compatibility
//Component controls = mediaPlayer.getControlPanelComponent();
} // end MediaPanel constructor
public void play(URL mediaURL) throws NoPlayerException, CannotRealizeException, IOException, IncompatibleSourceException{
Manager.setHint( Manager.LIGHTWEIGHT_RENDERER, true );
System.out.println("sdfdsg");
mediaPlayer = Manager.createRealizedPlayer( mediaURL );
Component video = mediaPlayer.getVisualComponent();
if ( video != null )
add( video);
mediaPlayer.start();
playing=true;
}
public void stop(){
mediaPlayer.stop();
playing = false;
}
public void play_one(){
mediaPlayer.stop();
mediaPlayer.start();
}
}
public class MediaPanel extends JPanel
{
public static boolean playing = false;
public static Player mediaPlayer;
public MediaPanel( URL mediaURL )
{
setLayout( new BorderLayout() );
} // end MediaPanel constructor
public void play(URL mediaURL) throws NoPlayerException, CannotRealizeException, IOException, IncompatibleSourceException{
Manager.setHint( Manager.LIGHTWEIGHT_RENDERER, true );
mediaPlayer = Manager.createRealizedPlayer( mediaURL );
Component video = mediaPlayer.getVisualComponent();
if ( video != null )
add( video);
mediaPlayer.start();
playing=true;
}
public void stop(){
mediaPlayer.stop();
playing = false;
}
public void play_one(){
mediaPlayer.stop();
mediaPlayer.start();
}
}
and the portion of the source code where i used this class..
try {
Home.text.setText("wait..");
if(Home.mediaPanel.playing==true)
Home.mediaPanel.stop();
Home.mediaPanel.play(new URL("file://C://Users//zubair//workspace//learningKit//"+Home.selected_topic+"//"+Home.sele cted_group+"//v"+k+".flv"));
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
JMF is from the stone-age. Do you have any reasons to stick to it?
I would recommend using JavaFX which has media support including video playing. JavaFX is part of Java 8, and is also shipped with Java 7 (just not on the default classpath). You can play a supported video format (*.flv, *.mp4) with just a few lines of code, and it also uses hardware acceleration if available.
Basically you only need to create a Media, a MediaPlayer and a MediaView class:
Media m = new Media(Paths.get("example.flv").toURI().toString());
MediaPlayer mp = new MediaPlayer(m);
MediaView mv = new MediaView(mp);
// Add the mediaview component somewhere to your GUI
// And you're done. You can start playing the video by:
mp.play();
Here is a short, complete example application which plays a video:
http://www.java2s.com/Code/Java/JavaFX/FullScreenVideoPlayer.htm
Official Oracle tutorial:
Introduction to JavaFX Media
I coded a j2me application using LWUIT. It works fine on emulator as well as a symbian device. But when i tried to run it on a nokia s40 device,it showed up a "nothing to display" message. I tried displaying a splash screen, as prescribed in some forums. Still,the app never gets past the splash screen.
EDIT 1
Display.init(this);
Resources r = Resources.open("/theme.res");
UIManager.getInstance().setThemeProps(r.getTheme(r.getThemeResourceNames()[0]));
Dialog splash = new Dialog("Splash Screen");
splash.setAutoDispose(true);
splash.setTimeout(5000);
splash.show();
RecordStore rs = null;
byte[] buffer = null;
rs = RecordStore.openRecordStore("xxxxxx", true);
if (rs.getNumRecords() > 0) {
buffer = rs.getRecord(rs.getNumRecords());
num = new String(buffer, 0, buffer.length);
rs.closeRecordStore();
offer(num); // a method which displays main form
} else {
rs.closeRecordStore();
registration("xxxxx"); //another method which displays the secondary form
}
In this snippet,a blank screen is displayed on the device after the dialog/splash screen.
The form gets displayed when i remove the codes managing the RecordStore.
How do i fix this mess ?
EDIT 2
Code for registration()
Form f = new Form();
f.setLayout(new BoxLayout(BoxLayout.Y_AXIS));
Image img = Image.createImage("logo.png");
f.addComponent(new Label(img));
Label lbl = new Label(msg);
f.addComponent(lbl);
f.addComponent(new Label("xxxxx"));
final TextArea number = new TextArea(1, 10, TextArea.NUMERIC);
f.addComponent(number);
Button btn = new Button("Register");
btn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
//perform rms related activities and move onto offer()
}
});
f.addComponent(btn);
Button help = new Button("Help?");
help.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
//display a help dialog
}
});
f.addComponent(help);
f.addCommandListener(this);
f.show();
Change the splash.show() to splash.showModeless()
Regardless your code is incorrect since it assumes show() will display the dialog immediately which is not how most GUI frameworks work. Your method needs to complete and return control to LWUIT in order for the dialog to show. However, you read the RMS and then the code to show your form is unclear, when do you expect it to actually occur.
You need to show the dialog without a timeout (I would use a form for the splash screen there is no reason to use a dialog), then open a thread (new Thread(...)) to do whatever you want and then when the thread completes show your form.
From this blog, The Nothing to display issue is standard Nokia S40 behavior for delayed calls to setCurrent() and the normal recommendation is to show a splash screen early on to avoid this prompt.
Also look this same related discussion.
Edit:
Form splashscreen = new Form();
splashscreen.getStyle().setBgImage(imageName);
splashscreen.show()
Display.getInstance().callSerially(new Runnable() {
public void run() {
try {
Thread.sleep(5000L);
// do RMS related things here.
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
});