-
Notifications
You must be signed in to change notification settings - Fork 20
/
thumb_generator.py
216 lines (168 loc) · 6.38 KB
/
thumb_generator.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
# Import Libraries
from email.policy import default
import textwrap
from turtle import back
from sympy import true
import cv2
import time
import numpy as np
import time
#from rembg import remove
from PIL import Image, ImageFont, ImageDraw
import os, random
import argparse
import shutil
def find_smile(frame, text, count):
# Load the cascade models
face_cascade = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")
smile_cascade = cv2.CascadeClassifier("haarcascade_smile.xml")
SCALE_FACTOR=40
resizeimg = ''
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# Detect the faces
face = face_cascade.detectMultiScale(gray, scaleFactor=1.3, minNeighbors=5)
for (x, y, w, h) in face:
# Draw the rectangle around each face
img = cv2.rectangle(frame, (x-SCALE_FACTOR, y-SCALE_FACTOR), (x+w+SCALE_FACTOR, y+h+SCALE_FACTOR), (255, 255, 255), 15)
# Save image to detect smile
croped_face = img[y-SCALE_FACTOR:y+h+SCALE_FACTOR, x-SCALE_FACTOR:x+w+SCALE_FACTOR]
# print("[INFO] Face found. Saving locally.")
# Store face
# cv2.imwrite('./tmp/croped-'+str(count)+'.png', croped_face)
if not isinstance(croped_face, (list, tuple, np.ndarray)) or croped_face is None:
print('Failed to detect croped face')
break
# Display output
# cv2.imshow('croped face', croped_face)
img_gray = cv2.cvtColor(croped_face, cv2.COLOR_BGR2GRAY)
if (not isinstance(img_gray, (list, tuple, np.ndarray)) or img_gray is None):
print('Failed to detect face')
break
# Detect the smile
smile = smile_cascade.detectMultiScale(img_gray, scaleFactor=1.8, minNeighbors=20)
for x, y, w, h in smile:
print("[INFO] Smile found. Saving locally.")
# resize image
resizeimg = cv2.resize(croped_face, (400, 400), interpolation = cv2.INTER_CUBIC)
# Store smiling face
# cv2.imwrite('./tmp/smiling-'+str(int(time.time()))+'.png', resizeimg)
add_background(resizeimg, text)
def add_background(img, text):
face = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img = Image.fromarray(face)
# merging files
bg_dir = "./backgrounds/"
logo = Image.open('./assets/logo.png').convert("RGBA")
logo_width, logo_height = logo.size
img1 = Image.new('RGBA', size=(700,700), color=(0, 0, 0, 0))
img1.paste(img,(175,175))
background = Image.open(bg_dir + random.choice(os.listdir(bg_dir))).convert("RGBA")
W, H = (1280, 720)
newimg = Image.new('RGBA', size=(W, H), color=(0, 0, 0, 0))
# choose random to decide the side of image where face will be placed
x = random.uniform(0, 1)
if (x >= 0.5):
img1 = img1.rotate(25)
else:
img1 = img1.transpose(method=Image.FLIP_LEFT_RIGHT)
img1 = img1.rotate(-25)
background = background.resize((W, H), Image.ANTIALIAS)
newimg.paste(background,(0,0))
if (x >= 0.5):
newimg.paste(img1, (-120,-120), img1)
newimg.paste(logo, (W-logo_width-5,5), logo)
else:
newimg.paste(img1, (W-700+120,-120), img1)
newimg.paste(logo, (5,5), logo)
add_text(newimg, W, H, text)
def add_text(bg, W, H, text):
title_font = ImageFont.truetype('font/Arial_Black.ttf', 80)
title_text = textwrap.fill(text, width=25)
image_editable = ImageDraw.Draw(bg)
# get text size
w, h = image_editable.textsize(title_text, font=title_font)
# write text in the middle
image_editable.text(((W-w)/2,(H-h)-75), title_text, (255, 255, 255), font=title_font, stroke_width=10,stroke_fill=(0,0,0))
save_thumbnail(bg)
def save_thumbnail(img):
img.save('./thumbs/thumb-'+str(int(time.time()))+'.png',"PNG")
def remove_background(img):
rembg = remove(img)
return (rembg)
def draw_border(img):
img2 = img.copy()
resizegray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(resizegray, 0, 255, 0)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
cv2.drawContours(img, contours, -1, (255,255,255), 8)
return (img)
def create_thumbnail(img_path, text, clear_thumbs:bool=True):
if clear_thumbs == True: remove_thumbs()
video = cv2.VideoCapture(img_path)
check = True
count = 0
while check:
# check if there are enough thumbs then exit
if (len(os.listdir('./thumbs')) > 10): break
# Read the frame
check, frame = video.read()
if not check:
#print("Stream end? Exiting...")
break
if not isinstance(frame, (list, tuple, np.ndarray)):
#print("Frame not identified? Exiting...")
break
# 30 fps video, then checking for smile each n frames
if (count >= 5): count = 0
if (count == 0):
face = find_smile(frame,text, count)
count += 1
# Display output
#cv2.imshow('smile detect', frame)
# Stop if escape key is pressed
key = cv2.waitKey(30) & 0xff
if key == 27:
break
# Release the VideoCapture object
video.release()
cv2.destroyAllWindows()
return
def remove_thumbs():
# remove previous thumbs
dir = './thumbs'
for f in os.listdir(dir):
os.remove(os.path.join(dir, f))
def copy_thumbs(title):
dir = './thumbs'
newdir = title.replace(' ','_')
shutil.copytree(dir, 'output/'+newdir, dirs_exist_ok=True)
def main(input: str, title: str, delete_thumbs: bool=True):
create_thumbnail(input, title, delete_thumbs)
copy_thumbs(title)
def str2bool(value):
return value.lower() == 'true'
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Find a smiling face on image or video and generate a random thumbnail')
parser.add_argument(
"-i",
"--input",
help="Video input file.",
type=str,
required=True,
)
parser.add_argument(
"-t",
"--title",
help="Video title description",
type=str,
required=True,
)
parser.add_argument(
"-d",
"--no_delete_thumbs",
type=str2bool,
default = True,
help="Delete previous Thumbs",
)
args = parser.parse_args()
main(args.input, args.title, args.no_delete_thumbs)