Professional Documents
Culture Documents
import numpy as np
import random
import os
import warnings
warnings.filterwarnings('ignore')
Sau đó, kết nối với GG Drive và giải nén dữ liệu tệp zip UTKFace.zip
from google.colab import drive
drive.mount('/content/drive')
!unzip '/content/drive/MyDrive/UTKFace.zip'
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
1
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ự.
BASE_DIR = '/content/UTKFace'
age_labels = []
gender_labels = []
image_paths = []
image_filenames = os.listdir(BASE_DIR)
random.shuffle(image_filenames)
Đ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:
for image in tqdm(image_filenames):
img_components = image.split('_')
age_label = int(img_components[0])
gender_label = int(img_components[1])
age_labels.append(age_label)
gender_labels.append(gender_label)
image_paths.append(image_path)
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
print(f'Number of age_labels: {len(age_labels)}, Number of gender_labels: {len(gender_labels)}, Number of
image_paths: {len(image_paths)}')
1: 'Female',
0: 'Male'
Chuyển đổi từng danh sách đã tạo thành từng cột riêng để khung dữ liệu ngắn gọn và đẹp mắt
hơn
import pandas as pd
df = pd.DataFrame()
df.head(5)
2
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.
from PIL import Image
age = df['age'][rand_index]
gender = df['gender'][rand_index]
IMG = Image.open(df['image_path'][rand_index])
plt.axis('off')
plt.imshow(IMG)
Dưới đây là code tạo biểu đồ phân phối tuổi và giới tính trong tệp dữ liệu
sns.distplot(df['age'])
sns.countplot(df['gender'])
Sau đó, sẽ cho xuất hiện một loạt các hình ảnh trong tệp với các thông tin như độ tuổi và giới
tính tương ứng
for index, sample, age, gender in samples.itertuples():
plt.subplot(4, 4, index + 1)
img = load_img(sample)
img = np.array(img)
plt.axis('off')
plt.imshow(img)
def extract_image_features(images):
features = list()
Đâ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ý
for image in tqdm(images):
img = load_img(image, grayscale=True)
img = img.resize((128, 128), Image.ANTIALIAS)
img = np.array(img)
features.append(img)
features = np.array(features)
features = features.reshape(len(features), 128, 128, 1)
return features
3
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’
X = extract_image_features(df['image_path'])
X.shape
X = X / 255.0
Gán kết quả trả về chứa các đặc trưng của tất cả hình ảnh
y_gender = np.array(df['gender'])
y_age = np.array(df['age'])
Đ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 toán.
input_shape = (128, 128, 1)
Dòng code này định nghĩa biến input_shape là một tuple có giá trị là (128, 128, 1)
inputs = Input((input_shape))
conv_1 = Conv2D(32, kernel_size=(3, 3), activation='relu')(inputs)
max_1 = MaxPooling2D(pool_size=(2, 2))(conv_1)
conv_2 = Conv2D(64, kernel_size=(3, 3), activation='relu')(max_1)
max_2 = MaxPooling2D(pool_size=(2, 2))(conv_2)
conv_3 = Conv2D(128, kernel_size=(3, 3), activation='relu')(max_2)
max_3 = MaxPooling2D(pool_size=(2, 2))(conv_3)
conv_4 = Conv2D(256, kernel_size=(3, 3), activation='relu')(max_3)
max_4 = MaxPooling2D(pool_size=(2, 2))(conv_4)
flatten = Flatten()(max_4)
Đị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.
dense_1 = Dense(256, activation='relu')(flatten)
dense_2 = Dense(256, activation='relu')(flatten)
dropout_1 = Dropout(0.3)(dense_1)
dropout_2 = Dropout(0.3)(dense_2)
output_1 = Dense(1, activation='sigmoid', name='gender_out')(dropout_1)
output_2 = Dense(1, activation='relu', name='age_out')(dropout_2)
model = Model(inputs=[inputs], outputs=[output_1, output_2])
model.compile(loss=['binary_crossentropy', 'mae'],
optimizer='adam', metrics=['accuracy'])
Đ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ự đoán giới tính và tuổi từ ảnh đầu vào.
from tensorflow.keras.utils import plot_model
plot_model(model)
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.
history = model.fit(x=X, y=[y_gender, y_age],
batch_size=32, epochs=50, validation_split=0.2)
Tiến hành training
4
# plot results for gender
acc = history.history['gender_out_accuracy']
val_acc = history.history['val_gender_out_accuracy']
epochs = range(len(acc))
plt.plot(epochs, acc, 'b', label='Training Accuracy')
plt.plot(epochs, val_acc, 'r', label='Validation Accuracy')
plt.title('Accuracy Graph')
plt.legend()
plt.figure()
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.
loss = history.history['gender_out_loss']
val_loss = history.history['val_gender_out_loss']
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ự đoá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
plt.plot(epochs, loss, 'b', label='Training Loss')
plt.plot(epochs, val_loss, 'r', label='Validation Loss')
plt.title('Loss Graph')
plt.legend()
plt.show()
- '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 toá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.
# plot results for age
loss = history.history['age_out_loss']
val_loss = history.history['val_age_out_loss']
epochs = range(len(loss))
- 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.
plt.plot(epochs, loss, 'b', label='Training Loss')
plt.plot(epochs, val_loss, 'r', label='Validation Loss')
plt.title('Loss Graph')
5
plt.legend()
plt.show()
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.
def get_image_features(image):
img = load_img(image, grayscale=True)
img = img.resize((128, 128), Image.ANTIALIAS)
img = np.array(img)
img = img.reshape(1, 128, 128, 1)
img = img / 255.0
return img
- 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
img_to_test = '/content/drive/MyDrive/2.png'
features = get_image_features(img_to_test)
pred = model.predict(features)
gender = gender_mapping[round(pred[0][0][0])]
age = round(pred[1][0][0])
plt.title(f'Predicted Age: {age} Predicted Gender: {gender}')
plt.axis('off')
plt.imshow(np.array(load_img(img_to_test)))
- Sử dụng hàm ‘get_image_features’ để xử lý trước hình ảnh rồi đưa ra dự đoán bằng mô
hình. Sau khi nhận được dự đoá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ự đoán.
- Giới tính dự đoá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ự đoá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ự đoán.
from IPython.display import display, Javascript, Image
from google.colab.output import eval_js
from base64 import b64decode, b64encode
import cv2
import numpy as np
import PIL
import io
import html
import time
6
Import các thư viện cần thiết
def js_to_image(js_reply):
"""
Params:
js_reply: JavaScript object containing image from webcam
Returns:
img: OpenCV BGR image
"""
# decode base64 image
image_bytes = b64decode(js_reply.split(',')[1])
# convert bytes to numpy array
jpg_as_np = np.frombuffer(image_bytes, dtype=np.uint8)
# decode numpy array into OpenCV BGR image
img = cv2.imdecode(jpg_as_np, flags=1)
return img
- 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
đọc ở dạng màu.
Kết quả là hình ảnh OpenCV BGR có thể được xử lý hoặc hiển thị thêm bằng các hàm
OpenCV.
# function to convert OpenCV Rectangle bounding box image into base64 byte string to be overlayed on video
stream
def bbox_to_bytes(bbox_array):
"""
Params:
bbox_array: Numpy array (pixels) containing rectangle to overlay on video stream.
Returns:
bytes: Base64 image byte string
"""
# convert array into PIL image
bbox_PIL = PIL.Image.fromarray(bbox_array, 'RGBA')
iobuf = io.BytesIO()
# format bbox into png for return
bbox_PIL.save(iobuf, format='png')
# format return string
bbox_bytes = 'data:image/png;base64,{}'.format((str(b64encode(iobuf.getvalue()), 'utf-8')))
return bbox_bytes
- 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.
7
- 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.
face_cascade = cv2.CascadeClassifier(cv2.samples.findFile(cv2.data.haarcascades +
'haarcascade_frontalface_default.xml'))
def take_photo(filename='photo.png', quality=0.8):
js = Javascript('''
async function takePhoto(quality) {
const div = document.createElement('div');
const capture = document.createElement('button');
capture.textContent = 'Capture';
div.appendChild(capture);
const video = document.createElement('video');
video.style.display = 'block';
const stream = await navigator.mediaDevices.getUserMedia({video: true});
document.body.appendChild(div);
div.appendChild(video);
video.srcObject = stream;
await video.play();
10