fixed merge conflict
This commit is contained in:
parent
e35245cd8c
commit
43d36335a6
12 changed files with 12124 additions and 12135 deletions
24
.gitignore
vendored
24
.gitignore
vendored
|
@ -1,13 +1,13 @@
|
||||||
.direnv/*
|
.direnv/*
|
||||||
venv/*
|
venv/*
|
||||||
output/*
|
output/*
|
||||||
.envrc
|
.envrc
|
||||||
training_data/data*
|
training_data/data*
|
||||||
training_data/info*
|
training_data/info*
|
||||||
training_data/training_data_*/
|
training_data/training_data_*/
|
||||||
training_data/*.vec
|
training_data/*.vec
|
||||||
training_data/backgrounds.txt
|
training_data/backgrounds.txt
|
||||||
training_data/negatives
|
training_data/negatives
|
||||||
training_data/opencv
|
training_data/opencv
|
||||||
validation/cascade*
|
validation/cascade*
|
||||||
validation/*.xlsx
|
validation/*.xlsx
|
306
Main.py
306
Main.py
|
@ -1,153 +1,153 @@
|
||||||
import cv2
|
import cv2
|
||||||
import argparse
|
import argparse
|
||||||
import time
|
import time
|
||||||
import os
|
import os
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
def dir_path(string):
|
def dir_path(string):
|
||||||
if os.path.exists(string):
|
if os.path.exists(string):
|
||||||
return string
|
return string
|
||||||
else:
|
else:
|
||||||
raise NotADirectoryError(string)
|
raise NotADirectoryError(string)
|
||||||
|
|
||||||
def init_argparse() -> argparse.ArgumentParser:
|
def init_argparse() -> argparse.ArgumentParser:
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
prog="FaceDetection",
|
prog="FaceDetection",
|
||||||
usage="%(prog)s [OPTION]",
|
usage="%(prog)s [OPTION]",
|
||||||
description="Run face localization"
|
description="Run face localization"
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-v", "--version", action="version", version=f"{parser.prog} version 1.0.1"
|
"-v", "--version", action="version", version=f"{parser.prog} version 1.0.1"
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-d", "--dashboard", action='store_true', help="Flag to enable live dashboard with statistics - requires terminal width of 90 columns or greater"
|
"-d", "--dashboard", action='store_true', help="Flag to enable live dashboard with statistics - requires terminal width of 90 columns or greater"
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-o", "--output", action='store_true', help="show the resultant directions"
|
"-o", "--output", action='store_true', help="show the resultant directions"
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-f", "--file", type=dir_path, nargs="?", help="File to scan instead of using the camera. Useful for generating training data"
|
"-f", "--file", type=dir_path, nargs="?", help="File to scan instead of using the camera. Useful for generating training data"
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-s", "--no-screen", action='store_true', help="Do not show the successful frames"
|
"-s", "--no-screen", action='store_true', help="Do not show the successful frames"
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-t", "--training-data", action='store_true', help="When set, saves successful face-location images and coordinates to use for future training data"
|
"-t", "--training-data", action='store_true', help="When set, saves successful face-location images and coordinates to use for future training data"
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--validate', action="store_true", help="if set, outputs frame_count and box coords for located faces for future validation"
|
'--validate', action="store_true", help="if set, outputs frame_count and box coords for located faces for future validation"
|
||||||
)
|
)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
multiplication_factor = 0.05
|
multiplication_factor = 0.05
|
||||||
|
|
||||||
def get_adjustment_amount(imgSize, currentX, currentY, currentW, currentH):
|
def get_adjustment_amount(imgSize, currentX, currentY, currentW, currentH):
|
||||||
|
|
||||||
current_top_left = [currentX, currentY]
|
current_top_left = [currentX, currentY]
|
||||||
current_bottom_right = [currentX + currentW, currentY + currentH]
|
current_bottom_right = [currentX + currentW, currentY + currentH]
|
||||||
|
|
||||||
current_top_right = [currentX + currentW, currentY]
|
current_top_right = [currentX + currentW, currentY]
|
||||||
|
|
||||||
# find the difference between the left gap and the right gap, divide it by two, and multiply it by the speed scale
|
# find the difference between the left gap and the right gap, divide it by two, and multiply it by the speed scale
|
||||||
horizontal_adjustment = multiplication_factor * (currentX - (imgSize[0] - current_top_right[0])) / 2
|
horizontal_adjustment = multiplication_factor * (currentX - (imgSize[0] - current_top_right[0])) / 2
|
||||||
vertical_adjustment = multiplication_factor * (currentY - (imgSize[0] - current_bottom_right[1])) / 2
|
vertical_adjustment = multiplication_factor * (currentY - (imgSize[0] - current_bottom_right[1])) / 2
|
||||||
|
|
||||||
return [horizontal_adjustment, vertical_adjustment]
|
return [horizontal_adjustment, vertical_adjustment]
|
||||||
|
|
||||||
frames_searched = 1
|
frames_searched = 1
|
||||||
faces_found = 0
|
faces_found = 0
|
||||||
start_time = datetime.datetime.now()
|
start_time = datetime.datetime.now()
|
||||||
|
|
||||||
def draw_dashboard(keep_stat_line = False):
|
def draw_dashboard(keep_stat_line = False):
|
||||||
global frames_searched, faces_found, start_time
|
global frames_searched, faces_found, start_time
|
||||||
|
|
||||||
elapsed_time = datetime.datetime.now() - start_time
|
elapsed_time = datetime.datetime.now() - start_time
|
||||||
|
|
||||||
hours, remainder = divmod(elapsed_time.total_seconds(), 3600)
|
hours, remainder = divmod(elapsed_time.total_seconds(), 3600)
|
||||||
minutes, seconds = divmod(remainder, 60)
|
minutes, seconds = divmod(remainder, 60)
|
||||||
|
|
||||||
f_found = f"{faces_found} Faces found".ljust(16, ' ')
|
f_found = f"{faces_found} Faces found".ljust(16, ' ')
|
||||||
f_searched = f"{frames_searched} Frames searched".ljust(21, ' ')
|
f_searched = f"{frames_searched} Frames searched".ljust(21, ' ')
|
||||||
success_rate = f"{round((faces_found / frames_searched) * 100, 1)}% Success rate".ljust(16, ' ')
|
success_rate = f"{round((faces_found / frames_searched) * 100, 1)}% Success rate".ljust(16, ' ')
|
||||||
|
|
||||||
if keep_stat_line:
|
if keep_stat_line:
|
||||||
print(f"{f_found} | {f_searched} | {success_rate} | {round(hours)}h {round(minutes)}m {round(seconds)}s elapsed", flush=True)
|
print(f"{f_found} | {f_searched} | {success_rate} | {round(hours)}h {round(minutes)}m {round(seconds)}s elapsed", flush=True)
|
||||||
else:
|
else:
|
||||||
print(f"{f_found} | {f_searched} | {success_rate} | {round(hours)}h {round(minutes)}m {round(seconds)}s elapsed", end="\r", flush=True)
|
print(f"{f_found} | {f_searched} | {success_rate} | {round(hours)}h {round(minutes)}m {round(seconds)}s elapsed", end="\r", flush=True)
|
||||||
|
|
||||||
|
|
||||||
parser = init_argparse()
|
parser = init_argparse()
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
if args.file:
|
if args.file:
|
||||||
cap = cv2.VideoCapture(args.file)
|
cap = cv2.VideoCapture(args.file)
|
||||||
else:
|
else:
|
||||||
cap = cv2.VideoCapture(0, cv2.IMREAD_GRAYSCALE) # instead of grayscale you can also use -1, 0, or 1.
|
cap = cv2.VideoCapture(0, cv2.IMREAD_GRAYSCALE) # instead of grayscale you can also use -1, 0, or 1.
|
||||||
faceCascade = cv2.CascadeClassifier(r"./cascades/cascade_5.xml") # CHECK THIS FIRST TROUBLE SHOOTING
|
faceCascade = cv2.CascadeClassifier(r"./cascades/cascade_10.xml") # CHECK THIS FIRST TROUBLE SHOOTING
|
||||||
|
|
||||||
datestamp = "{:%Y_%m_%d %H_%M_%S}".format(datetime.datetime.now())
|
datestamp = "{:%Y_%m_%d %H_%M_%S}".format(datetime.datetime.now())
|
||||||
output_dir = r"./output/" + datestamp + r"/"
|
output_dir = r"./output/" + datestamp + r"/"
|
||||||
|
|
||||||
|
|
||||||
if args.training_data:
|
if args.training_data:
|
||||||
if not os.path.exists(output_dir):
|
if not os.path.exists(output_dir):
|
||||||
os.makedirs(output_dir)
|
os.makedirs(output_dir)
|
||||||
with open(output_dir + r"found_faces.csv", 'a') as fd:
|
with open(output_dir + r"found_faces.csv", 'a') as fd:
|
||||||
fd.write(f"frame_name, x, y, width, height\n")
|
fd.write(f"frame_name, x, y, width, height\n")
|
||||||
|
|
||||||
tmp, frm = cap.read()
|
tmp, frm = cap.read()
|
||||||
height, width, channels = frm.shape
|
height, width, channels = frm.shape
|
||||||
if (args.file):
|
if (args.file):
|
||||||
print(f"Image is {height} tall and {width} wide")
|
print(f"Image is {height} tall and {width} wide")
|
||||||
frame_count = 0
|
frame_count = 0
|
||||||
start_timestamp = time.strftime("%Y%m%d-%H%M%S")
|
start_timestamp = time.strftime("%Y%m%d-%H%M%S")
|
||||||
# print(f"{height*.25}, {width}")
|
# print(f"{height*.25}, {width}")
|
||||||
del tmp, frm
|
del tmp, frm
|
||||||
#Color is 1, grayscale is 0, and the unchanged is -1
|
#Color is 1, grayscale is 0, and the unchanged is -1
|
||||||
while(True):
|
while(True):
|
||||||
ret, frame = cap.read()
|
ret, frame = cap.read()
|
||||||
frames_searched += 1
|
frames_searched += 1
|
||||||
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
|
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
|
||||||
|
|
||||||
# Detect faces in the image
|
# Detect faces in the image
|
||||||
faces = faceCascade.detectMultiScale(
|
faces = faceCascade.detectMultiScale(
|
||||||
gray,
|
gray,
|
||||||
scaleFactor=1.2,
|
scaleFactor=1.2,
|
||||||
minNeighbors=2,
|
minNeighbors=2,
|
||||||
# minSize=(70, 90)
|
# minSize=(70, 90)
|
||||||
minSize=(200, 200)
|
minSize=(200, 200)
|
||||||
)
|
)
|
||||||
|
|
||||||
# Draw a rectangle around the faces
|
# Draw a rectangle around the faces
|
||||||
for (x, y, w, h) in faces:
|
for (x, y, w, h) in faces:
|
||||||
if args.training_data:
|
if args.training_data:
|
||||||
frame_name = frames_searched
|
frame_name = frames_searched
|
||||||
with open(output_dir + r"found_faces.csv", 'a') as fd:
|
with open(output_dir + r"found_faces.csv", 'a') as fd:
|
||||||
fd.write(f"frame_{frame_name}.jpg, {x}, {y}, {w}, {h}\n")
|
fd.write(f"frame_{frame_name}.jpg, {x}, {y}, {w}, {h}\n")
|
||||||
cv2.imwrite(output_dir + f"frame_{frame_name}.jpg", frame)
|
cv2.imwrite(output_dir + f"frame_{frame_name}.jpg", frame)
|
||||||
|
|
||||||
if args.validate:
|
if args.validate:
|
||||||
with open(f"./validation/{start_timestamp}-validation.txt", 'a') as output_validation_file:
|
with open(f"./validation/{start_timestamp}-validation.txt", 'a') as output_validation_file:
|
||||||
output_validation_file.write(f"{frame_count}, {x}, {y}, {x+w}, {y+h}\n")
|
output_validation_file.write(f"{frame_count}, {x}, {y}, {x+w}, {y+h}\n")
|
||||||
|
|
||||||
faces_found += 1
|
faces_found += 1
|
||||||
adjustment_required = get_adjustment_amount([width, height], x, y, w, h)
|
adjustment_required = get_adjustment_amount([width, height], x, y, w, h)
|
||||||
cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 255, 255))
|
cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 255, 255))
|
||||||
|
|
||||||
if args.output:
|
if args.output:
|
||||||
print(f"Adjust right: {adjustment_required[0]}".ljust(90, ' '), flush=True)
|
print(f"Adjust right: {adjustment_required[0]}".ljust(90, ' '), flush=True)
|
||||||
print(f"Adjust up : {adjustment_required[1]}", flush=True)
|
print(f"Adjust up : {adjustment_required[1]}", flush=True)
|
||||||
|
|
||||||
if not args.no_screen:
|
if not args.no_screen:
|
||||||
cv2.imshow('frame', frame)
|
cv2.imshow('frame', frame)
|
||||||
|
|
||||||
if args.dashboard:
|
if args.dashboard:
|
||||||
draw_dashboard()
|
draw_dashboard()
|
||||||
|
|
||||||
if cv2.waitKey(1) & 0xFF == ord('q'):
|
if cv2.waitKey(1) & 0xFF == ord('q'):
|
||||||
break
|
break
|
||||||
|
|
||||||
frame_count += 1
|
frame_count += 1
|
||||||
|
|
||||||
draw_dashboard(keep_stat_line=True)
|
draw_dashboard(keep_stat_line=True)
|
||||||
cap.release()
|
cap.release()
|
||||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,25 +0,0 @@
|
||||||
NixOS/Nix:
|
|
||||||
If you run on a Nix or NixOS environment, you can use the included shell.nix file to create a nix shell to run this in.
|
|
||||||
|
|
||||||
Windows/Other Linux:
|
|
||||||
This program was developed with python 3.11, so please use that version of python to create the virtual environment. After making sure you are using the correct python version, run the following commands:
|
|
||||||
|
|
||||||
python -m venv venv
|
|
||||||
|
|
||||||
to create a new virtual environment ".\venv"
|
|
||||||
|
|
||||||
now enter the the virtual environment by running either .\venv\Scripts\Activate.ps1 or ./venv/Scripts/activate depending on if you use windows and install the following packages (found in requirements.txt)
|
|
||||||
|
|
||||||
pip install numpy
|
|
||||||
pip install opencv-python
|
|
||||||
|
|
||||||
Now you can run the program. It is recommended to run the program with -d and -o set while testing. This enables the dashboard which shows live statistics, and output, which shows the calculated adjustments required to center the face in the frame.
|
|
||||||
|
|
||||||
|
|
||||||
Training Data:
|
|
||||||
https://www.kaggle.com/datasets/utkarshsaxenadn/landscape-recognition-image-dataset-12k-images
|
|
||||||
|
|
||||||
|
|
||||||
create positives from the negatives: \opencv\build\x64\vc15\bin\opencv_createsamples.exe -img .\positives\face_1.png -bg .\bg.txt -info info/info.lst -pngoutput info -maxxangle 0.8 -maxyangle 0.8 -maxzangle 0.8 -num 1950
|
|
||||||
Create vec files from positives: .\opencv\build\x64\vc15\bin\opencv_createsamples.exe -info .\info\info.lst -num 1950 -w 80 -h 80 -vec positives-80.vec
|
|
||||||
(I created a 20, 40, and 80) we have 1650 positives
|
|
|
@ -1,2 +1,2 @@
|
||||||
numpy
|
numpy
|
||||||
opencv-python
|
opencv-python
|
|
@ -1,120 +1,120 @@
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
backgrounds_file_path = "backgrounds.txt"
|
backgrounds_file_path = "backgrounds.txt"
|
||||||
info_base_path = r"./info"
|
info_base_path = r"./info"
|
||||||
negatives_path = r"./negatives"
|
negatives_path = r"./negatives"
|
||||||
positives_path = r"./positives"
|
positives_path = r"./positives"
|
||||||
training_data_base = r"./training_data_"
|
training_data_base = r"./training_data_"
|
||||||
|
|
||||||
opencv_path = r".\opencv\build\x64\vc15\bin\opencv_createsamples.exe"
|
opencv_path = r".\opencv\build\x64\vc15\bin\opencv_createsamples.exe"
|
||||||
|
|
||||||
set_sizes = [1, 2, 5, 10]
|
set_sizes = [1, 2, 5, 10]
|
||||||
|
|
||||||
max_xangle = 0.5
|
max_xangle = 0.5
|
||||||
max_yangle = 0.5
|
max_yangle = 0.5
|
||||||
max_zangle = 0.5
|
max_zangle = 0.5
|
||||||
|
|
||||||
w, h = 25, 18
|
w, h = 25, 18
|
||||||
|
|
||||||
class InfoEntry:
|
class InfoEntry:
|
||||||
info_lst_line: str
|
info_lst_line: str
|
||||||
image_path: str
|
image_path: str
|
||||||
|
|
||||||
def __init__(self, info_line, file_path):
|
def __init__(self, info_line, file_path):
|
||||||
self.info_lst_line = info_line
|
self.info_lst_line = info_line
|
||||||
self.image_path = file_path
|
self.image_path = file_path
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"Image Entry: {self.info_lst_line}, {self.image_path}"
|
return f"Image Entry: {self.info_lst_line}, {self.image_path}"
|
||||||
|
|
||||||
|
|
||||||
max_x = 750
|
max_x = 750
|
||||||
max_y = 800
|
max_y = 800
|
||||||
|
|
||||||
# remove too small images
|
# remove too small images
|
||||||
for image in os.listdir("./negatives"):
|
for image in os.listdir("./negatives"):
|
||||||
im = Image.open(f"./negatives/{image}")
|
im = Image.open(f"./negatives/{image}")
|
||||||
width, height = im.size
|
width, height = im.size
|
||||||
del im
|
del im
|
||||||
if width <= max_x:
|
if width <= max_x:
|
||||||
os.remove(f"./negatives/{image}")
|
os.remove(f"./negatives/{image}")
|
||||||
elif height <= max_y:
|
elif height <= max_y:
|
||||||
os.remove(f"./negatives/{image}")
|
os.remove(f"./negatives/{image}")
|
||||||
|
|
||||||
# remove any existing file and assume old data
|
# remove any existing file and assume old data
|
||||||
if os.path.exists(backgrounds_file_path):
|
if os.path.exists(backgrounds_file_path):
|
||||||
os.remove(backgrounds_file_path)
|
os.remove(backgrounds_file_path)
|
||||||
|
|
||||||
# regenerate the available negatives list
|
# regenerate the available negatives list
|
||||||
count_negatives = len(os.listdir(negatives_path))
|
count_negatives = len(os.listdir(negatives_path))
|
||||||
for img in os.listdir(negatives_path):
|
for img in os.listdir(negatives_path):
|
||||||
line = f"{negatives_path}/" + img + "\n"
|
line = f"{negatives_path}/" + img + "\n"
|
||||||
with open(backgrounds_file_path, 'a') as f:
|
with open(backgrounds_file_path, 'a') as f:
|
||||||
f.write(line)
|
f.write(line)
|
||||||
|
|
||||||
info_dirs = []
|
info_dirs = []
|
||||||
|
|
||||||
if len(os.listdir(positives_path)) > max(set_sizes):
|
if len(os.listdir(positives_path)) > max(set_sizes):
|
||||||
print("Your set sizes were larger than the available positive images!")
|
print("Your set sizes were larger than the available positive images!")
|
||||||
quit(2)
|
quit(2)
|
||||||
|
|
||||||
for img in os.listdir(positives_path):
|
for img in os.listdir(positives_path):
|
||||||
i = len(info_dirs)
|
i = len(info_dirs)
|
||||||
info_dir = f"{info_base_path}{i}"
|
info_dir = f"{info_base_path}{i}"
|
||||||
|
|
||||||
com = f"{opencv_path} -img positives/" + str(i) + ".png -bg backgrounds.txt -info " + info_dir + "/info.lst" + \
|
com = f"{opencv_path} -img positives/" + str(i) + ".png -bg backgrounds.txt -info " + info_dir + "/info.lst" + \
|
||||||
" -pngoutput " + info_dir + " -maxxangle " + str(max_xangle) + " -maxyangle " + str(max_yangle) + " -maxzangle " + str(max_zangle) + \
|
" -pngoutput " + info_dir + " -maxxangle " + str(max_xangle) + " -maxyangle " + str(max_yangle) + " -maxzangle " + str(max_zangle) + \
|
||||||
" -num " + str(count_negatives)
|
" -num " + str(count_negatives)
|
||||||
|
|
||||||
if not os.path.exists(info_dir):
|
if not os.path.exists(info_dir):
|
||||||
subprocess.call(com, shell=True)
|
subprocess.call(com, shell=True)
|
||||||
|
|
||||||
info_dirs.append(info_dir)
|
info_dirs.append(info_dir)
|
||||||
|
|
||||||
for i in set_sizes:
|
for i in set_sizes:
|
||||||
if not os.path.exists(training_data_base + str(i)):
|
if not os.path.exists(training_data_base + str(i)):
|
||||||
os.makedirs(training_data_base + str(i))
|
os.makedirs(training_data_base + str(i))
|
||||||
|
|
||||||
def join_info_folders(info_dirs: list, output_dir: str):
|
def join_info_folders(info_dirs: list, output_dir: str):
|
||||||
info_dir: str
|
info_dir: str
|
||||||
cur_entry_name = 0
|
cur_entry_name = 0
|
||||||
for info_dir in info_dirs:
|
for info_dir in info_dirs:
|
||||||
info_lines = []
|
info_lines = []
|
||||||
with open(info_dir + "/info.lst", 'r') as info_file:
|
with open(info_dir + "/info.lst", 'r') as info_file:
|
||||||
for line in info_file.readlines():
|
for line in info_file.readlines():
|
||||||
image_path = f"{info_dir}/{line.split(' ')[0]}"
|
image_path = f"{info_dir}/{line.split(' ')[0]}"
|
||||||
info_lines.append(InfoEntry(line.strip(), image_path))
|
info_lines.append(InfoEntry(line.strip(), image_path))
|
||||||
|
|
||||||
item: InfoEntry
|
item: InfoEntry
|
||||||
for item in info_lines:
|
for item in info_lines:
|
||||||
shutil.copy(item.image_path, f"{output_dir}/{str(cur_entry_name)}.jpg")
|
shutil.copy(item.image_path, f"{output_dir}/{str(cur_entry_name)}.jpg")
|
||||||
with open(f"{output_dir}/info.lst", 'a') as info_file:
|
with open(f"{output_dir}/info.lst", 'a') as info_file:
|
||||||
to_write = []
|
to_write = []
|
||||||
to_write.append(str(cur_entry_name) + ".jpg")
|
to_write.append(str(cur_entry_name) + ".jpg")
|
||||||
to_write = to_write + item.info_lst_line.split(" ")[1:]
|
to_write = to_write + item.info_lst_line.split(" ")[1:]
|
||||||
to_write.append("\n")
|
to_write.append("\n")
|
||||||
info_file.write(" ".join(to_write))
|
info_file.write(" ".join(to_write))
|
||||||
cur_entry_name += 1
|
cur_entry_name += 1
|
||||||
|
|
||||||
for i in set_sizes:
|
for i in set_sizes:
|
||||||
join_info_folders(info_dirs[:i], training_data_base + str(i))
|
join_info_folders(info_dirs[:i], training_data_base + str(i))
|
||||||
|
|
||||||
commands = []
|
commands = []
|
||||||
|
|
||||||
for i in set_sizes:
|
for i in set_sizes:
|
||||||
num_positives = len(os.listdir(training_data_base + str(i)))
|
num_positives = len(os.listdir(training_data_base + str(i)))
|
||||||
if os.path.exists(training_data_base + str(i) + ".vec"):
|
if os.path.exists(training_data_base + str(i) + ".vec"):
|
||||||
os.remove(training_data_base + str(i) + ".vec")
|
os.remove(training_data_base + str(i) + ".vec")
|
||||||
com = f"{opencv_path} -info {training_data_base + str(i)}\info.lst -num {num_positives} -w {w} -h {h} -vec {training_data_base + str(i)}.vec"
|
com = f"{opencv_path} -info {training_data_base + str(i)}\info.lst -num {num_positives} -w {w} -h {h} -vec {training_data_base + str(i)}.vec"
|
||||||
subprocess.call(com, shell=True)
|
subprocess.call(com, shell=True)
|
||||||
commands.append(f".\opencv\\build\\x64\\vc15\\bin\opencv_traincascade.exe -data data_{str(i)} -vec .\\{training_data_base + str(i)}.vec -bg .\\{backgrounds_file_path} -numPos {num_positives} -numNeg {num_positives / 2} -numStages 15 -w {w} -h {h}")
|
commands.append(f".\opencv\\build\\x64\\vc15\\bin\opencv_traincascade.exe -data data_{str(i)} -vec .\\{training_data_base + str(i)}.vec -bg .\\{backgrounds_file_path} -numPos {num_positives} -numNeg {num_positives / 2} -numStages 15 -w {w} -h {h}")
|
||||||
|
|
||||||
if not os.path.exists(".\data_" + str(i)):
|
if not os.path.exists(".\data_" + str(i)):
|
||||||
os.makedirs(".\data_" + str(i))
|
os.makedirs(".\data_" + str(i))
|
||||||
|
|
||||||
for i in commands:
|
for i in commands:
|
||||||
print(f"You are ready to train the models with: \n {i}")
|
print(f"You are ready to train the models with: \n {i}")
|
||||||
|
|
||||||
|
|
|
@ -1,97 +1,111 @@
|
||||||
import argparse
|
import argparse
|
||||||
import os
|
import os
|
||||||
|
|
||||||
def dir_path(string):
|
def dir_path(string):
|
||||||
if os.path.exists(string):
|
if os.path.exists(string):
|
||||||
return string
|
return string
|
||||||
else:
|
else:
|
||||||
raise NotADirectoryError(string)
|
raise NotADirectoryError(string)
|
||||||
|
|
||||||
def init_argparse() -> argparse.ArgumentParser:
|
def init_argparse() -> argparse.ArgumentParser:
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
prog="FaceDetection",
|
prog="FaceDetection",
|
||||||
usage="%(prog)s [OPTION]",
|
usage="%(prog)s [OPTION]",
|
||||||
description="Run face localization"
|
description="Run face localization"
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"ground_truth", type=dir_path, help="ground truth file"
|
"ground_truth", type=dir_path, help="ground truth file"
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"test_file", type=dir_path, help="file to compare to the ground truth"
|
"test_file", type=dir_path, help="file to compare to the ground truth"
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"out_file", help="the file to write the output to"
|
"out_file", help="the file to write the output to"
|
||||||
)
|
)
|
||||||
return parser
|
parser.add_argument(
|
||||||
|
"-f", "--faces_count_file", help="the file output the number of faces found in each frame"
|
||||||
multiplication_factor = 0.05
|
)
|
||||||
def get_adjustment_amount(imgSize, x1, y1, x2, y2):
|
return parser
|
||||||
|
|
||||||
# find the difference between the left gap and the right gap, divide it by two, and multiply it by the speed scale
|
multiplication_factor = 0.05
|
||||||
horizontal_adjustment = multiplication_factor * (x1 - (imgSize[0] - x2)) / 2
|
def get_adjustment_amount(imgSize, x1, y1, x2, y2):
|
||||||
vertical_adjustment = multiplication_factor * (y1 - (imgSize[0] - y2)) / 2
|
|
||||||
|
# find the difference between the left gap and the right gap, divide it by two, and multiply it by the speed scale
|
||||||
return [horizontal_adjustment, vertical_adjustment]
|
horizontal_adjustment = multiplication_factor * (x1 - (imgSize[0] - x2)) / 2
|
||||||
|
vertical_adjustment = multiplication_factor * (y1 - (imgSize[0] - y2)) / 2
|
||||||
parser = init_argparse()
|
|
||||||
args = parser.parse_args()
|
return [horizontal_adjustment, vertical_adjustment]
|
||||||
|
|
||||||
class FrameBox:
|
parser = init_argparse()
|
||||||
frame_number: int
|
args = parser.parse_args()
|
||||||
top_left: tuple
|
|
||||||
bottom_right: tuple
|
class FrameBox:
|
||||||
|
frame_number: int
|
||||||
def __init__(self, frame_number, x1, y1, x2, y2):
|
top_left: tuple
|
||||||
self.frame_number = frame_number
|
bottom_right: tuple
|
||||||
self.top_left = (x1, y1)
|
|
||||||
self.bottom_right = (x2, y2)
|
def __init__(self, frame_number, x1, y1, x2, y2):
|
||||||
|
self.frame_number = frame_number
|
||||||
ground_truth = []
|
self.top_left = (x1, y1)
|
||||||
with open(args.ground_truth, 'r') as gt_file:
|
self.bottom_right = (x2, y2)
|
||||||
lines = gt_file.readlines()
|
|
||||||
for line in lines:
|
ground_truth = []
|
||||||
items = line.split(",")
|
with open(args.ground_truth, 'r') as gt_file:
|
||||||
ground_truth.append(FrameBox(int(items[0].strip()), int(items[1].strip()), int(items[2].strip()), int(items[3].strip()), int(items[4].strip())))
|
lines = gt_file.readlines()
|
||||||
|
for line in lines:
|
||||||
test_results = []
|
items = line.split(",")
|
||||||
with open(args.test_file, 'r') as test_file:
|
ground_truth.append(FrameBox(int(items[0].strip()), int(items[1].strip()), int(items[2].strip()), int(items[3].strip()), int(items[4].strip())))
|
||||||
lines = test_file.readlines()
|
|
||||||
for line in lines:
|
test_results = []
|
||||||
items = line.split(",")
|
with open(args.test_file, 'r') as test_file:
|
||||||
test_results.append(FrameBox(int(items[0].strip()), int(items[1].strip()), int(items[2].strip()), int(items[3].strip()), int(items[4].strip())))
|
lines = test_file.readlines()
|
||||||
|
for line in lines:
|
||||||
test_fb: FrameBox
|
items = line.split(",")
|
||||||
gt_frame: FrameBox
|
test_results.append(FrameBox(int(items[0].strip()), int(items[1].strip()), int(items[2].strip()), int(items[3].strip()), int(items[4].strip())))
|
||||||
last_frame_num = 0
|
|
||||||
average_sum = 0
|
test_fb: FrameBox
|
||||||
average_count = 0
|
gt_frame: FrameBox
|
||||||
print("length of test file: " + str(len(test_results)))
|
last_frame_num = 0
|
||||||
for test_fb in test_results:
|
average_sum = 0
|
||||||
# make
|
average_count = 0
|
||||||
def bring_up_gt():
|
print("length of test file: " + str(len(test_results)))
|
||||||
if test_fb.frame_number > ground_truth[0].frame_number:
|
for test_fb in test_results:
|
||||||
ground_truth.pop(0)
|
# make
|
||||||
bring_up_gt()
|
def bring_up_gt():
|
||||||
|
if test_fb.frame_number > ground_truth[0].frame_number:
|
||||||
bring_up_gt()
|
ground_truth.pop(0)
|
||||||
|
|
||||||
assert(ground_truth[0].frame_number == test_fb.frame_number)
|
if test_fb.frame_number > ground_truth[0].frame_number:
|
||||||
gt_frame = ground_truth[0]
|
# we need to include the empty frames too
|
||||||
|
if args.faces_count_file:
|
||||||
gt_adjustment = get_adjustment_amount((1920, 1000), gt_frame.top_left[0], gt_frame.top_left[1], gt_frame.bottom_right[0], gt_frame.bottom_right[1])
|
with open(args.faces_count_file, 'a') as out_file:
|
||||||
test_adjustment = get_adjustment_amount((1920, 1000), test_fb.top_left[0], test_fb.top_left[1], test_fb.bottom_right[0], test_fb.bottom_right[1])
|
out_file.write(f"{ground_truth[0].frame_number}, 0,\n")
|
||||||
|
|
||||||
if last_frame_num != test_fb.frame_number and average_count != 0:
|
bring_up_gt()
|
||||||
with open(args.out_file, 'a') as out_file:
|
|
||||||
out_file.write(f"{average_sum},\n")
|
bring_up_gt()
|
||||||
average_sum = 0
|
|
||||||
average_count = 0
|
assert(ground_truth[0].frame_number == test_fb.frame_number)
|
||||||
|
gt_frame = ground_truth[0]
|
||||||
average_count += 1
|
|
||||||
# get the average
|
gt_adjustment = get_adjustment_amount((1920, 1000), gt_frame.top_left[0], gt_frame.top_left[1], gt_frame.bottom_right[0], gt_frame.bottom_right[1])
|
||||||
average_sum += abs(( (gt_adjustment[0] - test_adjustment[0]) + (gt_adjustment[1] - test_adjustment[1]) ) / 2)
|
test_adjustment = get_adjustment_amount((1920, 1000), test_fb.top_left[0], test_fb.top_left[1], test_fb.bottom_right[0], test_fb.bottom_right[1])
|
||||||
|
|
||||||
last_frame_num = test_fb.frame_number
|
if last_frame_num != test_fb.frame_number :
|
||||||
|
if average_count > 0:
|
||||||
|
with open(args.out_file, 'a') as out_file:
|
||||||
|
out_file.write(f"{average_sum},\n")
|
||||||
|
if args.faces_count_file:
|
||||||
|
with open(args.faces_count_file, 'a') as out_file:
|
||||||
|
out_file.write(f"{test_fb.frame_number}, {average_count},\n")
|
||||||
|
average_sum = 0
|
||||||
|
average_count = 0
|
||||||
|
|
||||||
|
average_count += 1
|
||||||
|
# get the average
|
||||||
|
average_sum += abs(( (gt_adjustment[0] - test_adjustment[0]) + (gt_adjustment[1] - test_adjustment[1]) ) / 2)
|
||||||
|
|
||||||
|
last_frame_num = test_fb.frame_number
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,66 +1,66 @@
|
||||||
import cv2
|
import cv2
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
tracker = cv2.TrackerMIL_create()
|
tracker = cv2.TrackerMIL_create()
|
||||||
|
|
||||||
# Read video
|
# Read video
|
||||||
video = cv2.VideoCapture("./validation/TestVideo.mp4")
|
video = cv2.VideoCapture("./validation/TestVideo.mp4")
|
||||||
|
|
||||||
# Exit if video not opened.
|
# Exit if video not opened.
|
||||||
if not video.isOpened():
|
if not video.isOpened():
|
||||||
print("Could not open video")
|
print("Could not open video")
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
# Read first frame.
|
# Read first frame.
|
||||||
ok, frame = video.read()
|
ok, frame = video.read()
|
||||||
if not ok:
|
if not ok:
|
||||||
print('Cannot read video file')
|
print('Cannot read video file')
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
# Define an initial bounding box
|
# Define an initial bounding box
|
||||||
bbox = (857, 189, 346, 434)
|
bbox = (857, 189, 346, 434)
|
||||||
|
|
||||||
# Initialize tracker with first frame and bounding box
|
# Initialize tracker with first frame and bounding box
|
||||||
ok = tracker.init(frame, bbox)
|
ok = tracker.init(frame, bbox)
|
||||||
|
|
||||||
frame_count = 0
|
frame_count = 0
|
||||||
while True:
|
while True:
|
||||||
# Read a new frame
|
# Read a new frame
|
||||||
ok, frame = video.read()
|
ok, frame = video.read()
|
||||||
if not ok:
|
if not ok:
|
||||||
break
|
break
|
||||||
|
|
||||||
# Start timer
|
# Start timer
|
||||||
timer = cv2.getTickCount()
|
timer = cv2.getTickCount()
|
||||||
|
|
||||||
# Update tracker
|
# Update tracker
|
||||||
ok, bbox = tracker.update(frame)
|
ok, bbox = tracker.update(frame)
|
||||||
|
|
||||||
# Calculate Frames per second (FPS)
|
# Calculate Frames per second (FPS)
|
||||||
fps = cv2.getTickFrequency() / (cv2.getTickCount() - timer);
|
fps = cv2.getTickFrequency() / (cv2.getTickCount() - timer);
|
||||||
|
|
||||||
# Draw bounding box
|
# Draw bounding box
|
||||||
if ok:
|
if ok:
|
||||||
# Tracking success
|
# Tracking success
|
||||||
p1 = (int(bbox[0]), int(bbox[1]))
|
p1 = (int(bbox[0]), int(bbox[1]))
|
||||||
p2 = (int(bbox[0] + bbox[2]), int(bbox[1] + bbox[3]))
|
p2 = (int(bbox[0] + bbox[2]), int(bbox[1] + bbox[3]))
|
||||||
|
|
||||||
with open("./ground_truth.txt", 'a') as output_file:
|
with open("./ground_truth.txt", 'a') as output_file:
|
||||||
output_file.write(f"{frame_count}, {p1[0]}, {p1[1]}, {p2[0]}, {p2[1]}\n")
|
output_file.write(f"{frame_count}, {p1[0]}, {p1[1]}, {p2[0]}, {p2[1]}\n")
|
||||||
|
|
||||||
cv2.rectangle(frame, p1, p2, (255,0,0), 2, 1)
|
cv2.rectangle(frame, p1, p2, (255,0,0), 2, 1)
|
||||||
else :
|
else :
|
||||||
# Tracking failure
|
# Tracking failure
|
||||||
cv2.putText(frame, "Tracking failure detected", (100,80), cv2.FONT_HERSHEY_SIMPLEX, 0.75,(0,0,255),2)
|
cv2.putText(frame, "Tracking failure detected", (100,80), cv2.FONT_HERSHEY_SIMPLEX, 0.75,(0,0,255),2)
|
||||||
|
|
||||||
# Display FPS on frame
|
# Display FPS on frame
|
||||||
cv2.putText(frame, "FPS : " + str(int(fps)), (100,50), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (50,170,50), 2)
|
cv2.putText(frame, "FPS : " + str(int(fps)), (100,50), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (50,170,50), 2)
|
||||||
|
|
||||||
# Display result
|
# Display result
|
||||||
cv2.imshow("Tracking", frame)
|
cv2.imshow("Tracking", frame)
|
||||||
|
|
||||||
frame_count += 1
|
frame_count += 1
|
||||||
|
|
||||||
# Exit if ESC pressed
|
# Exit if ESC pressed
|
||||||
k = cv2.waitKey(1) & 0xff
|
k = cv2.waitKey(1) & 0xff
|
||||||
if k == 27 : break
|
if k == 27 : break
|
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue