Tải bản đầy đủ (.pdf) (12 trang)

báo cáo bài tập nhóm nhận diện khuôn mặt bằng ai dự đoán tuổi và giới tính

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (238.1 KB, 12 trang )

<span class="text_page_counter">Trang 1</span><div class="page_container" data-page="1">

<b>BỘ GIÁO DỤC VÀ ĐÀO TẠO </b>

<b>TRƯỜNG ĐẠI HỌC SƯ PHẠM KỸ THUẬT TP. HCM KHOA CƠ KHÍ CHẾ TẠO MÁY </b>

<b>BÁO CÁO BÀI TẬP NHĨM </b>

<b>NHẬN DIỆN KHN MẶT BẰNG AI DỰ ĐỐN TUỔI VÀ GIỚI TÍNH </b>

<b>MƠN HỌC: TRÍ TUỆ NHÂN TẠO </b>

</div><span class="text_page_counter">Trang 3</span><div class="page_container" data-page="3">

<b><small>1 </small></b>

<b>1. LÝ DO CHỌN ĐỀ TÀI </b>

Chúng em thực hiện bài tập nhóm lần này theo yêu cầu thầy đưa ra, qua đó có thể tích lũy cho bản thân một số điều sau:

- Sử dụng thuần thục các thư viện, thuật toán

- Giúp nhận biết được gương mặt, dự đoán được tuổi và giới tính của người ngồi trước camera, sau đó xem người đó có tập trung vào trong quảng cáo đang chiếu ra trên màn hình hay khơng. Từ đó xác định được các nhóm đối tượng phù hợp để xuất hiện quảng cáo, tăng hiệu quả của công việc.

- Cải thiện và phát triển các kỹ năng làm việc nhóm, khả năng research, ...

<b>2. TỔNG QUAN SƠ BỘ </b>

Thừa hưởng những thành tựu của nền khoa học kỹ thuật phát triển. Nhận diện khuôn mặt là một công nghệ được ứng dụng rộng rãi trong đời sống hằng ngày của con người như các hệ thống giám sát tại các tòa nhà, sân bay, trạm ATM, hệ thống chấm cơng, camera chống trộm, xác thực danh tính, …có rất nhiều các phương pháp nhận dạng khuôn mặt để nâng cao hiệu suất, bảo mật hiệu quả, cải thiện độ chính xác, tích hợp dễ dàng hơn. Hệ thống nhận dạng khuôn mặt được sử dụng trong các trường hợp như đăng nhập ID, phát hiện gian lận, an ninh mạng, kiểm soát sân bay và biên giới, ngân hàng, chăm sóc sức khỏe. Tuy nhiên dù ít hay nhiều thì những phương pháp này đang gặp phải những khó khăn, thử thách như về độ sáng, hướng nghiêng, kích thước hình ảnh, hay ảnh hưởng của tham số môi trường

<b>3. PHÂN TÍCH CODE </b>

Đầu tiên, chúng em import các thư viện và mô đun cần thiết để chạy code <small>import tensorflow astf </small>

<small>from tensorflow.keras.utils import load_img </small>

<small>from keras.models import Sequential, Model </small>

<small>from keras.layers import Dense, Conv2D, Dropout, Flatten, MaxPooling2D, Input </small>

<small>fromtqdm.notebookimporttqdm </small>

Sau đó, kết nối với GG Drive và giải nén dữ liệu tệp zip UTKFace.zip <small>from google.colab import drive </small>

<small>drive.mount('/content/drive') </small>

<small>!unzip '/content/drive/MyDrive/UTKFace.zip' </small>

Tiếp theo, cần tạo ra ba danh sách để lưu trữ độ tuổi, giới tính và đường dẫn hình ảnh. Trích

</div><span class="text_page_counter">Trang 4</span><div class="page_container" data-page="4">

xuất tên tệp hình ảnh bằng cách sử dụng thư mục os.list cung cấp tất cả tên tệp bên trong UTKFace và xáo trộn các tên tệp đó vì dữ liệu khi nhận diện là ngẫu nhiên, không tuần tự. <small>BASE_DIR = '/content/UTKFace' </small>

