diff --git a/Func/ClassifierModule.py b/Func/ClassifierModule.py new file mode 100644 index 0000000000000000000000000000000000000000..9b784d87b0788d0c1f7bdc2a1ac753fff5c08d68 --- /dev/null +++ b/Func/ClassifierModule.py @@ -0,0 +1,66 @@ +import keras +import numpy as np +import cv2 + + +class Classifier: + + def __init__(self, model_path, label_path): + self.model_path = model_path + + np.set_printoptions(suppress=True) + + self.model = keras.models.load_model(self.model_path) + self.data = np.ndarray(shape=(1, 224, 224, 3), dtype=np.float32) + self.labels_path = label_path + + if self.labels_path: + with open(self.labels_path, "r") as label_file: + self.list_labels = [line.strip() for line in label_file] + else: + print("No Labels Found") + + def getPrediction(self, img, draw=True, pos=(50, 50), scale=2, color=(0, 255, 0)): + img_resized = cv2.resize(img, (224, 224)) + image_array = np.asarray(img_resized) + normalized_image_array = (image_array.astype(np.float32) / 127.0) - 1 + + self.data[0] = normalized_image_array + + prediction = self.model.predict(self.data) + index_val = np.argmax(prediction) + + if draw and self.labels_path: + label_text = str(self.list_labels[index_val]) + cv2.putText(img, label_text, pos, cv2.FONT_HERSHEY_COMPLEX, scale, color, 2) + + return list(prediction[0]), index_val + + +def main(): + cap = cv2.VideoCapture(0) + + mask_classifier = Classifier('Model/keras_model.h5', 'Model/labels.txt') + + while True: + ret, frame = cap.read() + + if not ret: + print("Failed to capture frame") + break + + prediction = mask_classifier.getPrediction(frame) + + print("Prediction:", prediction) + + cv2.imshow("Image", frame) + + if cv2.waitKey(1) & 0xFF == ord('q'): + break + + cap.release() + cv2.destroyAllWindows() + + +if __name__ == "__main__": + main() diff --git a/Func/CloseProgram.py b/Func/CloseProgram.py index 3109b6e62a86acfbc5006bcd528acac050df6d5c..c0718008506f92b145b947c79237c71e001569ce 100644 --- a/Func/CloseProgram.py +++ b/Func/CloseProgram.py @@ -5,5 +5,3 @@ def Close(cap): cap.release() cv2.destroyAllWindows() print('closing') - - diff --git a/Func/getSubFolders.py b/Func/getSubFolders.py index 217d43f512c4ea586a2c48bc63d5f1a77551e810..a2dabc591b56c183ab80df6f1df2f0e2c3e44443 100644 --- a/Func/getSubFolders.py +++ b/Func/getSubFolders.py @@ -9,4 +9,4 @@ def count_sub_folders(folder_path): sub_folders = [f for f in os.listdir(folder_path) if os.path.isdir(os.path.join(folder_path, f))] num_sub_folders = len(sub_folders) - return num_sub_folders \ No newline at end of file + return num_sub_folders diff --git a/Model/keras_model.h5 b/Model/keras_model.h5 index 0169f5a80825b3b126671903fdf5fa711e782af3..cb2d0ba86927f0ce886987e6222fa846a1adb344 100644 Binary files a/Model/keras_model.h5 and b/Model/keras_model.h5 differ diff --git a/Model/labels.txt b/Model/labels.txt index ca427253d6f818ccda5af95a99305e035f85b407..5fbcfab644bb75991252a4d2f6ce35c41d649e4d 100644 --- a/Model/labels.txt +++ b/Model/labels.txt @@ -2,4 +2,5 @@ 1 B 2 C 3 D -4 E \ No newline at end of file +4 E +5 F \ No newline at end of file diff --git a/main.py b/main.py index 4df15358d2aac4a09d2c385e88f66bf55dd86edf..4a6a59adc32d640bb1ba9d0c6222dffa6ad68a5f 100644 --- a/main.py +++ b/main.py @@ -1,7 +1,6 @@ -import cv2 import numpy as np from cvzone.HandTrackingModule import HandDetector -from cvzone.ClassificationModule import Classifier +from Func.ClassifierModule import Classifier from Func.CloseProgram import Close from Func.Helpers import * @@ -11,10 +10,11 @@ size = 300 capture = cv2.VideoCapture(0) detector = HandDetector(maxHands=1) -classifier = Classifier("Model/Model.h5", "Model/labels.txt") -# classifier = Classifier("Model/keras_model.h5", "Model/labels.txt") -letters = GetLabels("Model/labels.txt") +model_path = "Model/keras_model.h5" +label_path = "Model/labels.txt" +classifier = Classifier(model_path, label_path) +letters = GetLabels(label_path) if not capture.isOpened(): print("Failed to open video capture.") @@ -47,8 +47,8 @@ while True: CalculateHeight(size, h, w, imgCropped, imgFixed) prediction, index = GetPrediction(classifier, imgFixed) - print(prediction) - print(index) + print('pred', prediction) + print('index', index) cv2.putText(imgOutput, letters[index], (x, y), cv2.FONT_HERSHEY_TRIPLEX, 2, (255, 0, 255), 2) diff --git a/trainModel.py b/trainModel.py index 47a1da4ae475bf3331f5a1dc506ade22cc1e5014..2fad7ff56726e65fa07342266458dee1605e47f9 100644 --- a/trainModel.py +++ b/trainModel.py @@ -1,55 +1,67 @@ +import time from keras.models import Sequential from keras.layers import Conv2D, MaxPooling2D, Flatten, Dense from keras.preprocessing.image import ImageDataGenerator from keras.losses import CategoricalCrossentropy +from keras.src.optimizers import Adam from Func.getSubFolders import count_sub_folders -path = 'Data_test' -output = 'Model/pruned.h5' +path = 'Data' +output = 'Model/keras_model.h5' +start_time = time.time() # Step 1: Load and Preprocess Images -train_datagen = ImageDataGenerator( +datagen = ImageDataGenerator( rescale=1. / 255, + validation_split=0.2, + width_shift_range=0.2, + height_shift_range=0.2, shear_range=0.2, zoom_range=0.2, - horizontal_flip=True ) test_datagen = ImageDataGenerator(rescale=1. / 255) # Step 2: Label the Data -train_set = train_datagen.flow_from_directory( +train_set = datagen.flow_from_directory( path, target_size=(224, 224), batch_size=32, - class_mode='categorical' + class_mode='categorical', + subset='training' ) -test_set = test_datagen.flow_from_directory( +test_set = datagen.flow_from_directory( path, target_size=(224, 224), batch_size=32, - class_mode='categorical' + class_mode='categorical', + subset='validation' ) # Step 4: Build the Model model = Sequential() model.add(Conv2D(32, (3, 3), input_shape=(224, 224, 3), activation='relu')) model.add(MaxPooling2D(pool_size=(2, 2))) +model.add(Conv2D(64, (3, 3), activation='relu')) +model.add(MaxPooling2D((2, 2))) +model.add(Conv2D(128, (3, 3), activation='relu')) +model.add(MaxPooling2D((2, 2))) +model.add(Conv2D(256, (3, 3), activation='relu')) +model.add(MaxPooling2D((2, 2))) model.add(Flatten()) +model.add(Dense(units=256, activation='relu')) model.add(Dense(units=128, activation='relu')) model.add(Dense(units=count_sub_folders(path), activation='softmax')) - # Compile the Model after pruning -model.compile(optimizer='adam', +model.compile(optimizer=Adam(learning_rate=0.001), loss=CategoricalCrossentropy(from_logits=False), metrics=['accuracy']) # Step 6: Train the Model -model.fit(train_set, epochs=10, validation_data=test_set) - +model.fit(train_set, epochs=20, validation_data=test_set) # Step 7: Evaluate the Model loss, accuracy = model.evaluate(test_set) @@ -57,3 +69,9 @@ print(f'Test loss: {loss}, Test accuracy: {accuracy}') # Save the trained model model.save(output) +end_time = time.time() + +execute_time = (end_time - start_time) / 60 + +# Print the result +print(f"It took: {execute_time:0.2f} seconds")