This repository has been archived by the owner on Dec 22, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
22 changed files
with
1,054 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,17 @@ | ||
# VideoComparison | ||
A video comparison tool which use pHash and is based on java. | ||
A video comparison tool based on java. This tool uses the pHash algorithm to hash a stack of frames (average frame per second). At the moment only the Windows operating system is supported. Depending on interests Linux and MacOS will follow. | ||
This tool uses the OpenCV-411 and FFMPEG library, which are noted in `src/lib`. These files are not included in this repository. | ||
|
||
The tools search recursively in the video directory for video. Then it generates a chain of hashes and compares the hash chains with a "Shifted Longest Common Subhash" algorithm (self defined name). | ||
The result is then written to the defined file in CSV format. This list can then be sorted by the percentage of match. | ||
|
||
At the moment the following parameters are offered: | ||
``` | ||
{-vd,-video_directory} Required: yes Video directory | ||
{-rp,-result_path} Required: no Result path (default './result.csv') | ||
{-pc,-phash_collection} Required: no Select a pHash collection source and/or saving destination (default '') | ||
{-t,-threads} Required: no Number of threads (default '1') | ||
{-hs,-hash_size} Required: no Size of the hash (default '256') | ||
{-senp,-save_each_n_percentage} Required: no How often (percentage steps) should the hashs be saved (0=only at end) (default '10') | ||
{-duh,-drop_unneeded_hashs} Required: no Drop unneeded hashs in given collection (default 'no') | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import java.io.File; | ||
import java.io.FileOutputStream; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.io.OutputStream; | ||
|
||
import exceptions.NotSupportedException; | ||
/** | ||
* Class to load the native libraries | ||
* | ||
* @author Steven | ||
* @version 0.1 | ||
*/ | ||
public class LibraryLoader { | ||
|
||
/** | ||
* Load native libraries from given path | ||
* | ||
* @param path Path to the library | ||
* @throws Exception | ||
*/ | ||
public static void loadLibrary(String path) throws IOException { | ||
InputStream inputStream = VideoComparison.class.getResourceAsStream(path); | ||
File fileOut = File.createTempFile("lib", ".dll"); | ||
if (fileOut != null) { | ||
OutputStream outputStream = new FileOutputStream(fileOut); | ||
byte[] buffer = new byte[1024]; | ||
int length; | ||
while ((length = inputStream.read(buffer)) > 0) { | ||
outputStream.write(buffer, 0, length); | ||
} | ||
inputStream.close(); | ||
outputStream.close(); | ||
System.load(fileOut.toString()); | ||
} | ||
} | ||
|
||
/** | ||
* Load all needed native libraries | ||
* | ||
* @throws Exception | ||
*/ | ||
public static void loadLibrary() throws Exception { | ||
String osName = System.getProperty("os.name"); | ||
if (osName.startsWith("Windows")) { | ||
int bitness = Integer.parseInt(System.getProperty("sun.arch.data.model")); | ||
if (bitness == 64) { | ||
loadLibrary("/lib/x64/opencv_java411.dll"); | ||
loadLibrary("/lib/x64/opencv_videoio_ffmpeg411_64.dll"); | ||
} else { | ||
loadLibrary("/lib/x86/opencv_java411.dll"); | ||
loadLibrary("/lib/x86/opencv_videoio_ffmpeg411.dll"); | ||
} | ||
} else { | ||
throw new NotSupportedException("OS \"" + osName + "\" not supported at this version."); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
import java.io.File; | ||
import java.text.DecimalFormat; | ||
import java.text.SimpleDateFormat; | ||
import java.util.Date; | ||
|
||
import argument.definition.flag.FlagArgumentDefinition; | ||
import argument.definition.integer.IntegerArgumentDefinition; | ||
import argument.definition.integer.rules.IntegerArgumentProportionRule; | ||
import argument.definition.integer.rules.IntegerArgumentRule; | ||
import argument.definition.rules.NumberProportionRuleType; | ||
import argument.definition.string.StringArgumentDefinition; | ||
import argument.definition.string.rules.StringArgumentRule; | ||
import argument.parser.ArgumentParser; | ||
import task.data.TaskDataManager; | ||
import task.hash.PHash; | ||
import task.lcs.ShiftToLongestCommonSubstring; | ||
import task.manager.ComparisonTaskManager; | ||
import task.manager.HashTaskManager; | ||
import task.manager.TaskManager; | ||
/** | ||
* This is the main class of this application. | ||
* | ||
* @author Steven Cybinski | ||
* @version 0.1 | ||
*/ | ||
public class VideoComparison { | ||
/** | ||
* Main function. | ||
* | ||
* @param args | ||
*/ | ||
public static void main(String[] args) { | ||
try { | ||
System.out.print(new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(new Date()) + ": Parse-Arguments -> "); | ||
ArgumentParser argumentParser = new ArgumentParser(true, true, true); | ||
argumentParser.addHelpArgument(new String[] {"-h", "-help"}, "This arguments are available:"); | ||
StringArgumentDefinition videoDirPath = new StringArgumentDefinition(new String[]{"-vd", "-video_directory"}, "Video directory", true, "", new StringArgumentRule[] {}); | ||
StringArgumentDefinition resultPath = new StringArgumentDefinition(new String[]{"-rp", "-result_path"}, "Result path", false, "./result.csv", new StringArgumentRule[] {}); | ||
StringArgumentDefinition pHashCollectionPath = new StringArgumentDefinition(new String[]{"-pc", "-phash_collection"}, "Select a pHash collection source and/or saving destination", false, "", new StringArgumentRule[] {}); | ||
IntegerArgumentDefinition threads = new IntegerArgumentDefinition(new String[] {"-t", "-threads"}, "Number of threads", false, 1, new IntegerArgumentRule[] {new IntegerArgumentProportionRule(NumberProportionRuleType.GREATER_EQUAL, 1)}); | ||
IntegerArgumentDefinition hashSize = new IntegerArgumentDefinition(new String[] {"-hs", "-hash_size"}, "Size of the hash", false, 256, new IntegerArgumentRule[] {new IntegerArgumentProportionRule(NumberProportionRuleType.GREATER_EQUAL, 4)}); | ||
IntegerArgumentDefinition saveEachNPercentage = new IntegerArgumentDefinition(new String[] {"-senp", "-save_each_n_percentage"}, "How often (percentage steps) should the hashs be saved (0=only at end)", false, 10, new IntegerArgumentRule[] {new IntegerArgumentProportionRule(NumberProportionRuleType.GREATER_EQUAL, 0)}); | ||
FlagArgumentDefinition dropUnneededHashs = new FlagArgumentDefinition(new String[] {"-duh", "-drop_unneeded_hashs"}, "Drop unneeded hashs in given collection", false, false); | ||
argumentParser.add(videoDirPath); | ||
argumentParser.add(resultPath); | ||
argumentParser.add(pHashCollectionPath); | ||
argumentParser.add(threads); | ||
argumentParser.add(hashSize); | ||
argumentParser.add(saveEachNPercentage); | ||
argumentParser.add(dropUnneededHashs); | ||
argumentParser.parse(args); | ||
System.out.println("OK"); | ||
|
||
if(!isValidSequenceMember(4, hashSize.getValue())) { | ||
throw new Exception("The size must be in the sequence of four (e.g. 4, 16, 64, ...)"); | ||
} | ||
|
||
System.out.print(new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(new Date()) + ": Load library -> "); | ||
LibraryLoader.loadLibrary(); | ||
System.out.println("OK"); | ||
|
||
System.out.print(new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(new Date()) + ": Search for available videos -> "); | ||
TaskDataManager taskDataManager = new TaskDataManager(); | ||
taskDataManager.searchVideos(videoDirPath.getValue()); | ||
if(taskDataManager.pathsSize() <= 1) { | ||
throw new Exception("Path must contain at least two video files"); | ||
} | ||
System.out.println("Found " + taskDataManager.pathsSize()); | ||
|
||
if(pHashCollectionPath.getValue().length() > 0) { | ||
System.out.print(new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(new Date()) + ": Check for available hash collection -> "); | ||
File pHashCollectionFile = new File(pHashCollectionPath.getValue()); | ||
if(pHashCollectionFile.exists() && pHashCollectionFile.isFile()) { | ||
System.out.print("[Load] "); | ||
taskDataManager.loadCollection(pHashCollectionPath.getValue()); | ||
} else { | ||
System.out.print("[Create new] "); | ||
pHashCollectionFile.createNewFile(); | ||
} | ||
System.out.println("OK"); | ||
} | ||
|
||
boolean finished = false; | ||
double[] progress = new double[] {-1, -1, -1}; | ||
double previousProgress = -1; | ||
int lastSave = 0; | ||
System.out.println(new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(new Date()) + ": Creat " + (threads.getValue()>1?threads.getValue() + " worker-threads":" worker-thread") + " and run hash calculation:"); | ||
TaskManager taskManager = new HashTaskManager(taskDataManager, threads.getValue(), new PHash(hashSize.getValue())); | ||
taskManager.run(); | ||
do { | ||
finished = taskManager.isFinished(); | ||
progress = taskManager.getProgress(); | ||
if(progress[1] != previousProgress) { | ||
previousProgress = progress[1]; | ||
String progressbar = ""; | ||
for(int i=10; i<=100; i+=10) { | ||
progressbar += (i <= progress[0])?"#":" "; | ||
} | ||
System.out.print("|" + progressbar + "| " + new DecimalFormat("000.00").format(progress[0]) + "% [" + ((int) progress[1]) + "/" + ((int) progress[2]) + "]\r"); | ||
} | ||
if(pHashCollectionPath.getValue().length() > 0 && saveEachNPercentage.getValue() != 0 && lastSave + saveEachNPercentage.getValue() <= progress[0]) { | ||
while(lastSave + saveEachNPercentage.getValue() <= progress[0]) { | ||
lastSave += saveEachNPercentage.getValue(); | ||
} | ||
taskDataManager.saveCollection(pHashCollectionPath.getValue(), true); | ||
} | ||
Thread.sleep(10); | ||
} while(!finished); | ||
|
||
if(pHashCollectionPath.getValue().length() > 0) { | ||
taskDataManager.saveCollection(pHashCollectionPath.getValue(), !dropUnneededHashs.getValue()); | ||
} | ||
|
||
System.out.println(""); | ||
System.out.print(new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(new Date()) + ": Create compare list -> "); | ||
taskDataManager.generateComparisonList(); | ||
System.out.println("OK"); | ||
|
||
finished = false; | ||
previousProgress = -1; | ||
System.out.println(new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(new Date()) + ": Creat " + (threads.getValue()>1?threads.getValue() + " worker-threads":" worker-thread") + " and run comparison:"); | ||
taskManager = new ComparisonTaskManager(taskDataManager, threads.getValue(), new ShiftToLongestCommonSubstring(hashSize.getValue())); | ||
taskManager.run(); | ||
do { | ||
finished = taskManager.isFinished(); | ||
progress = taskManager.getProgress(); | ||
if(progress[1] != previousProgress) { | ||
previousProgress = progress[1]; | ||
String progressbar = ""; | ||
for(int i=10; i<=100; i+=10) { | ||
progressbar += (i <= progress[0])?"#":" "; | ||
} | ||
System.out.print("|" + progressbar + "| " + new DecimalFormat("000.00").format(progress[0]) + "% [" + ((int) progress[1]) + "/" + ((int) progress[2]) + "]\r"); | ||
} | ||
Thread.sleep(10); | ||
} while(!finished); | ||
|
||
System.out.println("\r\n" + new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(new Date()) + ": "); | ||
taskDataManager.saveResult(resultPath.getValue()); | ||
System.out.println("OK"); | ||
|
||
System.out.println(new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(new Date()) + ": Finished."); | ||
} catch (Exception e) { | ||
System.err.println(e.getMessage()); | ||
e.printStackTrace(); | ||
} | ||
} | ||
|
||
/** | ||
* Check if a given number is in a given sequence. | ||
* | ||
* @param seq Sequence where n must be included | ||
* @param n Number to check | ||
* @return Is n a member of the given sequence | ||
*/ | ||
static boolean isValidSequenceMember(int seq, int n) { | ||
int nBinary = seq; | ||
do { | ||
if (n == nBinary) { | ||
return true; | ||
} | ||
nBinary *= seq; | ||
} while (nBinary <= n); | ||
return false; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package exceptions; | ||
/** | ||
* Simple custom exception class if class without functionality is used | ||
* | ||
* @author Steven Cybinski | ||
* @version 0.1 | ||
*/ | ||
public class NotExtendsException extends Exception { | ||
private static final long serialVersionUID = 2177455068671395760L; | ||
/** | ||
* Constructor of the class | ||
* | ||
* @param message Message of this exception | ||
*/ | ||
public NotExtendsException(String message) { | ||
super(message); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package exceptions; | ||
/** | ||
* Simple custom exception class if action is not supported in this version | ||
* | ||
* @author Steven Cybinski | ||
* @version 0.1 | ||
*/ | ||
public class NotSupportedException extends Exception { | ||
private static final long serialVersionUID = 1889837977001071866L; | ||
|
||
/** | ||
* Constructor of the class | ||
* | ||
* @param message Message of this exception | ||
*/ | ||
public NotSupportedException(String message) { | ||
super(message); | ||
} | ||
} |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
opencv-411.jar |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
opencv_java411.dll |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
opencv_videoio_ffmpeg411_64.dll |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
opencv_java411.dll |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
opencv_videoio_ffmpeg411.dll |
Oops, something went wrong.