<small>age_labels = [] </small>

<small>gender_labels = [] </small>

<small>image_paths = [] </small>

<small>image_filenames = os.listdir(BASE_DIR) </small>

<small>random.shuffle(image_filenames) </small>

Đoạn code dưới đây đang duyệt qua danh sách các hình ảnh để lấy thơng tin và giới tính từ tên tệp:

<small>forimageintqdm(image_filenames): </small>

<small> image_path = os.path.join(BASE_DIR, image) img_components = image.split('_') </small>

<small> age_label = int(img_components[0]) gender_label = int(img_components[1]) </small>

<small> # Append the image_path, age_label, and gender_label </small>

<small> age_labels.append(age_label) gender_labels.append(gender_label) image_paths.append(image_path)</small>

Sau đó in ra để xác định xem số lượng nhãn độ tuổi, nhãn giới tính và đường dẫn hình ảnh có giống nhau hay khơng

<small>print('Number of age_labels: {len(age_labels)}, Number of gender_labels: {len(gender_labels)}, Number of image_paths: {len(image_paths)}')</small>

Tiếp theo tạo một từ điển đơn giản, 0 là Male, 1 là Female

</div><span class="text_page_counter">Trang 5</span><div class="page_container" data-page="5">

<b><small>3 </small></b>

Và chúng em có đoạn code cho hiển thị một hình ảnh ngẫu nhiên, phân tích dữ liệu và cho ra tuổi cùng giới tính của tấm hình ấy.

<small>rand_index = random.randint(0, len(image_paths)) </small>

<small>age = df['age'][rand_index] </small>

<small>gender = df['gender'][rand_index] </small>

<small>IMG = Image.open(df['image_path'][rand_index]) </small>

<small>plt.title('Age: {age} Gender: {gender_mapping[gender]}') </small>

<small> img = load_img(sample) img = np.array(img) </small>

Đây là khai báo hàm Python có tên là ‘extract_image_features’, nhận một tham số là

images. Tham số này là một danh sách chứa đường dẫn đến các hình ảnh hoặc nội dung hình ảnh.

features = list(): Tạo một biến features là một danh sách rỗng được sử dụng để lưu trữ các đặc trưng của hình ảnh sau khi được xử lý

<small>forimageintqdm(images): </small>

<small> img = load_img(image, grayscale=True) </small>

<small> img = img.resize((128, 128), Image.ANTIALIAS) img = np.array(img) </small>

<small> features.append(img) </small>

<small> features = np.array(features) </small>

<small> features = features.reshape(len(features), 128, 128, 1) returnfeatures</small>

</div><span class="text_page_counter">Trang 6</span><div class="page_container" data-page="6">

Thực hiện việc xử lý từng hình ảnh trong danh sách ‘images’, duyệt và thay đổi hình ảnh sau đó thay đổi kích thước ảnh thành 128x128 pixel, chuyển đổi thành Numpy thêm vào danh sách ‘features’

<small>X = extract_image_features(df['image_path']) </small>

<small>X = X255.0 </small>

Gán kết quả trả về chứa các đặc trưng của tất cả hình ảnh

<small>y_gender = np.array(df['gender']) </small>

<small>y_age = np.array(df['age']) </small>

Đoạn code này giúp chuyển đổi dữ liệu từ cột của DataFrame thành các mảng NumPy để thuận tiện cho việc xử lý và tính tốn.

<small>input_shape = (128, 128, ) </small>

Dịng code này định nghĩa biến input_shape là một tuple có giá trị là (128, 128, 1)

<small>inputs = Input((input_shape)) </small>

<small>conv_1 = Conv2D(32, kernel_size=(3, 3), activation='relu')(inputs) </small>

<small>max_1 = MaxPooling2D(pool_size=(2, 2))(conv_1) </small>

<small>conv_2 = Conv2D(64, kernel_size=(3, 3), activation='relu')(max_1) </small>

<small>max_2 = MaxPooling2D(pool_size=(2, 2))(conv_2) </small>

<small>conv_3 = Conv2D(128, kernel_size=(3, 3), activation='relu')(max_2) </small>

<small>max_3 = MaxPooling2D(pool_size=(2, 2))(conv_3) </small>

<small>conv_4 = Conv2D(256, kernel_size=(3, 3), activation='relu')(max_3) </small>

<small>max_4 = MaxPooling2D(pool_size=(2, 2))(conv_4) </small>

<small>flatten = Flatten()(max_4) </small>

Định nghĩa đầu vào của mơ hình với kích thước là input_shape. Sau đó, Tích chập đầu vào với 32 bộ lọc kích thước (3, 3) và hàm kích hoạt ReLU, Lấy giá trị lớn nhất từ các vùng 2x2, giúp giảm kích thước của đầu ra. Lớp Flatten được sử dụng để biến đổi đầu ra của lớp pooling cuối cùng (max_4) thành một vector 1 chiều. Nó "làm phẳng" dữ liệu, giữ nguyên thơng tin từ các bức ảnh đã được trích xuất các đặc trưng.

<small>dense_1 = Dense(256, activation='relu')(flatten) </small>

<small>dense_2 = Dense(256, activation='relu')(flatten) </small>

<small>dropout_1 = Dropout(0.3)(dense_1) </small>

<small>dropout_2 = Dropout(0.3)(dense_2) </small>

<small>output_1 = Dense(1activation='sigmoid', name='gender_out')(dropout_1) </small>

<small>output_2 = Dense(1activation='relu', name='age_out')(dropout_2) </small>

<small>model = Model(inputs=[inputs], outputs=[output_1, output_2]) </small>

<small>model.compile(loss=['binary_crossentropy', 'mae'], optimizer='adam', metrics=['accuracy']) </small>

Đoạn code đang xây dựng một mơ hình mạng nơ-ron sâu (deep learning) để thực hiện hai nhiệm vụ: dự đốn giới tính và tuổi từ ảnh đầu vào

.

<small>from tensorflow.keras.utils import plot_model plot_model(model) </small>

Sau khi chạy đoạn mã trên sẽ vẽ biểu đồ cấu trúc của mô hình. Biểu đồ này sẽ mơ tả mối quan hệ giữa các lớp trong mơ hình, giúp hiểu cấu trúc tổng quan của mơ hình nhanh chóng.

<small>history = model.fit(x=X, y=[y_gender, y_age], </small>

<small> batch_size=32, epochs=50, validation_split=0.2) </small>

Tiến hành training

</div><span class="text_page_counter">Trang 7</span><div class="page_container" data-page="7">

<b><small>5 </small></b>

<small># plot results for gender </small>

<small>acc = history.history['gender_out_accuracy'] </small>

<small>val_acc = history.history['val_gender_out_accuracy'] </small>

<small>epochs = range(len(acc)) </small>

<small>plt.plot(epochs, acc, 'b', label='Training Accuracy') </small>

<small>plt.plot(epochs, val_acc, 'r', label='Validation Accuracy') </small>

<small>plt.title('Accuracy Graph') </small>

<small>plt.legend() </small>

<small>plt.figure() </small>

Dòng code này giúp theo dõi sự phát triển của độ chính xác trên cả tập training và tập kiểm thử qua các epoch, giúp đánh giá hiệu suất của mô hình và phát hiện hiện tượng overfitting hoặc underfitting.

<small>loss = history.history['gender_out_loss'] </small>

<small>val_loss = history.history['val_gender_out_loss'] </small>

Lấy thông tin về giá trị mất mát trên tập training từ lịch sử training (history). Trong đoạn mã này, "gender_out_loss" là mất mát của lớp đầu ra dự đốn giới tính và lấy thông tin về giá trị mất mát trên tập kiểm thử từ lịch sử training

<small>plt.plot(epochs, loss, 'b', label='Training Loss') </small>

<small>plt.plot(epochs, val_loss, 'r', label='Validation Loss') </small>

<small>plt.title('Loss Graph') </small>

<small>plt.legend() </small>

<small>plt.show() </small>

- 'b' và 'r' trong ‘plt.plot’ chỉ định màu của các đường ('b' cho màu xanh lam và 'r' cho màu đỏ).

- Tham số ‘label’ trong ‘plt.plot’ được sử dụng để gắn nhãn cho các dòng cho chú giải. - ‘plt.title’ đặt tiêu đề cho plot.

- ‘plt.legend()’ hiển thị chú giải, rất hữu ích khi vẽ nhiều dịng để phân biệt giữa chúng.

Mã này thường được sử dụng trong đào tạo machine learning model trong đó 'epochs' biểu thị số lần thuật tốn học sẽ hoạt động thơng qua toàn bộ tập dữ liệu đào tạo. 'Training Loss' và 'Validation Loss' là các số liệu được sử dụng để đánh giá mức độ hoạt động của mô hình trong quá trình đào tạo và trên dữ liệu khơng nhìn thấy tương ứng. Plot giúp hình dung các giá trị mất mát này thay đổi như thế nào qua các giai đoạn huấn luyện.

<small># plot results for age </small>

<small>loss = history.history['age_out_loss'] </small>

<small>val_loss = history.history['val_age_out_loss'] </small>

<small>epochs = range(len(loss)) </small>

- Vẽ đồ thị các giá trị tổn thất huấn luyện và xác thực cho đầu ra 'age' của mơ hình. 'age_out_loss' và 'val_age_out_loss' là các phần giữ chỗ cho các khóa thực tế trong đối tượng 'history' của bạn để lưu trữ các giá trị tổn thất trong quá trình đào tạo và xác thực cho đầu ra 'age'.

- Đảm bảo điều chỉnh mã theo các khóa thực tế được sử dụng trong đối tượng 'history' của bạn. Ngoài ra, việc cung cấp nhãn trục với ‘plt.xlabel’ và ‘plt.ylabel’ có thể nâng cao khả năng diễn giải biểu đồ của bạn.

<small>plt.plot(epochs, loss, 'b', label='Training Loss') </small>

<small>plt.plot(epochs, val_loss, 'r', label='Validation Loss') </small>

<small>plt.title('Loss Graph') </small>

</div><span class="text_page_counter">Trang 8</span><div class="page_container" data-page="8">

<small>plt.legend() </small>

<small>plt.show() </small>

Sử dụng lại đoạn mã để vẽ sơ đồ mất dữ liệu đào tạo và xác thực qua các epochs. Mã này được sử dụng để trực quan hóa xu hướng mất đi quá trình đào tạo và xác thực trong quá trình đào tạo.

<small>defget_image_features(image): </small>

<small> img = load_img(image, grayscale=True) </small>

<small> img = img.resize((128, 128), Image.ANTIALIAS) img = np.array(img) </small>

<small> img = img.reshape(1, 128, 128, 1) img = img255.0 </small>

<small> returnimg </small>

- Load Image:Hàm sử dụng hàm Load_img từ Keras để tải hình ảnh ở thang độ xám. - Resize Image: Nó thay đổi kích thước hình ảnh thành kích thước cố định 128x128 pixel

bằng cách sử dụng tính năng khử răng cưa để thay đổi kích thước mượt mà.

- Convert to NumPy Array: Hình ảnh được chuyển đổi thành mảng NumPy bằng np.array. - Reshape: Mảng được định hình lại để có kích thước (1, 128, 128, 1). Các kích thước bổ sung

thường được sử dụng khi làm việc với mạng nơ ron tích chập (CNN).

- Normalization: Các giá trị pixel được chuẩn hóa thành phạm vi [0, 1] bằng cách chia mỗi giá trị pixel cho 255,0.

Kết quả có thể được sử dụng làm đầu vào cho mơ hình mong đợi hình ảnh có kích thước 128x128 pixel

<small>img_to_test = '/content/drive/MyDrive/2.png' </small>

<small>features = get_image_features(img_to_test) </small>

<small>pred = model.predict(features) </small>

<small>gender = gender_mapping[round(pred[0][0][0])] </small>

<small>age = round(pred[1][0][0]) </small>

