Skip to content

Instantly share code, notes, and snippets.

@Jeffrey-P-McAteer
Created June 28, 2020 00:28
Show Gist options
  • Select an option

  • Save Jeffrey-P-McAteer/c0b25c2ebfed8248b79a5d18d5997a5e to your computer and use it in GitHub Desktop.

Select an option

Save Jeffrey-P-McAteer/c0b25c2ebfed8248b79a5d18d5997a5e to your computer and use it in GitHub Desktop.
# I have a script which runs in the background.
# Every 5 minutes it checks to see if a picture was taken
# for YYYY_MM_DD_HH.jpg. If it does not exist,
# the script takes a photo and checks if faces exist.
# if so it gets saved to YYYY_MM_DD_HH.jpg.
# This is a brief 20-minute excursion into the use of
# perceptual hashes to join 4 months of pictures into
# a video.
# One run is saved at https://youtu.be/9ExS8LDD9BQ
import cv2
import os, sys
from PIL import Image
import random
# python -m pip install --user ImageHash
import imagehash
# Download from https://raw.githubusercontent.com/opencv/opencv/master/data/haarcascades/haarcascade_frontalface_default.xml
FACE_CASCADE_F = '/j/.cache/haarcascade_frontalface_default.xml'
image_folder = '/j/res/profiles/dailies/'
video_name = '/tmp/video.avi'
images = [img for img in os.listdir(image_folder) if img.endswith(".jpg")]
frame = cv2.imread(os.path.join(image_folder, images[0]))
vid_height, vid_width, layers = frame.shape
print("vid_height={}, vid_width={}".format(vid_height, vid_width))
framerate = 8
video = cv2.VideoWriter(video_name, 0, framerate, (vid_width, vid_height))
frames = [
cv2.imread(os.path.join(image_folder, image)) for image in images
]
# Throw out non-face images
face_cascade = cv2.CascadeClassifier(FACE_CASCADE_F)
def has_face(f):
global face_cascade
gray = cv2.cvtColor(f, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.1, 5)
if len(faces) < 1:
return False
return True
face_frames = [f for f in frames if has_face(f)]
print("Threw out {} non-face frames...".format(len(frames) - len(face_frames)))
frames = face_frames
for i in range(0, len(frames)):
height, width, layers = frames[i].shape
if height != vid_height or width != vid_width:
frames[i] = cv2.resize(frames[i], (vid_width, vid_height))
print("Read in frames!")
# First sort frames so similar images are next to eachother
# frames = sorted(frames, key=lambda one_frame: hash(imagehash.phash(
# Image.fromarray( cv2.cvtColor(one_frame, cv2.COLOR_BGR2GRAY) )
# )))
frame_phashes = [
imagehash.phash( Image.fromarray( img ) )
for img in frames
]
all_frames_len = len(frames);
some_idx = random.randint(0, len(frames)-1)
print("Started with index {}".format(some_idx))
similar_frames = [ frames[some_idx] ]
added_frame_i = [ some_idx ]
# Skip last 35% of frames b/c they get erratic
max_similar_frames = all_frames_len - int(0.35 * all_frames_len)
while len(similar_frames) < max_similar_frames:
# Find the most similar frame to similar_frames[-1]...
if len(similar_frames) % 10 == 0:
print("{}/{} sorted...".format(len(similar_frames), max_similar_frames))
best_frames_i = 0
while best_frames_i in added_frame_i:
best_frames_i += 1
for i in range(0, len(frames)):
if i in added_frame_i:
continue
# Compute best diff
diff_best = frame_phashes[added_frame_i[-1]] - frame_phashes[best_frames_i]
# Compute this diff
diff_n = frame_phashes[added_frame_i[-1]] - frame_phashes[i]
if diff_n < diff_best:
best_frames_i = i
# Add best
similar_frames.append( frames[best_frames_i] )
added_frame_i.append( best_frames_i )
# Now replace frames with similar_frames
frames = similar_frames
print("Sorted!")
# Now join them all
for frame in frames:
video.write(frame)
cv2.destroyAllWindows()
video.release()
print("Wrote video! ({})".format(video_name))
os.system("mpv '{}'".format(video_name))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment