Skip to content

Commit

Permalink
added autotag feature. pretty print times. code organization. wmvs no…
Browse files Browse the repository at this point in the history
…t written as mkvs anymore.
  • Loading branch information
ryanjay0 committed Nov 16, 2016
1 parent 5108e9f commit 104dc40
Show file tree
Hide file tree
Showing 6 changed files with 367 additions and 144 deletions.
27 changes: 24 additions & 3 deletions README.md
Expand Up @@ -51,23 +51,23 @@ I'm working on a version for Windows. Sorry, I don't have a Mac but it should ru
##Usage ##Usage


Example: Example:
```shell ```bash
miles-deep -t sex_back,sex_front movie.mp4 miles-deep -t sex_back,sex_front movie.mp4
``` ```


This finds the scenes sex from the back or front and outputs the result This finds the scenes sex from the back or front and outputs the result
in `movie.cut.avi` in `movie.cut.avi`


Example: Example:
```shell ```bash
miles-deep -x movie.avi miles-deep -x movie.avi
``` ```


This edits out all the non-sexual scenes from `movie.avi` This edits out all the non-sexual scenes from `movie.avi`
and outputs the result in `movie.cut.avi`. and outputs the result in `movie.cut.avi`.


Example: Example:
``` ```bash
miles-deep -b 16 -t cunnilingus -o /cut_movies movie.mkv miles-deep -b 16 -t cunnilingus -o /cut_movies movie.mkv
``` ```


Expand All @@ -93,6 +93,27 @@ Tested on an Nvidia GTX 960 with 4GB VRAM and a 24.5 minute video file. At batch


In addition to batching, Miles Deep also uses threading, which allows the screenshots to be captured and processed while they are classified. In addition to batching, Miles Deep also uses threading, which allows the screenshots to be captured and processed while they are classified.


###Auto-Tagging Without Cutting

Example:
```bash
miles-deep movie.mp4 -a
```

By popular demand I added this option, which outputs `movie.tag`:

```
movie_name, label_1, ..., label_n
total_time, label_1_time, ..., label_n_time
label, start, end, score, coverage
.
.
.
```

The file contains the cuts for each target, ordered as they occur in the movie. The first lines give the movie name, the labels, the total movie time, and the total seconds for each label. Then for each cut it list the start time, end time, average score, and coverage. Because of the threshold and the gaps, these cuts may overlap and aren't guaranteed to cover ever second.

###Prediction Weights ###Prediction Weights
Here is an example of the predictions for each second of a video: Here is an example of the predictions for each second of a video:


Expand Down
272 changes: 153 additions & 119 deletions cut_movie.cpp
Expand Up @@ -13,77 +13,173 @@
#include <string> #include <string>


#include "cut_movie.hpp" #include "cut_movie.hpp"
#include "util.hpp"


using namespace std; using namespace std;


float scoreMax(vector<float> x) //find the cuts using the winners and their values (returns the cut_list)
int findTheCuts(int score_list_size, const vector<int>& winners,const vector<float>& vals,
const vector<int>& target_on, string target, int min_cut, int max_gap, float threshold, float min_coverage,
CutList* cut_list)
{ {
return *max_element(x.begin(), x.end());
}


int scoreArgMax(vector<float> x) int cut_start = -1;
{ int gap = 0;
return distance(x.begin(), max_element(x.begin(), x.end())); int win_sum = 0;
float val_sum = 0.0;
int total_size = 0;

for( int i=0; i<score_list_size; i++)
{
if( cut_start >= 0 )
{
if( target_on[winners[i]] )
{
win_sum++;
val_sum += vals[i];
}

if( !target_on[winners[i]] || vals[i] < threshold || i == score_list_size-1 )
{
if(i < score_list_size-1) gap++;

if( gap > max_gap || i == score_list_size-1 )
{
if( cut_start < i - gap - min_cut )
{
//output cut
int win_size = (i - gap) - cut_start + 1;
float score_avg = val_sum / (float)win_sum;
float coverage = (float)win_sum / (float)win_size;

if(coverage >= min_coverage)
{
cout << PrettyTime(cut_start) << " - " << PrettyTime(i - gap)
<< ": size= " << PrettyTime(win_size) << " coverage= " << coverage
<< " score= " << score_avg << '\n';
total_size += win_size;
Cut cut;
cut.s = cut_start;
cut.e = i-gap;
cut.score = score_avg;
cut.coverage = coverage;
cut.label = target;
cut_list->push_back(cut);
}
}
cut_start = -1;
gap = 0;
val_sum = 0.0;
win_sum = 0;
}
}
else
{
gap = 0;
}

}
else if( target_on[winners[i]] && vals[i] >= threshold )
{
cut_start = i;
gap = 0;
val_sum = 0.0;
win_sum = 0.0;
}
}

return(total_size);

} }


string getFileName(const string& s)
{
char sep = '/';


void TagTargets( ScoreList score_list, string movie_file, string output_dir,
vector<string> labels, int total_targets, int min_cut, int max_gap,
float threshold, float min_coverage)
{
//path stuff with movie file
char sep = '/';
#ifdef _WIN32 #ifdef _WIN32
sep = '\\'; char sep = '\\';
#endif #endif
string movie_base = getBaseName(getFileName(movie_file));
string movie_directory = getDirectory(movie_file);
string tag_movie = movie_base + ".tag";
if(output_dir == "")
output_dir = movie_directory;
string tag_path = output_dir + sep + tag_movie;


size_t i = s.rfind(sep, s.length()); //find winners and their scores
if( i != string::npos) vector<int> winners(score_list.size());
return(s.substr(i+1, s.length() -i)); vector<float> vals(score_list.size());
return(s); for( int i=0; i < score_list.size(); i++ )
} {
winners[i] = scoreArgMax(score_list[i]);
vals[i] = scoreMax(score_list[i]);
}


string getFileExtension(const string& s) //open tag output file
{ ofstream f(tag_path);
char sep = '.'; if(!f)
{
cerr << "Cannot open file: " << tag_path << endl;
exit(EXIT_FAILURE);
}


size_t i = s.rfind(sep, s.length()); //write header
if( i != string::npos) f << getFileName(movie_file) << ",";
return(s.substr(i, s.length() -i)); for(int i=0; i < labels.size(); i++)
return(s); f << labels[i] << ",";
} f << endl;


string getBaseName(const string& s) //find the predicted cuts for each target
{ vector<int> target_time(total_targets,0);
char sep = '.'; CutList cut_list;
for(int i=0; i < total_targets; i++)
{


size_t i = s.rfind(sep, s.length()); vector<int> target_on(total_targets,0);
if( i != string::npos) target_on[i] = 1;
return(s.substr(0, i));
return(s);
}


bool queryYesNo() cout << "Target [" << labels[i] << "]" << endl;
{
cout << "Replace movie with cut? This will delete the movie. [y/N]?"; target_time[i] = findTheCuts(score_list.size(), winners, vals, target_on, labels[i], min_cut,
string input; max_gap, threshold, min_coverage, &cut_list);
getline(cin, input);
if( input == "YES" || input == "Yes" || input == "yes"
|| input == "Y" || input == "y") cout << "Total cut length: " << PrettyTime(target_time[i]) << endl;
return true; cout << endl;
else
return false; }
}
//write target total information
f << score_list.size() << ",";
for(int i=0; i< total_targets; i++)
f << target_time[i] << ",";
f << endl;

//sort the list based on cut start time
sort(cut_list.begin(),cut_list.end(), [](const Cut &x, const Cut &y){ return (x.s < y.s);});


//write cutlist to tag file
f << "label,start,end,score,coverage" << endl;
for( int j=0; j<cut_list.size(); j++)
{
Cut this_cut = cut_list[j];
f << this_cut.label << "," << this_cut.s << "," << this_cut.e
<< "," << this_cut.score << "," << this_cut.coverage << endl;
}

cout << "Writing tag data to: " << tag_path << endl;
f.close();


std::string GetDirectory (const std::string& path)
{
int found = path.find_last_of("/\\");
if(found < 0)
return(".");
else
return(path.substr(0, found));
} }




void cut( ScoreList score_list, string movie_file, vector<int> target_list, string output_dir, string temp_dir, void CutMovie( ScoreList score_list, string movie_file, vector<int> target_list,
int total_targets, int min_cut, int max_gap, float threshold, float min_coverage) string output_dir, string temp_dir, int total_targets, int min_cut, int max_gap,
float threshold, float min_coverage)
{ {


//path stuff with movie file //path stuff with movie file
Expand All @@ -96,10 +192,9 @@ void cut( ScoreList score_list, string movie_file, vector<int> target_list, stri
string cut_movie = movie_base + ".cut"; string cut_movie = movie_base + ".cut";
string temp_base = temp_dir + sep + "cuts"; string temp_base = temp_dir + sep + "cuts";
string temp_path = temp_base + sep + cut_movie; string temp_path = temp_base + sep + cut_movie;
string movie_directory = GetDirectory(movie_file); string movie_directory = getDirectory(movie_file);


//will come from input //will come from input

vector<int> target_on(total_targets,0); vector<int> target_on(total_targets,0);
for(int i=0; i<target_list.size(); i++) for(int i=0; i<target_list.size(); i++)
target_on[target_list[i]] = 1; target_on[target_list[i]] = 1;
Expand All @@ -115,79 +210,22 @@ void cut( ScoreList score_list, string movie_file, vector<int> target_list, stri


//init //init
CutList cut_list; CutList cut_list;
int cut_start = -1;
int gap = 0;
int win_sum = 0;
float val_sum = 0.0;
bool did_concat = true; bool did_concat = true;




//find winners and their scores //find winners and their scores
vector<int> winners(score_list.size()); vector<int> winners(score_list.size());
vector<float> vals(score_list.size()); vector<float> vals(score_list.size());


for( int i=0; i < score_list.size(); i++ ){ for( int i=0; i < score_list.size(); i++ )
{
winners[i] = scoreArgMax(score_list[i]); winners[i] = scoreArgMax(score_list[i]);
vals[i] = scoreMax(score_list[i]); vals[i] = scoreMax(score_list[i]);
} }


//find the cuts int total = findTheCuts(score_list.size(), winners, vals, target_on,
for( int i=0; i<score_list.size(); i++) "", min_cut, max_gap, threshold, min_coverage, &cut_list);
{ cout << "Total cut length: " << PrettyTime(total) << endl;
if( cut_start >= 0 )
{
if( target_on[winners[i]] )
{
win_sum++;
val_sum += vals[i];
}

if( !target_on[winners[i]] || vals[i] < threshold || i == score_list.size()-1 )
{
if(i < score_list.size()-1) gap++;

if( gap > max_gap || i == score_list.size()-1 )
{
if( cut_start < i - gap - min_cut )
{
//output cut
int win_size = (i - gap) - cut_start + 1;
float score_avg = val_sum / (float)win_sum;
float coverage = (float)win_sum / (float)win_size;

if(coverage >= min_coverage)
{
cout << cut_start << " - " << i - gap << ": size= "
<< win_size << " coverage= " << coverage
<< " score= " << score_avg << '\n';
Cut cut;
cut.s = cut_start;
cut.e = i-gap;
cut_list.push_back(cut);
}
}
cut_start = -1;
gap = 0;
val_sum = 0.0;
win_sum = 0;
}
}
else
{
gap = 0;
}

}
else if( target_on[winners[i]] && vals[i] >= threshold )
{
cut_start = i;
gap = 0;
val_sum = 0.0;
win_sum = 0.0;
}
}


//make the cuts //make the cuts
if( cut_list.size() > 0 ) if( cut_list.size() > 0 )
{ {
Expand All @@ -205,11 +243,7 @@ void cut( ScoreList score_list, string movie_file, vector<int> target_list, stri
//use output_seek for wmv. fixed bug where cuts would freeze //use output_seek for wmv. fixed bug where cuts would freeze
bool output_seek = false; bool output_seek = false;
if(movie_type == ".wmv" || movie_type == ".WMV" || movie_type == ".Wmv") if(movie_type == ".wmv" || movie_type == ".WMV" || movie_type == ".Wmv")
{
movie_type = ".mkv";
output_seek = true; output_seek = true;
}



//output a file for each cut in the list //output a file for each cut in the list
for( int i=0; i<cut_list.size(); i++) for( int i=0; i<cut_list.size(); i++)
Expand Down

0 comments on commit 104dc40

Please sign in to comment.