<small>plt.title('Predicted Age: {age} Predicted Gender: {gender}') </small>

<small>plt.axis('off') </small>

<small>plt.imshow(np.array(load_img(img_to_test))) </small>

- Sử dụng hàm ‘get_image_features’ để xử lý trước hình ảnh rồi đưa ra dự đốn bằng mơ hình. Sau khi nhận được dự đốn, bạn sẽ hiển thị hình ảnh gốc cùng với độ tuổi và giới tính được dự đốn.

- Giới tính dự đốn được lấy từ ‘gender_mapping’, có lẽ là mapping từ các giá trị số sang nhãn giới tính.

- Độ tuổi dự đốn được làm trịn, giả sử đó là dự đoán hồi quy.

- ‘plt.title’, ‘plt.axis('off')’ và ‘plt.imshow’ được sử dụng để hiển thị hình ảnh gốc với độ tuổi và giới tính được dự đốn.

<small>fromIPython.displayimportdisplay, Javascript, Image </small>

<small>from google.colab.output import eval_js </small>

<small>frombase64importb64decode, b64encode </small>

</div><span class="text_page_counter">Trang 9</span><div class="page_container" data-page="9">

<b><small>7 </small></b>

Import các thư viện cần thiết <small>defjs_to_image(js_reply): </small>

<small> # decode base64 image </small>

<small> image_bytes = b64decode(js_reply.split(',')[1]) # convert bytes to numpy array </small>

<small> jpg_as_np = np.frombuffer(image_bytes, dtype=np.uint8) # decode numpy array into OpenCV BGR image </small>

<small> img = cv2.imdecode(jpg_as_np, flags=1) returnimg </small>

- Decode Base64 Image: Hàm lấy hình ảnh được mã hóa base64 từ đối tượng JavaScript (‘js_reply’), phân tách nó để lấy nội dung được mã hóa base64 thực tế, sau đó giải mã nó bằng ‘b64decode’. Bước này chuyển đổi hình ảnh được mã hóa base64 thành byte.

- Convert Bytes to NumPy Array: Các byte được giải mã sau đó được chuyển đổi thành mảng NumPy bằng cách sử dụng ‘np.frombuffer’.

- Decode NumPy Array into OpenCV BGR Image: Mảng NumPy được giải mã thành hình ảnh OpenCV BGR bằng ‘cv2.imdecode’. Tham số ‘flags=1’ chỉ ra rằng hình ảnh phải được

<small> # convert array into PIL image </small>

<small> bbox_PIL = PIL.Image.fromarray(bbox_array, 'RGBA') iobuf = io.BytesIO() </small>

<small> # format bbox into png for return bbox_PIL.save(iobuf, format='png') # format return string </small>

<small> bbox_bytes = 'data:image/png;base64,{}'.format((str(b64encode(iobuf.getvalue()), 'utf-8'))) returnbbox_bytes </small>

- Convert Array to PIL Image: Hàm chuyển đổi mảng NumPy đầu vào (được giả sử ở định dạng RGBA) thành Hình ảnh PIL với chế độ 'RGBA'.

- Create Binary Stream: Một luồng nhị phân trong bộ nhớ (‘io.BytesIO()’) được tạo. - Save Image to Binary Stream:: Hình ảnh PIL được lưu vào luồng nhị phân ở định dạng

PNG.

</div><span class="text_page_counter">Trang 10</span><div class="page_container" data-page="10">

- Convert to Base64 Byte String: Luồng nhị phân sau đó được chuyển đổi thành chuỗi byte được mã hóa base64.

Kết quả ‘bbox_byte’ có thể được sử dụng để phủ hình chữ nhật trên luồng video bằng cách nhúng nó vào HTML hoặc sử dụng nó trong ứng dụng web.

<small>face_cascade = cv2.CascadeClassifier(cv2.samples.findFile(cv2.data.haarcascades + </small>

<small>'haarcascade_frontalface_default.xml')) </small>

