J'ai eu la chance de découvrir comment «détecter des images similaires» pendant un moment, et dans le processus, je pensais aux vidéos.
\(^o^)/
J'ai eu l'idée simple et j'ai décidé d'en faire un peu. ** En développement **
image d'écran
Java (Java 9) est utilisé sous Windows et Eclipse est utilisé comme IDE. La création de l'interface graphique est Scene Builder ou JavaFX.
L'installation d'OpenCV crée des fichiers JAR et des DLL. Placez-les dans un endroit où ils peuvent être lus.
opencv/build/java/x64/opencv_java330.dll
opnecv/build/bin/opencv_ffmpeg330_64.dll
→ Copier dans Windows \ System32 \
→ Copier sous le chemin de classe, ajouter depuis Eclipse
De plus, en Java, il était nécessaire de décrire le processus de chargement dans une classe qui utilise OpenCV comme indiqué ci-dessous.
static {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
}
Extrayez certaines images de la vidéo sous forme d'images. Ici, j'ai décidé d'extraire 9 images. Il n'y a pas de base particulière, mais c'est un jugement qu'il semble bon lorsqu'il est arrangé en 3x3 avec GUI. Étant donné que la première et la dernière image sont susceptibles d'être assombries, enregistrez 9 images séparées par 10. -> Détection de différence FPS ...?
En outre, toutes les images extraites sont mises à l'échelle de manière à ce que la largeur soit de 200 pixels, puis enregistrées. -> Détection de différence de taille ...?
↓ Cela ressemble à ceci.
static public VideoMetadata captureFrame(Config config, String videoFile) {
// ------------------------------------------------------------------
//Ouvrez la vidéo
// ------------------------------------------------------------------
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();
}
// ------------------------------------------------------------------
//Acquisition d'informations vidéo
// ------------------------------------------------------------------
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);
// ------------------------------------------------------------------
//Obtenez le nombre d'images spécifié dans les paramètres
// ------------------------------------------------------------------
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;
}
Dans la section précédente, nous avons fait 9 images par vidéo. Cette fois, nous comparerons cela.
Concernant la comparaison des images, j'ai décidé de comparer les histogrammes. Je pense qu'il y a beaucoup de place à considérer à cet égard.
La moyenne des résultats de comparaison de chacune des 9 images a été utilisée comme résultat de comparaison de la vidéo entière.
Le code est ci-dessous.
static public VideoComparison compareImages(Config config, VideoMetadata video1, VideoMetadata video2) {
List<Double> histList = new ArrayList<Double>();
// ------------------------------------------------------------------
//Comparer par image
// ------------------------------------------------------------------
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;
}
// ------------------------------------------------------------------
//histogramme
// ------------------------------------------------------------------
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;
}
Je veux en faire une interface graphique car elle gère les images. J'étais inquiet, mais j'ai décidé de le faire avec JavaFX pour commémorer la sortie de Java9. (JavaFX est 8 ...)
Dans JavaFX, la mise en page de conception peut être décrite en XML (fxml) et Scene Builder peut la modifier graphiquement. La liaison XML et le code se fait avec l'attribut fx: id en XML et l'annotation @FMXL en .java.
Par exemple, si la commande du bouton d'exécution est organisée comme suit,
<Button fx:id="executeBtn" layoutX="214.0" layoutY="31.0" mnemonicParsing="false" onAction="#doExecuteAction" prefHeight="38.0" prefWidth="115.0" text="execute" />
Du côté du code Java, procédez comme suit:
@FXML
void doExecuteAction(ActionEvent event) {
// ...
}
Vous pouvez maintenant joindre le processus qui sera exécuté lorsque vous appuyez sur le bouton.
Les commandes et actions utilisées cette fois sont les suivantes.
--Exécuter
ajouter à
Effacer
ListView
TableView
Choix
ImgView
J'ai écrit le code en Java pour la première fois depuis longtemps, mais il y a de nombreux aspects ennuyeux dans l'utilisation personnelle. En fait, je l'ai écrit en Python au début, mais je voulais en faire une interface graphique, que dois-je faire avec les threads et ainsi de suite ... → OpenCV peut aussi être fait avec Java. Alors je l'ai fait Java.
J'ai l'impression que je n'ai pas fait d'interface graphique en Java depuis AWT, mais JavaFX était meilleur que ce à quoi je m'attendais.
Le reste est autour de ce qui suit.
Cela prend du temps s'il y a beaucoup de fichiers
Bien qu'il soit traité par parallelStream, il semble y avoir de la place pour un réglage en termes de temps de traitement.
--Visualisation de l'état du traitement
--Mise en place de la barre de progression
--Afficher le journal d'état du traitement
--Comparaison par quantité de fonctionnalités.
--Autre ...?
La programmation des fêtes était amusante. fin.
Client Technology: Java Platform, Standard Edition (Java SE) 8 Release 8
JavaFX Scene Builder 1.x Archive
Développement de JavaFX 8 avec Eclipse à l'aide de Designer-Qiita
bitWalk's: JavaFX: ListView avec CheckBox
Recommended Posts