Détecter des vidéos similaires dans Java et OpenCV rev.3

Nous y travaillons encore.

Détection de vidéos similaires en Java et OpenCV rev.1 --Qiita

Détection de vidéos similaires en Java et OpenCV rev.2 --Qiita

Cache des résultats

En enregistrant le résultat pour le fichier qui a été traité une fois, le traitement d'image n'est pas effectué par OpenCV pour la deuxième fois.

Enregistrer le tapis

Le tapis de l'image doit être enregistré en tant qu'image par imwrite, mais le résultat du calcul de l'histogramme, etc. n'a pas pu être enregistré par imwrite et lu par imread.

Il existe un moyen générique d'enregistrer Mat dans un fichier en C ++, mais il semble que vous deviez le créer vous-même car il n'y a rien d'encapsulé en Java.

Puisque Mat est une matrice, c'est-à-dire des données matricielles, elle peut être exprimée verticalement, horizontalement et sous forme de tableau de données. Dans le cas de Mat, en plus de cela, il aura un code de type qui représente le type de données.

À cette fin, la quantité de données n'est pas si grande, je vais donc la sauvegarder en tant que données json. J'ai utilisé la bibliothèque gson de google pour gérer json.

C'est la partie de sauvegarde.

	/**
	 *Enregistrer le tapis dans un fichier
	 * @param filename
	 * @param mat
	 * @throws IOException
	 */
	public static void storeMat(String filename, Mat mat) throws IOException {
		String jsondata = matToJson(mat);
		PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(new File(filename))));
		writer.write(jsondata);
		writer.close();
	}

	/**
	 *Convertir Mat au format Json
	 * @param mat
	 * @return
	 */
	public static String matToJson(Mat mat) {
		JsonObject obj = new JsonObject();

		if (mat.isContinuous()) {
			int cols = mat.cols();
			int rows = mat.rows();
			int elemSize = (int) mat.elemSize();
			int type = mat.type();
			String typeStr = CvType.typeToString(type);
			int dataSize = cols * rows * elemSize;
			if (rows == 0) {
				dataSize = cols * elemSize;
			}

			String dataString = "";
			if (typeStr.contains("32F")) {
				float[] data = new float[dataSize];
				String[] strData = new String[dataSize];
				mat.get(0, 0, data);
				for (int i = 0; i < data.length; i++) {
					strData[i] = String.valueOf(data[i]);
				}
				dataString = String.join(",", strData);
			} else if (typeStr.contains("8U")) {
				byte[] data = new byte[dataSize];
				String[] strData = new String[dataSize];
				mat.get(0, 0, data);
				for (int i = 0; i < data.length; i++) {
					strData[i] = String.valueOf(data[i]);
				}
				dataString = String.join(",", strData);
			}

			obj.addProperty("rows", mat.rows());
			obj.addProperty("cols", mat.cols());
			obj.addProperty("type", mat.type());
			obj.addProperty("data", dataString);

			Gson gson = new Gson();
			String json = gson.toJson(obj);

			return json;
		} else {
			System.err.println("");
		}
		return "{}";
	}

Ceci est la partie lecture.

	/**
	 *Lire le tapis à partir d'un fichier
	 * @param filename
	 * @return
	 * @throws IOException
	 */
	public static Mat loadMat(String filename) throws IOException {
		InputStream input = new FileInputStream(filename);
		int size = input.available();
		byte[] buffer = new byte[size];
		input.read(buffer);
		input.close();
		return matFromJson(new String(buffer));
	}

	/**
	 *Créer un tapis à partir de Json
	 * @param json
	 * @return
	 */
	public static Mat matFromJson(String json) {
		JsonParser parser = new JsonParser();
		JsonObject JsonObject = parser.parse(json).getAsJsonObject();

		int rows = JsonObject.get("rows").getAsInt();
		int cols = JsonObject.get("cols").getAsInt();
		int type = JsonObject.get("type").getAsInt();
		String typeStr = CvType.typeToString(type);

		String dataString = JsonObject.get("data").getAsString();
		Mat mat = new Mat(rows, cols, type);
		String[] splitedStr = dataString.split(",");
		if (typeStr.contains("32F")) {
			float[] data = new float[splitedStr.length];
			for (int i = 0; i < data.length; i++) {
				data[i] = Float.parseFloat(splitedStr[i]);
			}
			mat.put(0, 0, data);
		} else if (typeStr.contains("8U")) {
			byte[] data = new byte[splitedStr.length];
			for (int i = 0; i < data.length; i++) {
				data[i] = Byte.parseByte(splitedStr[i]);
			}
			mat.put(0, 0, data);
		} else {
			System.err.println("");
		}

		return mat;
	}

Le type Mat est uniquement pour 8U et 32F, et c'est un peu exagéré pour un usage général. Si nécessaire, comme 64F → double, il est nécessaire d'ajouter pour chaque type.

Python (pandas) est supérieur dans la gestion des matrices et json ici.

Enregistrer d'autres informations vidéo

Je l'ai enregistré en tant que fichier de propriétés à l'aide de java.util.Properties.

Properties videoProperty = new Properties();
videoProperty.setProperty("playtime", String.valueOf(time));
videoProperty.setProperty("width", String.valueOf(width));
videoProperty.setProperty("height", String.valueOf(height));
videoProperty.setProperty("fps", String.valueOf(fps));
videoProperty.setProperty("size", String.valueOf(fileSize));
videoProperty.store(new FileOutputStream(metadata.getMetaFilename()), "");

Enregistrez le résultat de la comparaison

Au début, j'essayais de l'enregistrer en CSV, mais j'ai finalement décidé de l'enregistrer dans SQLite. J'ai abandonné le CSV car il y a plusieurs bibliothèques et je n'ai pas pu obtenir celle que j'ai choisie correctement.

La table créée.

CREATE TABLE IF NOT EXISTS compare_video ( 
	key text PRIMARY KEY, 
	file1 text, 
	file2 text, 
	timediff integer, 
	hist real, 
	feature real, 
	skip integer 
)

J'ai préparé un champ appelé "sauter" ici. Il s'agit d'un indicateur qui indique que ce résultat de comparaison est exclu du résultat et est défini lorsqu'il est jugé qu'il est différent lors de l'inspection visuelle, ou lorsque le temps de lecture est différent de 10% ou plus.

Améliorations de l'interface utilisateur

Ce qui suit a été ajouté pour faciliter l'utilisation.

--Afficher les métadonnées sur l'étiquette --Bouton pour déplacer la sélection de résultats de haut en bas --Bouton pour masquer le résultat du suivant --Bouton jouer

Pour la lecture, je souhaite le démarrer avec l'application associée, mais cela ne fonctionne pas ... Pour le moment, j'essaye de le démarrer avec une application fixe.

L'écran après le changement.

image

Le sens du design est délicat. ..

Autre

Libération diligente

N'oubliez pas d'appeler fréquemment Mat # release lorsque vous traitez un grand nombre d'images. Surtout dans le cas de Java, les ressources de l'objet Mat qui semble alloué par JNI ne sont pas visibles, donc soyez particulièrement prudent.

La même chose est vraie pour la capture vidéo.

Paramètres du logiciel antivirus

Lorsque je créais un grand nombre de fichiers, l'utilisation du processeur était élevée, mais la cause était un logiciel antivirus. Il semble préférable de le définir de manière à désactiver la recherche en temps réel du dossier cible.

référence

OpenCV Mat object serialization in java - Stack Overflow

Recommended Posts

Détecter des vidéos similaires dans Java et OpenCV rev.2
Détecter des vidéos similaires dans Java et OpenCV rev.3
Détecter des vidéos similaires dans Java et OpenCV rev.1
Utiliser OpenCV avec Java
Classe StringBuffer et StringBuilder en Java
Comprendre equals et hashCode en Java
Java + OpenCV 3.X avec IntelliJ IDEA
Bonjour tout le monde en Java et Gradle
Différence entre final et immuable en Java
J'ai fait l'étalonnage de la caméra OpenCV en Java
Différence entre les listes d'arry et les listes liées en Java
Programmer les en-têtes et pieds de page PDF en Java
Apprenez les modèles Flyweight et ConcurrentHashMap en Java
La direction de Java dans "C ++ Design and Evolution"
De Java à C et de C à Java dans Android Studio
Lire et écrire des fichiers gzip en Java
Différence entre int et Integer en Java
Discrimination d'énum dans Java 7 et supérieur
Concernant les modificateurs transitoires et la sérialisation en Java
Utilisez OpenCV_Contrib (ArUco) avec Java! (Partie 1-Construire) (OpenCV-3.4.4)
Traitement parallèle et parallèle dans divers langages (édition Java)
Différence entre next () et nextLine () dans Java Scanner
Différences dans l'écriture des classes Java, C # et Javascript
Capture et sauvegarde de l'installation de sélénium en Java
Ajouter, lire et supprimer des commentaires Excel à l'aide de Java
Vérifier le comportement statique et public dans les méthodes Java
[Java] Comprenez en 10 minutes! Tableau associatif et HashMap
Distinguer les nombres positifs et négatifs en Java
Java ajoute et supprime les filigranes dans les documents Word
Représente le «jour suivant» et le «jour précédent» en Java / Android
Questions sur la gestion des exceptions Java throw et try-catch
Télécharger et télécharger des notes en java sur S3
Crypter / décrypter avec AES256 en PHP et Java
Générer OffsetDateTime à partir de Clock et LocalDateTime en Java
Partition en Java
Changements dans Java 11
Janken à Java
Java et JavaScript
XXE et Java
Taux circonférentiel à Java
FizzBuzz en Java
[Android / Java] Transition d'écran et traitement de retour par fragments
Essayé l'API Toot et Streaming de Mastodon en Java
Écrivez ABNF en Java et transmettez l'adresse e-mail
Organiser les builds dans des combinaisons C ++ / Java et Win / Linux
Vectoriser et imager les données d'images numériques manuscrites MNIST avec Java
Ecrire une classe en Kotlin et l'appeler en Java
[Java] Différence entre statique final et final dans les variables membres
Classes et instances Java comprises dans la figure
Jonction Java et division des cellules de tableau dans un document Word
Ceci et cela pour éditer ini en Java. : inieditor-java
Comment convertir A en A et A en A en utilisant le produit logique et la somme en Java
Soustraire les constantes Enum des chaînes et des valeurs en Java
Utilisation correcte de la classe abstraite et de l'interface en Java