<small>deftake_photo(filename='photo.png', quality=0.8): js = Javascript(''' </small>

<small> async function takePhoto(quality) { </small>

<small> const div = document.createElement('div'); const capture = document.createElement('button'); </small>

<small> // Wait for Capture to be clicked. </small>

<small> await new Promise((resolve) => capture.onclick = resolve); const canvas = document.createElement('canvas'); </small>

Ở bước này, chúng ta cung cấp một chức năng để chụp ảnh từ webcam của người dùng bằng môi trường Google Colab. Hàm này được đặt tên là takePhoto và nhận hai tham số tùy chọn như sau: tên tệp mặc định là 'photo.png' và chất lượng mặc định là 0,8. Chức năng này thiết lập một nút để chụp ảnh, khởi tạo thành phần video để hiển thị nguồn cấp dữ liệu webcam và trả về hình ảnh đã chụp dưới dạng URL dữ liệu ở định dạng JPEG. Để sử dụng hàm này trong Jupyter, có thể gọi nó từ ơ mã sau khi chạy mã được cung cấp.

Thao tác này sẽ hiển thị nút "Chụp" và khi nhấp vào nút này, nó sẽ chụp ảnh từ webcam và trả về URL dữ liệu của hình ảnh. Chúng ta có thể tùy chỉnh tên tệp và thơng số chất lượng nếu cần. Mã này được thiết kế cho mơi trường Google Colab và dựa trên các tính năng dành riêng cho mơi trường đó, chẳng hạn như google.colab.output.setIframeHeight. Nếu sử dụng một môi trường khác, ta cần phải điều chỉnh code.

</div><span class="text_page_counter">Trang 11</span><div class="page_container" data-page="11">

<b><small>9 </small></b>

<small># get photo data </small>

<small> data = eval_js('takePhoto({})'.format(quality)) # get OpenCV format image </small>

<small> img = js_to_image(data) # grayscale img </small>

<small> gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY) print(gray.shape) </small>

<small> # get face bounding box coordinates using Haar Cascade faces = face_cascade.detectMultiScale(gray) </small>

<small> # draw face bounding box on image </small>

Khi chụp ảnh khn mặt và chuyển hình ảnh về thang độ xám xong, phát hiện các khuôn mặt bằng bộ phân loại Haar Cascade, vẽ hình chữ nhật xung quanh các khuôn mặt được phát hiện, sau đó là lưu hình ảnh thu được và trả về kết quả.

<small>try: </small>

<small> filename = take_photo('photo.png') print('Saved to {}'.format(filename)) </small>

<small> # Show the image which was just taken. display(Image(filename)) </small>

<small>exceptExceptionaserr: </small>

<small> # Errors will be thrown if the user does not have a webcam or if they do not # grant the page permission to access it. </small>

<small> print(str(err)) </small>

Ở bước này, máy sẽ hiện thị hình ảnh mà nó vừa chụp được hoặc báo lỗi khi máy tính khơng có webcam hoặc người dùng khơng cấp quyền truy cập để chụp ảnh

.

<small>fromPILimportImage </small>

<small>from keras.preprocessing.image import load_img </small>

Nhập lớp hình ảnh từ thư viện PIL và hàm Load_img từ mô đun keras.preprocessing.image. <small>defget_image_features2(image): </small>

<small> img = load_img(image, grayscale=True) </small>

<small> img = img.resize((128, 128), Image.ANTIALIAS) # Use Image.ANTIALIAS directly in resize img = np.array(img) </small>

<small> img = img.reshape(1, 128, 128, 1) </small>

<small> returnimg</small>

Xác định hàm get_image_features2 để lấy đường dẫn tệp hình ảnh làm đầu vào, tải hình ảnh bằng hàm Load_img của Keras, thực hiện một số quy trình trước khi xử lý hình ảnh và sau đó trả về hình ảnh đã xử lý dưới dạng mảng NumPy. Định hình lại mảng hình ảnh thành (1, 128, 128, 1) và kích thước 128x128 pixel.

<small>img_to_test2 = '/content/photo.png' </small>

<small>features = get_image_features2(img_to_test2) </small>

<small>pred = model.predict(features) </small>

<small>gender = gender_mapping[round(pred[0][0][0])] </small>

</div>

×