How would I go about capturing an image for use in OpenCV from the standard camera module v2 plugged into a Raspberry Pi 3B? I've been trying to get high frame-rate video working, but using OpenCV's VideoCapture always gives me an empty Mat when I try to index device 0, and this and this both produced 1 frame per second or worse when I tried. I've also looked into spawning a raspivid process, but I don't see a way to get OpenCV's VideoCapture to read from the output of that process.
How would I get high FPS frame capture in Java? Is there a way I can get OpenCV to read from an OutputStream that I grab from another process?
EDIT: a simplified version of my code is below. I want to know how to populate the startRecording() function in this class
abstract class Main {
public static Mat currentCapture = null;
public static final double FOV_HEIGHT = 48.8;
public static final int WIDTH = 480;
public static final int HEIGHT = 384;
public static final int VIDEO_WIDTH = WIDTH * 2;
public static final int VIDEO_HEIGHT = HEIGHT * 2;
static {
System.loadLibrary(org.opencv.core.Core.NATIVE_LIBRARY_NAME);
}
public static void main(String[] args) {
client = new VisionClientTable("10.55.6.4", 5506);
new Thread(new VisionThread(VisionThread.Mode.VIDEO)).start();
new Thread(new VisionThread(VisionThread.Mode.TARGETING)).start();
}
private static class VisionThread implements Runnable {
private final Mode mode;
enum Mode {
VIDEO,
TARGETING
}
public VisionThread(Mode mode) {
this.mode = mode;
}
#Override
public void run() {
if (mode == Mode.TARGETING)
startTracking();
else if (mode == Mode.VIDEO)
startRecording();
}
}
public static void startTracking() {
/* this thread repeatedly captures currentCapture and processes it */
}
// this is where I need help
public static void startRecording() {
try {
VideoWriter video = new VideoWriter("/home/pi/vision/videos/video-" + Files.list(Paths.get("/home/pi/vision/captures")).count() + ".mp4", VideoWriter.fourcc('X', '2', '6', '4'), 30, new Size(VIDEO_WIDTH, VIDEO_HEIGHT), true);
VideoCapture capture = new VideoCapture(0);
capture.set(Videoio.CAP_PROP_FRAME_WIDTH, VIDEO_WIDTH);
capture.set(Videoio.CAP_PROP_FRAME_HEIGHT, VIDEO_HEIGHT);
Thread.sleep(2000);
while (true) {
long start = System.currentTimeMillis();
Mat mat = new Mat();
capture.read(mat);
if (!mat.empty()) { // mat is always empty
Mat downscaled = new Mat();
Imgproc.resize(mat, downscaled, new Size(WIDTH, HEIGHT), 0, 0, Imgproc.INTER_NEAREST);
currentCapture = downscaled;
}
video.write(mat);
long end = System.currentTimeMillis();
if (end - start < 1000 / 60)
Thread.sleep(1000 / 60 - (end - start));
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void log(String text) {
System.out.println(text);
}
}
I feel like the best way to do this might be to set raspivid to output to a file, and somehow feed the output of it into OpenCV, but I'm not sure how to do this.
EDIT 2: So far, I have tried using Runtime.getRuntime().exec() to run a raspivid command that outputs to a file, which works, but then when I try to open that file with OpenCV, capture.isOpened() remains false, even as the program repeatedly tries to open the file.
not getting much idea about your code from your question.
following may help you.
http://bigdinotech.com/tutorials/beaglebone-black-tutorials/building-opencv-on-the-beaglebone-black-or-raspberry-pi/
Related
I tried making a synth and it works and I can play music with them. However the first synth that I made had delay and you couldn't play fast songs. So I tried again using sourceDataline.flush() method to speed it up. Well it somewhat fixes it but delay is to much. I tried also reducing sample rate but delay is to much.
Edit: turns out you can comment the line keyStateInterface.setFlush(false);
it improves the delay however you still can't play fast songs
here is the code:
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
public class SoundLine implements Runnable{
KeyStateInterface keyStateInterface;
public SoundLine(KeyStateInterface arg){
keyStateInterface=arg;
}
#Override
public void run() {
AudioFormat audioFormat = new AudioFormat(44100,8,1,true,false);
try {
SourceDataLine sourceDataLine = AudioSystem.getSourceDataLine(audioFormat);
sourceDataLine.open(audioFormat);
sourceDataLine.start();
SynthMain synthMain = new SynthMain();
int v = 0;
while (true) {
int bytesAvailable = sourceDataLine.available();
if (bytesAvailable > 0) {
int sampling = 256/(64);
byte[] bytes = new byte[sampling];
for (int i = 0; i < sampling; i++) {
//bytes[i] = (byte) (Math.sin(angle) * 127f);
float t = (float) (synthMain.makeSound((double)v,44100,keyStateInterface)* 127f);
bytes[i] = (byte) (t);
v += 1;
}
if(keyStateInterface.getFlush()){
sourceDataLine.flush();
}
sourceDataLine.write(bytes, 0, sampling);
//if(!keyStateInterface.isCacheKeysSame())sourceDataLine.flush();
//System.out.println(bytesWritten);
} else {
Thread.sleep(1);
}
//System.out.println(bytesAvailable);
//System.out.println();
//if((System.currentTimeMillis()-mil)%50==0)freq+=0.5;
}
}catch (Exception e){
}
}
}
public class SynthMain {
double[] noteFrequency = {
466.1637615181,
493.8833012561,
523.2511306012,
554.3652619537,
587.3295358348,
622.2539674442,
659.2551138257,
698.4564628660,
739.9888454233,
783.9908719635,
830.6093951599,
880.0000000000,
932.3275230362,
987.7666025122,
1046.5022612024,
1108.7305239075,
1174.6590716696,
1244.5079348883,
1318.5102276515,
1396.9129257320,
1479.9776908465,
1567.9817439270,
1661.2187903198,
1760.0000000000,
1864.6550460724,
1975.5332050245,
2093.0045224048,
2217.4610478150,
2349.3181433393,
2489.0158697766,
2637.0204553030,
2793.8258514640,
2959.9553816931,
3135.9634878540,
3322.4375806396,
3520.0000000000,
3729.3100921447,
};
boolean[] keys = new boolean[noteFrequency.length];
public double makeSound(double dTime,double SampleRate,KeyStateInterface keyStateInterface){
if(keyStateInterface.getSizeOfMidiKey()>0){
keyStateInterface.setFlush(true);
for(int i=0;i<keyStateInterface.getSizeOfMidiKey();i++) {
KeyRequest keyRequest = keyStateInterface.popMidiKey();
if(keyRequest.getCommand()==-112){
if(keyRequest.getVelocity()>0)keys[keyRequest.getArg1()] = true;
if(keyRequest.getVelocity()<1)keys[keyRequest.getArg1()] = false;
System.out.println(keyRequest.getVelocity());
}
}
}else{
keyStateInterface.setFlush(false);
}
//System.out.println("makeSound");
double a = 0.0;
for(int i=0;i<keys.length;i++){
if(keys[i]){
a+=Oscillate(dTime,noteFrequency[i],(int)SampleRate);
}
}
return a*0.4;
}
public double Oscillate(double dTime,double dFreq,int sampleRate){
double period = (double)sampleRate / dFreq;
return Math.sin(2.0 * Math.PI * (int)dTime / period);
}
}
import java.util.ArrayList;
import java.util.Stack;
public class KeyState implements KeyStateInterface{
boolean isFlush;
ArrayList<KeyRequest> keyRequest = new ArrayList<KeyRequest>();
ArrayList<KeyRequest> midiKeyRequest = new ArrayList<KeyRequest>();
#Override
public void pushKey(int keyCode, boolean press) {
keyRequest.add(new KeyRequest(KeyRequest.KEY,keyCode,press));
}
#Override
public void pushMidiKey(int command, int arg1, int velocity) {
midiKeyRequest.add(new KeyRequest(KeyRequest.MIDI_KEY,command,arg1,velocity));
}
#Override
public KeyRequest popKey() {
KeyRequest t = keyRequest.get(keyRequest.size());
return t;
}
#Override
public KeyRequest popMidiKey() {
KeyRequest t = midiKeyRequest.get(keyRequest.size());
midiKeyRequest.remove(keyRequest.size());
return t;
}
#Override
public int getSizeOfKey() {
return keyRequest.size();
}
#Override
public int getSizeOfMidiKey() {
return midiKeyRequest.size();
}
#Override
public boolean getFlush() {
boolean v = isFlush;
isFlush = false;
return v;
}
#Override
public void setFlush(boolean arg) {
isFlush=arg;
}
}
I haven't dug deep into your code, but perhaps the following info will be useful.
The SourceDataLine.write() method uses a blocking queue internally. It will only progress as fast as the data can be processed. So, there is no need to test for available capacity before populating and shipping bytes.
I'd give the SDL thread a priority of 10, since most of it's time is spent in a blocked state anyway.
Also, I'd leave the line open and running. I first got that advice from Neil Smith of Praxis Live. There is a cost associated with continually rebuilding it. And it looks to me like you are creating a new SDL for every 4 bytes of audio data. That would be highly inefficient. I suspect that shipping somewhere in the range of 256 to 8K on a line that is left open would be a better choice, but I don't have hard facts to back that up that opinion. Neil wrote about having all the transporting arrays be the same size (e.g., the array of data produced by the synth be the same size as the SDL write).
I've made a real-time theremin with java, where the latency includes the task of reading the mouse click and position, then sending that to the synth that is generating the audio data. I wouldn't claim thay my latency down to a precision that allows "in the pocket" starts and stops to notes, but it still is pretty good. I suspect further optimization possible on my end.
I think Neil (mentioned earlier) has had better results. He's spoken of achieving latencies in the range of 5 milliseconds and less, as far back as 2011.
OK so I have the uploader uploading files using the Java FTP, I would like to update the label and the progress bar. Label with the percent text, bar with the percent int value. Right now with the current code only get the 100 and full bar at the end of the upload. During the upload none of them change.
here it is:
OutputStream output = new BufferedOutputStream(ftpOut);
CopyStreamListener listener = new CopyStreamListener() {
public void bytesTransferred(long totalBytesTransferred, int bytesTransferred, long streamSize) {
System.out.printf("\r%-30S: %d / %d", "Sent", totalBytesTransferred, streamSize);
ftpup.this.upd(totalBytesTransferred,streamSize);
}
public void bytesTransferred(CopyStreamEvent arg0) { }
};
Util.copyStream(input, output, ftp.getBufferSize(), f.length(), listener);
}
public void upd(long num, long size){
int k = (int) ((num*100)/size);
System.out.println(String.valueOf(k));
this.d.setText(String.valueOf(k));
//d.setText(String.valueOf(k));
progressBar.setValue(k);
}
From the sounds of it (and lacking any evidence to the contree) it sounds like your processing a time consuming action in the Event Dispatching Thread
You might like to read Concurrency in Swing for some further insight
I'd suggest using a SwingWorker to perform the actual transfer & take advantage of its built in progress support
UPDATE after seeing source code
Don't mix heavy weight components with light weight components. Change Applet to JApplet, change TextField to JTextField, don't use Canvas use a JPanel or JComponent
If you expect other people to read your code, please use proper names for your variables, I have no idea what p is.
Your Thread is useless. Rather then starting the thread and using it's run method you simply make your download call within it's constructor. This will do nothing for you...
Remove your implementation of MyThread and replace it with
public class MyWorker extends SwingWorker<Object, Object> {
private URL host;
private File outputFile;
public MyWorker(URL host, File f) {
this.host = host;
outputFile = f;
}
#Override
protected Object doInBackground() throws Exception {
// You're ignoring the host you past in to the constructor
String hostName = "localhost";
String username = "un";
String password = "pass";
String location = f.toString();
//FTPClient ftp = null;
ftp.connect(hostName, 2121);
ftp.login(username, password);
ftp.setFileType(FTP.BINARY_FILE_TYPE);
ftp.setKeepAlive(true);
ftp.setControlKeepAliveTimeout(3000);
ftp.setDataTimeout(3000); // 100 minutes
ftp.setConnectTimeout(3000); // 100 minutes
ftp.changeWorkingDirectory("/SSL");
int reply = ftp.getReplyCode();
System.out.println("Received Reply from FTP Connection:" + reply);
if (FTPReply.isPositiveCompletion(reply)) {
System.out.println("Connected Success");
}
System.out.println(f.getName().toString());
File f1 = new File(location);
in = new FileInputStream(f1);
FileInputStream input = new FileInputStream(f1);
// ftp.storeFile(f.getName().toString(),in);
//ProgressMonitorInputStream is= new ProgressMonitorInputStream(getParent(), "st", in);
OutputStream ftpOut = ftp.storeFileStream(f.getName().toString());
System.out.println(ftpOut.toString());
//newname hereSystem.out.println(ftp.remoteRetrieve(f.toString()));
OutputStream output = new BufferedOutputStream(ftpOut);
CopyStreamListener listener = new CopyStreamListener() {
public void bytesTransferred(final long totalBytesTransferred, final int bytesTransferred, final long streamSize) {
setProgress((int) Math.round(((double) totalBytesTransferred / (double) streamSize) * 100d));
}
#Override
public void bytesTransferred(CopyStreamEvent arg0) {
// TODO Auto-generated method stub
}
};
Util.copyStream(input, output, ftp.getBufferSize(), f.length(), listener);
return null;
}
}
In your ActionListener of o (??) replace the thread execution code with
try {
MyWorker worker = new MyWorker(new URL("http://localhost"), file);
worker.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("progress")) {
Integer progress = (Integer) evt.getNewValue();
progressBar.setValue(progress);
}
}
});
worker.execute();
} catch (MalformedURLException ex) {
ex.printStackTrace();
}
Note. You are ignoring the URL you pass to the constructor. http:// is not ftp:// so I doubt this will work...
During the upload you don't see changes to the GUI, because you run the upload and the GUI changes in the same thread.
You should start one threayd that does the upload and another one in EDT (Event-Dispatch-Thread) that does the GUI updates.
For more info see:
The Event Dispatch Thread
You should implement the transfer logic in a SwingWorker, that way the UI will have the chance to present the progress.
I'm trying to implement a simple application to show my webcamera, which works good, until I try to flip the output stream. After I'm flipping the stream the program starts to leak. The strange its only leak when I flip the stream and I have no idea why, since I try to release everything. When I dont flip, the leak is gone. (Its still leaks when I comment out all the release lines)
I'm getting my image source from GrabCamera through these methods:
private void StartWebcamera(){
cameraThread = new Thread(){
public void run(){
while ((grabbedImage = opencv_highgui.cvQueryFrame(capture)) != null) {
grabbedImage.release();
}
}
};
cameraThread.start();
}
public IplImage GetGrabbedStream(){
return grabbedImage;
}
In my main i pass the image to my GUI class like these:
while (true) {
gui.SetVideoStream(grabCamera.GetGrabbedStream(), true);//if true its leaking if false its not leaking
}
And I show my image in the GUI class:
public void SetVideoStream(IplImage img,boolean flip){
if (flip) {
IplImage mirrorImage = img.clone();
cvFlip(img, mirrorImage, 1);
cameraFeed.setImage(mirrorImage.getBufferedImage());
videoPanel.setIcon(cameraFeed);
videoPanel.repaint();
mirrorImage.release();
img.release();
}
else {
cameraFeed.setImage(img.getBufferedImage());
videoPanel.setIcon(cameraFeed);
videoPanel.repaint();
img.release();
}
}
Here are the complete classes:
Classes
I'am doing simple libgdx game. I have lag (game stop for 0. 5 sec) when i use sound.play()
edit this bug apear on android 4.0 on 2.3 everything is running fine.
method. I play sound by this code:
if(CollisionDetector.detect(touchArea, hoodie.getTouchArea())){
GameScreen.totalScore++;
setPosition();
System.out.println("played");
Assets.eatSound.play();
}
And i use this method to load sound:
static long waitForLoadCompleted(Sound sound,float volume) {
long id;
while ((id = sound.play(volume)) == -1) {
long t = TimeUtils.nanoTime();
while (TimeUtils.nanoTime() - t < 100000000);
}
return id;
}
What am i doing wrong? Or what can i do to fix this lag ?
edit:
I have just tried to do thread with sound.play() but it also doesn't work:
new Thread(new Runnable() {
#Override
public void run() {
// do something important here, asynchronously to the rendering thread
// post a Runnable to the rendering thread that processes the result
Gdx.app.postRunnable(new Runnable() {
#Override
public void run() {
// process the result, e.g. add it to an Array<Result> field of the ApplicationListener.
eatSound2.play();
}
});
}
}).start();
My Sound asset class looks like this but i still have lag with sound.
package com.redHoodie;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.utils.Disposable;
public class SoundEffect implements Disposable {
private static final int WaitLimit = 1000;
private static final int ThrottleMs = 100;
Sound eatSound;
Sound endSound;
public SoundEffect(){
eatSound = Gdx.audio.newSound(Gdx.files.internal("eatSound.ogg"));
endSound = Gdx.audio.newSound(Gdx.files.internal("sadend.wav"));
checkedPlay(eatSound);
}
protected long checkedPlay (Sound sound) {
return checkedPlay(sound, 1);
}
protected long checkedLoop (Sound sound) {
return checkedLoop(sound, 1);
}
protected long checkedPlay (Sound sound, float volume) {
int waitCounter = 0;
long soundId = 0;
boolean ready = false;
while (!ready && waitCounter < WaitLimit) {
soundId = sound.play(volume);
ready = (soundId != 0);
waitCounter++;
try {
Thread.sleep(ThrottleMs);
} catch (InterruptedException e) {
}
}
return soundId;
}
protected long checkedLoop (Sound sound, float volume) {
int waitCounter = 0;
long soundId = 0;
boolean ready = false;
while (!ready && waitCounter < WaitLimit) {
soundId = sound.loop(volume);
ready = (soundId != 0);
waitCounter++;
try {
Thread.sleep(ThrottleMs);
} catch (InterruptedException e) {
}
}
return soundId;
}
#Override
public void dispose() {
// TODO Auto-generated method stub
}
}
I had the same problem. It was because my .mp3 file was too short. Mine was 0.167 seconds long. I added 1.2 seconds of silence with Audacity, and it fixed the problem.
Lately I run into the same issue (except I'm using wav instead mp3 files). My app was lagging when I play many (like 10 or 20) sounds at the same time (same render method). "Solved" this by playing only 1 sound at the time. Generally it's hard to distinct many sounds at the same time. Also on desktop it works fine, but problem appears on android (9 or 8).
If someone still facing this issue as me there is the alternative solution with one limitation: no option to use sound id.
You can change default LibGDX behavior and use AsynchronousAndroidAudio by overriding this method in your AndroidLauncher class:
#Override
public AndroidAudio createAudio(Context context, AndroidApplicationConfiguration config) {
return new AsynchronousAndroidAudio(context, config);
}
See the official documentation for more info and also the pull request
Also, if for any reasons you need sound id you can take this implementation as an example and find a workaround for your project.
Fix is available starting from LibGDX 1.9.12
Im trying to implement fade in effect to my mp3 player.
I´m using
FloatControl volumeControl = (FloatControl) line.getControl(FloatControl.Type.MASTER_GAIN);
because FloatControl.Type.VOLUME throws an exception(Unavaliable Control) I dont know why.
I need some help with the algorithm, because its not working ok.
Heres the code:
public class FloatControlFader
{
public static void fadeIn(final FloatControl control, final float from,
final float to, final int seconds)
{
final float vps = ((to-from) / (seconds*10));//Volume incrased/100millisecond
control.setValue(from);
Thread t = new Thread(new Runnable(){
public void run() {
for(int i=0; i < seconds*10; i++)
{
try
{
Thread.sleep(100);
}
catch (InterruptedException ex)
{
}
System.out.println(control.getValue()); //for DEBUG
control.setValue(control.getValue() + vps);
}
}
});
t.start();
}
}
Would appreciate any help, thanks!
Remember the human ear does not hear linearly so increasing by a steady X vps is not going to sound like a smooth fade. You need to put a log function in there. Then you need to map the linear increases to log values. This is of course all assuming the volume control units are not in decibels. If you're increasing by db then you're fine.