Skip to content

Perceptual Hash Detector #290

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 27 commits into from
Apr 18, 2024
Merged

Conversation

wjs018
Copy link
Collaborator

@wjs018 wjs018 commented Oct 3, 2022

Hi @Breakthrough,

This is a proof of concept for a perceptual hash based detection algorithm I had started working on a while back. I updated things to be compatible with the 0.6.x updates (I think) and implemented things in OpenCV without adding additional dependencies (previously I had PIL and scipy). I also added a cli command and help strings, but have not written any actual documentation yet.

As for the actual algorithm, I re-implemented the phash algorithm from the imagehash library. For a more human readable version of the algorithm, you can see the blog post here.

Performance wise, I chose defaults that worked well on the goldeneye clip and seemed fairly performant.

There might be some formatting issues to make it match the updated codebase (typing for instance). Feel free to change things to make it fit or, point it out and I will try to take a crack at it.

Copy link
Owner

@Breakthrough Breakthrough left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is awesome! We need to add some tests before merging this. There's also documentation that needs to be updated, but that can be done after in a separate change - I can help with that part too.

Before merging this, we need to:

  • Retarget for v0.6.1 branch
  • Add unit tests

I'm curious, do you know how well this handles motion? I saw you had used motion correction for the edge detector, so was wondering if that would be applicable here or not as well. This PR also makes me rethink a lot of how to combine various detection methods, since now we have the possibility to incorporate all of HSV deltas, edges, and perceptual hashes. In v0.6.1 I may move the edge detection part back to a separate detector as per your original design, rather than combining it into ContentDetector. We could then use how confident each detector was to improve the final result.

)
@click.option(
'--freq_factor', '-f', metavar='VAL',
type=click.IntRange(min=1), default=2, show_default=True, help=
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here and elsewhere, default values must be None if they correspond to config file values. This was the only way I could find to figure out if the config value or the CLI value should be used.

Instead, you can append USER_CONFIG.get_help_string('detect-hash', 'freq-factor')) in the help text so it still shows the default.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I addressed this in efa4023 (I based this off what you did in detect-threshold, but would love you to confirm.

)
@click.option(
'--size', '-s', metavar='VAL',
type=click.IntRange(min=2), default=16, show_default=True, help=
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should re-use the constant defined in CONFIG_MAP for min in config.py so changing the value there updates all uses.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I addressed this in efa4023 (I based this off what you did in detect-threshold, but would love you to confirm.

)
@click.option(
'--freq_factor', '-f', metavar='VAL',
type=click.IntRange(min=1), default=2, show_default=True, help=
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should re-use the value from CONFIG_MAP for min here and elsewhere.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I addressed this in efa4023 (I based this off what you did in detect-threshold, but would love you to confirm.

)
@click.option(
'--freq_factor', '-f', metavar='VAL',
type=click.IntRange(min=1), default=2, show_default=True, help=
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Default values need to be None in order to work with the config file (here and elsewhere). To get the default value to show up, you can append USER_CONFIG.get_help_string('detect-hash', 'freq-factor')) to the help string. Sorry I know this is a very non-obvious thing (gotta love business logic).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I addressed this in efa4023 (I based this off what you did in detect-threshold, but would love you to confirm.

Comment on lines 412 to 420
if self.drop_short_scenes:
min_scene_len = 0
else:
if min_scene_len is None:
if self.config.is_default("detect-hash", "min-scene-len"):
min_scene_len = self.min_scene_len.frame_num
else:
min_scene_len = self.config.get_value("detect-hash", "min-scene-len")
min_scene_len = parse_timecode(min_scene_len, self.video_stream.frame_rate).frame_num
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably time to refactor this into a helper function (e.g. get_min_scene_len("detect-hash") or something) and use that here and in the other detectors.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I implemented a version of this in 688d67e as a private function of the CliContext class (_get_min_scene_len(command)). I tested it with all the detectors (and found a typo from an earlier commit of mine in the process) and it seems to work for all of them. Let me know if you think this should be done another way.

@Breakthrough Breakthrough self-assigned this Oct 7, 2022
@wjs018 wjs018 changed the base branch from master to v0.6.1 October 7, 2022 05:09
Breakthrough
Breakthrough previously approved these changes Oct 24, 2022
Copy link
Owner

@Breakthrough Breakthrough left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well done, this is amazing. Great work!

@Breakthrough
Copy link
Owner

One thing I think might need to be updated is the API docs and the scenedetect.cfg template file. I can follow up with those changes though, but just want to write it down so it's not forgotten.

@Breakthrough Breakthrough added this to the v0.6.1 milestone Nov 16, 2022
@Breakthrough Breakthrough modified the milestones: v0.6.1, v0.6.2 Nov 16, 2022
@Breakthrough Breakthrough modified the milestones: v0.6.2, v0.6.3 Feb 6, 2023
@wjs018 wjs018 changed the base branch from v0.6.1 to v0.6.2 April 4, 2023 15:04
@Breakthrough Breakthrough modified the milestones: v0.6.3, v0.7 Nov 20, 2023
@Breakthrough Breakthrough merged commit eb393ff into Breakthrough:develop Apr 18, 2024
@Breakthrough
Copy link
Owner

Finally got this into develop, thanks for your patience! There was some refactoring done to the CLI in the latest version, so it doesn't show up on the CLI yet. Will need to fix that in develop branch, but I'll make sure to do that soon.

Thanks a ton for this, amazing work!

@Breakthrough Breakthrough modified the milestones: v0.6.5, v0.6.4 Jun 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants