Programm beendet sich nicht und weiteres seltsames Verhalten

benjamin222

Mitglied
Java:
 private static void OpenCVStart() {
        nu.pattern.OpenCV.loadLocally();
        Mat m = Mat.eye(3,3, CvType.CV_8UC1);
        System.out.println("OpenCV matrix = " + m.dump());

        Mat f= Imgcodecs.imread("D:\\Bilder\\bikinigross.jpg");
        HighGui.imshow("bild",f);
        HighGui.waitKey(500);

        Mat g= Imgcodecs.imread("D:\\Bilder\\wwm2.png");
        HighGui.imshow("wwm",g);
        HighGui.waitKey(500);

        VideoCapture camera=new VideoCapture("D:\\Bilder\\elvira2.mp4");




        Mat frame=new Mat();

        while (true) {
            System.out.println("Looping.. \n");
            if (camera.read(frame)) {
                System.out.println("Frame Obtained");
                System.out.println("Captured Frame Width " +
                        frame.width() + " Height " + frame.height());
                HighGui.imshow("camera.jpg", frame);
                HighGui.waitKey(5);
            }else{
                break;
            }
        }

        System.out.println(" end reached");
        camera.release();
        HighGui.destroyAllWindows();


    }

Ich möchte hier zwei Bilder anzeigen und ein Video. Das klappt soweit auch, aber es gibt Probleme:

1. Ich hätte erwartet, dass jedes Bild und das Video in einem eigenen Popup auftauchen, das ist aber nicht so. Die sind alle im gleichen Fenster nacheinander.
2. Am Ende bleibt das letzte Bild des Videos sichtbar d.h. das Fenster bleibt offen und so auch das Programm. Selbst nach manuellem Schließen des Fensters läuft das Programm weiter und ich muss es hart in der IDE beenden.
 
Zu 1.: vermutlich willst Du auch HighGui.newWindow aufrufen. Zumindest klingt das sehr nach dem, was Du willst.
Zu 2.: Vermutlich wurde bei den Fenstern kein setDefaultCloseOperation gesetzt. Dann kann man mit System.exit(0) das Programm beenden oder eben die Default Close Operation setzen. (Default ist das hide on close, d.h. das Fenster existiert weiter und daher läuft das Programm auch noch weiter.)
 
1. Die Methode "HighGui.newWindow" gibt es gar nicht. Aber ja, ich hätte gerne, dass ich entscheiden kann ob ein weiteres Fenster aufgeht oder das alte überschrieben wird. Da die HighGui Klasse aus einer externen Library ist möchte ich da natürlich nichts ändern.

Ich kopiere die Klasse mal rein:

Java:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.opencv.highgui;

import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import org.opencv.core.Mat;

public final class HighGui {
    public static final int WINDOW_NORMAL = 0;
    public static final int WINDOW_AUTOSIZE = 1;
    public static int n_closed_windows = 0;
    public static int pressedKey = -1;
    public static CountDownLatch latch = new CountDownLatch(1);
    public static Map<String, ImageWindow> windows = new HashMap();

    public HighGui() {
    }

    public static void namedWindow(String winname) {
        namedWindow(winname, 1);
    }

    public static void namedWindow(String winname, int flag) {
        ImageWindow newWin = new ImageWindow(winname, flag);
        if (windows.get(winname) == null) {
            windows.put(winname, newWin);
        }

    }

    public static void imshow(String winname, Mat img) {
        if (img.empty()) {
            System.err.println("Error: Empty image in imshow");
            System.exit(-1);
        } else {
            ImageWindow tmpWindow = (ImageWindow)windows.get(winname);
            if (tmpWindow == null) {
                ImageWindow newWin = new ImageWindow(winname, img);
                windows.put(winname, newWin);
            } else {
                tmpWindow.setMat(img);
            }
        }

    }

    public static Image toBufferedImage(Mat m) {
        int type = 10;
        if (m.channels() > 1) {
            type = 5;
        }

        int bufferSize = m.channels() * m.cols() * m.rows();
        byte[] b = new byte[bufferSize];
        m.get(0, 0, b);
        BufferedImage image = new BufferedImage(m.cols(), m.rows(), type);
        byte[] targetPixels = ((DataBufferByte)image.getRaster().getDataBuffer()).getData();
        System.arraycopy(b, 0, targetPixels, 0, b.length);
        return image;
    }

    public static JFrame createJFrame(String title, int flag) {
        JFrame frame = new JFrame(title);
        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent windowEvent) {
                ++HighGui.n_closed_windows;
                if (HighGui.n_closed_windows == HighGui.windows.size()) {
                    HighGui.latch.countDown();
                }

            }
        });
        frame.addKeyListener(new KeyListener() {
            public void keyTyped(KeyEvent e) {
            }

            public void keyReleased(KeyEvent e) {
            }

            public void keyPressed(KeyEvent e) {
                HighGui.pressedKey = e.getKeyCode();
                HighGui.latch.countDown();
            }
        });
        if (flag == 1) {
            frame.setResizable(false);
        }

        return frame;
    }

    public static void waitKey() {
        waitKey(0);
    }

    public static int waitKey(int delay) {
        latch = new CountDownLatch(1);
        n_closed_windows = 0;
        pressedKey = -1;
        if (windows.isEmpty()) {
            System.err.println("Error: waitKey must be used after an imshow");
            System.exit(-1);
        }

        Iterator iter = windows.entrySet().iterator();

        ImageWindow win;
        while(iter.hasNext()) {
            Entry<String, ImageWindow> entry = (Entry)iter.next();
            win = (ImageWindow)entry.getValue();
            if (win.alreadyUsed) {
                iter.remove();
                win.frame.dispose();
            }
        }

        Iterator var8 = windows.values().iterator();

        while(var8.hasNext()) {
            win = (ImageWindow)var8.next();
            if (win.img != null) {
                ImageIcon icon = new ImageIcon(toBufferedImage(win.img));
                if (win.lbl == null) {
                    JFrame frame = createJFrame(win.name, win.flag);
                    JLabel lbl = new JLabel(icon);
                    win.setFrameLabelVisible(frame, lbl);
                } else {
                    win.lbl.setIcon(icon);
                }
            } else {
                System.err.println("Error: no imshow associated with namedWindow: \"" + win.name + "\"");
                System.exit(-1);
            }
        }

        try {
            if (delay == 0) {
                latch.await();
            } else {
                latch.await((long)delay, TimeUnit.MILLISECONDS);
            }
        } catch (InterruptedException var7) {
            var7.printStackTrace();
        }

        for(var8 = windows.values().iterator(); var8.hasNext(); win.alreadyUsed = true) {
            win = (ImageWindow)var8.next();
        }

        return pressedKey;
    }

    public static void destroyWindow(String winname) {
        ImageWindow tmpWin = (ImageWindow)windows.get(winname);
        if (tmpWin != null) {
            windows.remove(winname);
        }

    }

    public static void destroyAllWindows() {
        windows.clear();
    }

    public static void resizeWindow(String winname, int width, int height) {
        ImageWindow tmpWin = (ImageWindow)windows.get(winname);
        if (tmpWin != null) {
            tmpWin.setNewDimension(width, height);
        }

    }

    public static void moveWindow(String winname, int x, int y) {
        ImageWindow tmpWin = (ImageWindow)windows.get(winname);
        if (tmpWin != null) {
            tmpWin.setNewPosition(x, y);
        }

    }
}

So wie ich das sehe sollte die imshow() Methode ein neues ImageWindow erstellen wenn der übergebene Name noch nicht verwendet wurde. Aber das tut es ja bei mir irgendwie nicht, sondern es wird das bestehende Window überschrieben.

2. destroyallWindows() scheint ja nur die Einträge der ImageWindows aus der Map zu löschen. Damit wäre dann immerhin klar wieso das Fenster trotzdem offen bleibt.

Zu System.exit(0): Selbst wann zeigt die IDE erst dann an, dass das Programm nicht mehr läuft wenn ich die Maus bewege und wenn ich nur die Femster schließen will aber das Programm danach noch weiter gehen soll bringt es auch nichts :/
 
Hallo du befindest dich ja in einer Endlosschleife „while(true)“

Frage wird das "If(camera.read(frame))"

überhaupt irgendwann mal false und kommst du in den else zweig wo du die Schleife beendest ?


Das VideoCapture wird doch bestimmt auch in einem Thread ausgeführt ich sehe nichts wo du Play beendest. So das der VideoThread beendet wird.
 
Zuletzt bearbeitet:
System.exit(0): beendet das Programm. Ob da auch immer alle gestarteten Threads mit beendet werden bin ich mir nicht sicher.
 
Hmm, ich wundere mich gerade, was für ein HighGui JavaDoc ich eben vor mir hatte. Denn ich hatte da nach einer Dokumentation gesucht und bin da irgendwie drüber gestolpert.

Die Fenster sind aber da auch alle erreichbar, da public static - damit wäre ein direkter Zugiff auf alle Windows möglich.

System.exit(0): beendet das Programm. Ob da auch immer alle gestarteten Threads mit beendet werden bin ich mir nicht sicher.
Da die ganze JVM beendet wird, werden alle Threads beendet. ("Terminates the currently running Java Virtual Machine")
 
Hallo du befindest dich ja in einer Endlosschleife „while(true)“

Frage wird das "If(camera.read(frame))"

überhaupt irgendwann mal false und kommst du in den else zweig wo du die Schleife beendest ?


Das VideoCapture wird doch bestimmt auch in einem Thread ausgeführt ich sehe nichts wo du Play beendest. So das der VideoThread beendet wird.

Ja, wenn das Video zu Ende ist wird das false und die Schleife verlassen. Das wird auch durch meine debug Ausgabe

Java:
 System.out.println(" end reached");

bestätigt.
 
So wie ich das sehe sollte die imshow() Methode ein neues ImageWindow erstellen wenn der übergebene Name noch nicht verwendet wurde. Aber das tut es ja bei mir irgendwie nicht, sondern es wird das bestehende Window überschrieben.
Wenn ich es richtig sehe, funktioniert der Spaß folgendermaßen:
  1. imshow() legt ein ImageWindow-Objekt in eine Map
  2. in waitKey() wird zu jedem noch nicht "verbrauchten" ImageWindow-Objekt der Map ein JFrame erzeugt. Die bereits "verbrauchten" ImageWindow-Objekte werden aus der Map entfernt wobei die mit ihnen assoziierten JFrames abgeräumt werden.
  3. in waitKey() wird dann auf ein Ereignis (Tastendruck, Schließen des Fensters, Timeout) gewartet.
  4. Nach dem Ereignis aus 3. werden alle ImageWindow-Objekte, die sich zu diesem Zeitpunkt in der Map befinden, als "verbraucht" markiert.
waitKey() schließt somit alle Fenster, die sich beim Aufruf zuvor in der Map befanden. Um mit dieser Klasse das gewünschte Ergebnis zu erzielen, dürftest Du folglich nach einem waitKey() über die windows iterieren und bei allen Fenstern, die offen bleiben sollen, das Flag alreadyUsed auf false setzen müssen. Am Ende müsstest Du nochmal waitKey mit kurzem Timeout aufrufen, um auch das letzte Fenster zu schließen.
 

Zurück
Oben