Ich hatte die Gelegenheit, für einen Moment herauszufinden, wie man "ähnliche Bilder erkennt", und dabei dachte ich über Videos nach.
\(^o^)/
Ich kam auf die einfache Idee und beschloss, ein wenig zu machen. ** In Entwicklung **
Bildschirmbild
Java (Java 9) wird unter Windows verwendet, und Eclipse wird als IDE verwendet. Das Erstellen der GUI erfolgt mit Scene Builder oder JavaFX.
Durch die Installation von OpenCV werden Jars und DLLs erstellt. Platzieren Sie sie an einem Ort, an dem sie gelesen werden können.
opencv/build/java/x64/opencv_java330.dll
opnecv/build/bin/opencv_ffmpeg330_64.dll
→ Nach Windows \ System32 \ kopieren
→ Unter Klassenpfad kopieren, aus Eclipse hinzufügen
Darüber hinaus war es in Java erforderlich, den Ladevorgang in einer Klasse zu beschreiben, die OpenCV verwendet (siehe unten).
static {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
}
Extrahieren Sie einige Bilder aus dem Video als Bilder. Hier habe ich beschlossen, 9 Bilder zu extrahieren. Es gibt keine bestimmte Grundlage, aber es ist ein Urteil, dass es gut aussieht, wenn es in 3x3 mit GUI angeordnet wird. Da das erste und das letzte Bild wahrscheinlich abgedunkelt sind, speichern Sie 9 durch 10 getrennte Bilder. -> FPS-Differenzerkennung ...?
Außerdem werden alle extrahierten Bilder so vergrößert und verkleinert, dass die Breite 200 Pixel beträgt, und dann gespeichert. -> Erkennung von Größenunterschieden ...?
↓ Es sieht so aus.
static public VideoMetadata captureFrame(Config config, String videoFile) {
// ------------------------------------------------------------------
//Öffne das Video
// ------------------------------------------------------------------
System.out.println(videoFile);
VideoCapture capture = new VideoCapture(videoFile);
if (!capture.isOpened()) {
System.out.println("file not opened.");
return null;
}
String outputDir = config.getTempDir() + "/" + String.valueOf(videoFile.hashCode()).replace("-", "_");
File dir = new File(outputDir);
if (!dir.exists()) {
dir.mkdir();
}
// ------------------------------------------------------------------
//Erfassung von Videoinformationen
// ------------------------------------------------------------------
double fps = capture.get(Videoio.CV_CAP_PROP_FPS);
int resizeHeight = (int) (config.getImageWidth() / capture.get(Videoio.CV_CAP_PROP_FRAME_WIDTH)
* capture.get(Videoio.CV_CAP_PROP_FRAME_HEIGHT));
double allFrameCnt = capture.get(Videoio.CV_CAP_PROP_FRAME_COUNT);
int captureInterval = (int) (allFrameCnt / (config.getCaptureCount() + 1));
long time = (long) (allFrameCnt / fps);
// ------------------------------------------------------------------
//Ruft die Anzahl der in den Einstellungen angegebenen Frames ab
// ------------------------------------------------------------------
for (int i = 1; i < config.getCaptureCount() + 1; i++) {
int frameIndex = captureInterval * i;
Mat orgFrame = new Mat();
Mat resizedFrame = new Mat();
capture.set(Videoio.CV_CAP_PROP_POS_FRAMES, frameIndex - 1);
if (!capture.read(orgFrame)) {
continue;
}
Imgproc.resize(orgFrame, resizedFrame, new Size(config.getImageWidth(), resizeHeight));
Imgcodecs.imwrite(outputDir + "/" + i + ".jpg ", resizedFrame);
}
VideoMetadata metadata = new VideoMetadata();
metadata.setFilename(videoFile);
metadata.setFrameDirname(outputDir);
metadata.setPlayTime(time);
return metadata;
}
Im vorherigen Abschnitt haben wir 9 Bilder pro Video erstellt. Dieses Mal werden wir dies vergleichen.
In Bezug auf den Vergleich von Bildern habe ich beschlossen, die Histogramme zu vergleichen. Ich denke, diesbezüglich gibt es viel Raum für Überlegungen.
Der Durchschnitt der Vergleichsergebnisse jedes der 9 Bilder wurde als Vergleichsergebnis des gesamten Videos verwendet.
Der Code ist unten.
static public VideoComparison compareImages(Config config, VideoMetadata video1, VideoMetadata video2) {
List<Double> histList = new ArrayList<Double>();
// ------------------------------------------------------------------
//Vergleichen Sie nach Bild
// ------------------------------------------------------------------
for (int i = 1; i < config.getCaptureCount() + 1; i++) {
String filename1 = video1.getFrameDirname() + "/" + i + ".jpg ";
String filename2 = video2.getFrameDirname() + "/" + i + ".jpg ";
File file1 = new File(filename1);
File file2 = new File(filename2);
if (!(file1.exists() && file2.exists())) {
continue;
}
// ------------------------------------------------------------------
//Histogramm
// ------------------------------------------------------------------
Mat img1 = Imgcodecs.imread(filename1);
List<Mat> src1 = new ArrayList<Mat>();
src1.add(img1);
Mat hist1 = new Mat();
Imgproc.calcHist(src1, new MatOfInt(0), new Mat(), hist1, new MatOfInt(256), new MatOfFloat(0, 256));
Mat img2 = Imgcodecs.imread(filename2);
List<Mat> src2 = new ArrayList<Mat>();
src2.add(img2);
Mat hist2 = new Mat();
Imgproc.calcHist(src2, new MatOfInt(0), new Mat(), hist2, new MatOfInt(256), new MatOfFloat(0, 256));
histList.add(Imgproc.compareHist(hist1, hist2, 0));
}
VideoComparison videoComparison = new VideoComparison();
videoComparison.setVideo1(video1);
videoComparison.setVideo2(video2);
videoComparison.setHist(calcAvg(histList));
return videoComparison;
}
Ich möchte es zu einer GUI machen, weil es Bilder verarbeitet. Ich war besorgt, aber ich entschied mich, es mit JavaFX zu machen, um an die Veröffentlichung von Java9 zu erinnern. (JavaFX ist 8 ...)
In JavaFX kann das Entwurfslayout in XML (fxml) beschrieben werden, und Scene Builder kann dies grafisch bearbeiten. XML und Code werden durch das Attribut fx: id in XML und die Annotation @FMXL in .java verknüpft.
Wenn beispielsweise die Steuerung der Ausführungsschaltfläche wie folgt angeordnet ist,
<Button fx:id="executeBtn" layoutX="214.0" layoutY="31.0" mnemonicParsing="false" onAction="#doExecuteAction" prefHeight="38.0" prefWidth="115.0" text="execute" />
Gehen Sie auf der Java-Codeseite wie folgt vor:
@FXML
void doExecuteAction(ActionEvent event) {
// ...
}
Jetzt können Sie den Vorgang anhängen, der ausgeführt wird, wenn Sie die Taste drücken.
Die diesmal verwendeten Steuerelemente und Aktionen sind wie folgt.
--Ausführen
hinzufügen
Löschen
ListView
TableView
Wahl
ImgView
Ich habe den Code zum ersten Mal seit langer Zeit in Java geschrieben, aber es gibt viele nervige Aspekte im persönlichen Gebrauch. Eigentlich habe ich es zuerst in Python geschrieben, aber ich wollte es zu einer GUI machen, was soll ich mit Threads machen und so weiter ... → OpenCV kann auch mit Java gemacht werden. Also habe ich es Java gemacht.
Ich habe das Gefühl, dass ich seit AWT keine GUI in Java mehr gemacht habe, aber JavaFX war besser als ich erwartet hatte.
Der Rest dreht sich um Folgendes.
Es braucht Zeit, wenn es viele Dateien gibt
Obwohl es von parallelStream verarbeitet wird, scheint es Raum für eine Optimierung der Verarbeitungszeit zu geben.
--Visualisierung des Verarbeitungsstatus
--Verarbeitungsstatusprotokoll anzeigen
Verbesserte Bildvergleichsgenauigkeit
Vergleich nach Merkmalsmenge.
--Andere ...?
Urlaubsprogrammierung hat Spaß gemacht. Ende.
Client-Technologie: Java-Plattform, Standard Edition (Java SE) 8, Version 8
JavaFX Scene Builder 1.x Archive
Entwickeln von JavaFX 8 mit Eclipse mithilfe von Designer-Qiita
bitWalk's: JavaFX: ListView mit CheckBox
Recommended Posts