-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathFaceCaptureandFiles.py
More file actions
390 lines (331 loc) · 18.8 KB
/
FaceCaptureandFiles.py
File metadata and controls
390 lines (331 loc) · 18.8 KB
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
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
import PIL.Image
import PIL
import numpy as np
import cv2 #this is a module for life feed camera stuff
import os
from pathlib import Path #used to get what type a file is (.txt,.png etc)
#####################
# Some import Notes about things:
# I assume some level of idealized file structure, because im using this purely for personal use, i think thats ok.
# This 'idealized' structure is as follows: i assume there will be no more then one extra level of folders within a folder im am accessing
#! (MIGHT ACTUALLY MAKE CODE THAT AUTOMATES THIS IDK) And two, that if a folder contains folders, it DOESNT contain anything like images or stuff we might want to load in
#
#####################
class FaceCamera:
face_detector = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_frontalface_default.xml") #finds fave in a image
def __init__(self):
pass
######################
#_capture_and_get_faces_data
# takes N pictures and then returns the data from the cropped image
# downsizepixels is the size in which the face should be downscaled to
# datatype: if 'pixel_list' saves pixel data, if 'image' saves it as PIL object and returns that
#
#(where each list is one images grayscale, down sized pixel data)
######################
def _capture_and_get_faces_data(self,N,downsizepixels = 64,datatype = "pixel_list"): #n is number of pictures to take
final_image_data = []
cam = cv2.VideoCapture(1) #video capture object made
cv2.namedWindow("Picture") #names the window
taking_pictures = True
while taking_pictures:
ret, frame = cam.read() #gets the camera
if not ret:
print("Failed to grab frame")
break
cv2.imshow("Picture", frame) #shows the video/livefeed
k = cv2.waitKey(1) #tells it to wait for a key press
if k%256 == 27:# ESC pressed
print("Escape hit, closing...")
break
elif k%256 == 32:# SPACE pressed
for x in range(N): #for total numebr of images
print(str(x) + " picture has been taken")
picture = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) #makes it grayscale while capturing what is displayed on the frame
face_data = self.face_detector.detectMultiScale(frame, scaleFactor=1.1, minNeighbors=5, minSize=(40, 40)) #gets face data from the face detection model
for (x, y, w, h) in face_data: #crops the picture from the face data
face = picture[y:y+h,x:x+w]
face = cv2.resize(face, (downsizepixels, downsizepixels)) #this resizes the image to be of lower pixel count to be the ratio you input
image_cropped = PIL.Image.fromarray(face) #gets the frame data and gives it to a PIL image
if datatype == "pixel_list":
values = list(image_cropped.getdata()) #gets the indidual pixel data as a list
final_image_data.append(values)
elif datatype == "image":
final_image_data.append(image_cropped)
taking_pictures = False #finishs taking pictures
cam.release()
cv2.destroyAllWindows()
return final_image_data #returns all the images pixel data
#TODO
#TODO
#TODO
#TODO
#TODO
#TODO ADD A FUNCTION THAT TAKES ONE IMAGE, AND 'PREPS IT'
#TODO ADD A FEATURE TO CROP BASED ON DIFFERENT THINGS?
#TODO
#TODO
#TODO
#TODO
##################
# takes in the file path and the data for one image and saves it in the desired location =
# image_formats are any PIL support file types you can save to, like 'PNG', 'JPEG' etc see here:
# https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html
##################
def _write_info_to_file(self,file_path,data,image_format="PNG"):
if type(data) == list: # if we save it as pixel data explictly (!!!!!!!!!!will be a whitespace seperated file!!!!!!!!!!)
file = open(file_path, "a") #opens file
for x in data:
file.write(str(x)) #reads the data in
file.write(" ")
file.close()
elif type(data) == PIL.Image.Image: # if we save as a image (like a png)
if data.mode != 'RGBA': #this is to make sure the image has the rigth transperency settings
data = data.convert('RGBA')
data.save(file_path, format=image_format)
##################
#_write_all_info_to_file:
# takes the list of image data, and where the images should be saved and places then there with the desired file type (pixel list, png etc)
# folder_name: what to call the higher directory of where images are to be placed
# folder_location: where 'folder_name' is to be located (defaults to current working directory)
# subfolder_name: if you want to put the data into a subfolder of 'folder_name' gives this a value
# datatype: pixel_list, PNG, JPEG, etc, what file type we should use to store the image data
##################
def _write_all_info_to_file(self,image_data,folder_name="temp_storage",folder_location = os.getcwd(),subfolder_name="",datatype="pixel_list"):
folder_path = folder_location + "/" + folder_name
##
## First checks, does highest level folder exist? if not make one
##
try:
os.mkdir(folder_path) #makes highest level fold if it doesnt exist
print(f"Folder '{folder_path}' created.")
except FileExistsError:
pass
except FileNotFoundError:
raise FileNotFoundError((f"Parent directory does not exist."))
##
## Next checks, Is a subfolder desired? if so, does that folder exist? if not make one
##
if subfolder_name != "" : #if we are to write to a sub file, make sure that exists
subfolder_path = folder_path + "/" + subfolder_name
try:
os.mkdir(subfolder_path)
except FileExistsError:
pass
except FileNotFoundError:
raise FileNotFoundError((f"Parent directory does not exist."))
##
## Now writes the data to the file
## #this is the list of all support datatypes right now
if datatype == "pixel_list":
file_type = ".txt"
elif datatype == "PNG":
file_type = ".png"
elif datatype == "JPEG":
file_type = ".jpeg"
for x in range(len(image_data)): #for all the image data
if subfolder_name != "": #IE we have a subfolder we want to write to
file_name = str(subfolder_name) + "_" + str(x) + file_type
file_path = subfolder_path + "/" + file_name #final file path for this specifc image
#file_path = str(section) + "/" + person_name + "/" + file_name #makes the file path for this iteration
self._write_info_to_file(file_path,image_data[x])
elif subfolder_name == "":
file_name = str(folder_name) + "_" + str(x) + file_type #makes a file name for this specfic piece of data
file_path = folder_path + "/" + file_name #final file path for this specifc image (no sub folder)
self._write_info_to_file(file_path,image_data[x])
##################
# createReducedFaceData
# Captures and writes the relvent face data to files given the following configurations
# N: number of images to capture
# downsizepixels: num of pixels per side to reduce image down to
# datatype: how to store the image data (PNG, JPEG, list of pixel values (input 'pixel_list'))
# folder_name: what to call the higher directory of where images are to be placed
# folder_location: where 'folder_name' is to be located (defaults to current working directory)
# subfolder_name: if you want to put the data into a subfolder of 'folder_name' gives this a value
##################
def createReducedFaceData(self,
N,
downsizepixels = 64,
datatype = "pixel_list",
folder_name="temp_storage",
folder_location = os.getcwd(),
subfolder_name="",):
image_data = self._capture_and_get_faces_data(N,downsizepixels,datatype)
self._write_all_info_to_file(image_data,folder_name,folder_location,subfolder_name,datatype)
################
# _list_folder_names_in_dir
# gets list of all folder names within a directory
# full_directory_path: the FULL directory pathh to the folder we are looking in to see what folders are inside of it
################
def _list_folder_names_in_dir(self,full_directory_path):
folders = []
with os.scandir(full_directory_path) as entries:
for entry in entries:
if entry.is_dir():
folders.append(entry.name) # Use entry.path for full path
return folders
############
# Counts the number of files in the specified directory (ALL of them folders included)
# path: this is the FULL path to the folder mind you
############
def _count_all_files_in_directory(self,path):
count = 0
# Iterate over all entries in the directory
for entry in os.listdir(path):
full_path = os.path.join(path, entry)
if os.path.isfile(full_path): #make sure its an actual file
count += 1
return count
############
# Counts the number of files in the specified directory (NOT including folders)
# path: this is the FULL path to the folder mind you
############
def _count_none_folders_in_directory(self,path):
count = 0
# Iterate over all entries in the directory
for entry in os.listdir(path):
full_path = os.path.join(path, entry)
if os.path.isfile(full_path): #make sure its an actual file and not a folder
count += 1
num_folders = len(self._list_folder_names_in_dir(path)) #gest num of FOLDERS in the folder
count = count
return count
############
#Tells us what file type (.txt,.png etc) a specfic directory is made up of (not including folders)
#! THROWS A ERROR IF MORE THEN 1 TYPE EXISTS
############
def _discover_file_type(self,path):
dir_path = Path(path)
if not dir_path.is_dir():
raise Exception("This is not a valid directory")
all_exstensions = []
for file in dir_path.iterdir():
all_exstensions.append(file.suffix)
all_exstensions = list(filter(None, all_exstensions)) #clears out any empty string elements
intial_exstension = all_exstensions[0]
for ext in all_exstensions:
if ext != intial_exstension:
raise Exception("You cant have more then 1 file type to load in")
return intial_exstension
###################
# _retrive_files_by_subfolder
# Gets all files within a certain file, and, if a subfolder is given, gets all files within that subfolder specficly
# folder_location: where the folder exists in the directory structure
# subfolder_name: we default assume there is no subfolder
# folder_name: the name of the folder we are pulling files from
###################
def _retrive_files_by_subfolder(self,folder_name,folder_location = os.getcwd(),subfolder_name=""):
if subfolder_name != "": #if we have a subfolder, use that to make full file path
full_folder_path = folder_location + "/" + folder_name + "/" + subfolder_name
specfic_file_name = subfolder_name
elif subfolder_name == "":
full_folder_path = folder_location + "/" + folder_name
specfic_file_name = folder_name
file_count = self._count_none_folders_in_directory(full_folder_path) #how many files to load in (OF NONE FOLDER FILES)
file_extension = self._discover_file_type(full_folder_path) #gets what file ex
all_image_data = []
for image_count in range(file_count): #for num of files
#! now we do different things depending on what file exstension we have
if file_extension == ".txt": #list of pixels
try:
file = open(full_folder_path + "/" + specfic_file_name + "_" + str(image_count) + file_extension) #opens the file
except FileNotFoundError: #checks if the file exists and etc
raise FileNotFoundError((f"File does not exist or you tampered with the numberings of the files. Make sure all file numbers (the numbers in their name) are in sequential order from 0 to N-1 (where N is the total number of files )"))
except FileExistsError:
raise FileExistsError((f"Parent directory does not exist."))
image_data = [] #temp image data
for x in ((file.readline()).split()): #splits all the data in the file by whitespace (its all one long line in each file)
image_data.append(int(x))
all_image_data.append(image_data) #adds the one image to the greater list
file.close()
else: #this will handle png and jpeg files
try:
img = PIL.Image.open(full_folder_path + "/" + specfic_file_name + "_" + str(image_count) + file_extension)
except FileNotFoundError:
raise FileNotFoundError((f"File does not exist or you tampered with the numberings of the files. Make sure all file numbers (the numbers in their name) are in sequential order from 0 to N-1 (where N is the total number of files )"))
except FileExistsError:
raise FileExistsError((f"Parent directory does not exist."))
all_image_data.append(img)
return all_image_data
##########################
# _retrive_all_files
# gets all files, whether they are in a subfolder or not from the folder
# folder_location: where the folder exists in the directory structure
# folder_name: the name of the folder we are pulling files from
##########################
def _retrive_all_files(self,folder_name,folder_location = os.getcwd()):
full_folder_path = folder_location + "/" + folder_name
list_subfolders = self._list_folder_names_in_dir(full_folder_path)
data = []
if list_subfolders:
for subfolder in list_subfolders: #for each subfolder
subfolder_data = self._retrive_files_by_subfolder(folder_name,folder_location,subfolder) #gets all the data within a subfolder
data.append(subfolder_data)
if self._count_none_folders_in_directory(full_folder_path) != 0: #ie only runs this if there are files in the top folder that arent folders
extra_data = self._retrive_files_by_subfolder(folder_name,folder_location)
data.append(extra_data)
else:
folder_data = self._retrive_files_by_subfolder(folder_name,folder_location) #gets all the data within a subfolder
data.append(folder_data)
return data
##########################
# load_and_prepare_data
# gets all files, whether they are in a subfolder or not from the folder and then prepares then for use in model (ie giving them labels)
# folder_location: where the folder exists in the directory structure
# folder_name: the name of the folder we are pulling files from
# the output has shape of data : ((total images in all folders) x (downscale amount)^2)
# labels : (total images in all folders)
#! NOTE: This assumes all the data loaded in is of pixel list format and will have other checks for the correct preperation of data such has
#! homogenius shape, and that they actaully are pixel lists and not pngs
#! NOTE: This also assumes that each subfolder is of a UNQIUE image type, ie, it assumes that if you have a folder of 'car' images, that you
#! also wont have another folder that should also be 'car' images, as otherwise they will be getting unique labels
#* Thusly: this is meant to be a internal function, a additional function will later serve as a 'wraper' that will ensure the function is provided safe and correct things
##########################
def _load_and_prepare_pixel_data(self,folder_name,folder_location = os.getcwd()):
data = self._retrive_all_files(folder_name,folder_location)
#checks to make sure all subfolders loaded in are of the same data type
base_type = type(data[0][0]) #takes the first image type(pixel list, or png) of the first subfolder/group
for group in data:
group_type = type(group[0]) #compar
if base_type != group_type:
raise TypeError("Your file types are miss matched, this needs to be resolved in some manner")
#preparing the labels
labels = []
iter = 0
for group in data: #for each subfolder, gets a different label
sub_labels = np.zeros(len(group))
sub_labels = sub_labels + iter #this makes the labels
iter += 1
labels.append(sub_labels)
print(len(data[0]))
try:
np_data = np.array(data) #! this will also raise a error if the files have different types, I think, so its like a second check device
except ValueError:
raise TypeError("Your file types are miss matched, this needs to be resolved in some manner")
print(np_data.shape)
np_labels = np.array(labels)
final_data = np_data.reshape(-1,np_data.shape[2])
final_labels = np_labels.reshape(-1)
return final_data, final_labels
#TODO
#TODO
#TODO ADD FUNCTINOALITY SUCH THAT IF THE FILES YOU WANT TO PREPARE ARE IN IMAGE FORMAT (SAY PNG) YOU CONVERT TO PIXEL DATA WITH COSTUMIZABLE SETTINGS
#TODO
#TODO
def load_prep_images(self,downscale,grayscale=False):
#* uses default load in function, then transform images, then convert to pixels
#
pass
cam = FaceCamera()
#print(cam._discover_file_type("temp_storage"))
#print(cam._list_folder_names_in_dir("."))
#print(cam._retrive_all_files("temp_storage"))
#print(cam._retrive_files_by_subfolder("temp_storage"))
#data = cam._capture_and_get_faces_data(10,datatype="image")
#cam._write_info_to_file("output_2.png",data[0])
#print(data[0])
#cam._write_all_info_to_file(data,datatype="PNG")
#print(cam._retrive_all_files("temp_storage"))
#print(len(cam._retrive_all_files("temp_storage")[2]))
data,labels = cam._load_and_prepare_pixel_data("temp_storage")
print(labels.shape)