Untitled
unknown
python
9 months ago
15 kB
17
Indexable
# Bước 1: Cài đặt các thư viện cần thiết
!pip install tensorflow opencv-python matplotlib scikit-learn tqdm
# Import các thư viện
import os
import cv2
import numpy as np
import matplotlib.pyplot as plt
import random
from tqdm import tqdm
from sklearn.model_selection import train_test_split
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, Activation, Flatten, Conv2D, MaxPooling2D
from tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping, ReduceLROnPlateau
from google.colab import drive, files
# Bước 2: Kết nối với Google Drive để lưu trữ dữ liệu và mô hình
drive.mount('/content/drive')
# Tạo thư mục để lưu trữ dữ liệu và mô hình
!mkdir -p /content/drive/MyDrive/VietnamCurrencyDetection/data
!mkdir -p /content/drive/MyDrive/VietnamCurrencyDetection/models
# Bước 3: Tải lên dữ liệu (nếu chưa có trên Drive)
# Đường dẫn đến thư mục dữ liệu
DATA_DIR = "/content/drive/MyDrive/VietnamCurrencyDetection/data"
REAL_DIR = os.path.join(DATA_DIR, "real")
FAKE_DIR = os.path.join(DATA_DIR, "fake")
# Kiểm tra xem thư mục dữ liệu đã tồn tại chưa
if not os.path.exists(REAL_DIR) or not os.path.exists(FAKE_DIR):
print("Thư mục dữ liệu chưa tồn tại. Vui lòng tải lên dữ liệu.")
# Tạo thư mục nếu chưa tồn tại
!mkdir -p {REAL_DIR}
!mkdir -p {FAKE_DIR}
# Tải lên dữ liệu
print("Tải lên ảnh tiền thật vào thư mục:", REAL_DIR)
print("Tải lên ảnh tiền giả vào thư mục:", FAKE_DIR)
else:
print("Đã tìm thấy thư mục dữ liệu.")
print("Số lượng ảnh tiền thật:", len(os.listdir(REAL_DIR)))
print("Số lượng ảnh tiền giả:", len(os.listdir(FAKE_DIR)))
# Bước 4: Định nghĩa các hàm tiền xử lý dữ liệu
IMG_SIZE = 224 # Kích thước ảnh đầu vào cho mô hình
def process_image(img):
"""
Xử lý ảnh
Args:
img: Ảnh đầu vào
Returns:
processed_img: Ảnh đã xử lý
"""
try:
# 1. Làm mờ để giảm nhiễu
blur = cv2.medianBlur(img, 5)
# 2. Phát hiện cạnh để tìm viền của tờ tiền
high_thresh, thresh_im = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
low_thresh = 0.5 * high_thresh
edge_img = cv2.Canny(blur, low_thresh, high_thresh)
# 3. Tìm và cắt theo viền tờ tiền
pts = np.argwhere(edge_img > 0)
if len(pts) > 0:
y1, x1 = pts.min(axis=0)
y2, x2 = pts.max(axis=0)
cropped = img[y1:y2, x1:x2]
else:
cropped = img
# 4. Thay đổi kích thước ảnh
resized = cv2.resize(cropped, (IMG_SIZE, IMG_SIZE))
return resized
except Exception as e:
print(f"Lỗi khi xử lý ảnh: {e}")
# Trả về ảnh gốc đã resize nếu có lỗi
return cv2.resize(img, (IMG_SIZE, IMG_SIZE))
def augment_image(img):
"""
Tăng cường dữ liệu bằng cách tạo ra các biến thể của ảnh
Args:
img: Ảnh đầu vào
Returns:
augmented_images: Danh sách các ảnh đã tăng cường
"""
augmented_images = []
try:
# 1. Xoay ảnh
for angle in [90, 180, 270]:
rows, cols = img.shape
M = cv2.getRotationMatrix2D((cols/2, rows/2), angle, 1)
rotated = cv2.warpAffine(img, M, (cols, rows))
augmented_images.append(rotated)
# 2. Lật ảnh
flipped = cv2.flip(img, 1) # Lật ngang
augmented_images.append(flipped)
# 3. Thêm nhiễu muối tiêu
s_vs_p = 0.5
amount = 0.02
noisy = np.copy(img)
# Muối (điểm trắng)
num_salt = np.ceil(amount * img.size * s_vs_p)
coords = [np.random.randint(0, i - 1, int(num_salt)) for i in img.shape]
noisy[tuple(coords)] = 255
# Tiêu (điểm đen)
num_pepper = np.ceil(amount * img.size * (1. - s_vs_p))
coords = [np.random.randint(0, i - 1, int(num_pepper)) for i in img.shape]
noisy[tuple(coords)] = 0
augmented_images.append(noisy)
except Exception as e:
print(f"Lỗi khi tăng cường ảnh: {e}")
return augmented_images
def create_training_data(real_dir, fake_dir):
"""
Tạo dữ liệu huấn luyện từ thư mục chứa ảnh tiền thật và giả
Args:
real_dir: Đường dẫn đến thư mục chứa ảnh tiền thật
fake_dir: Đường dẫn đến thư mục chứa ảnh tiền giả
Returns:
training_data: Dữ liệu huấn luyện
"""
training_data = []
# Xử lý ảnh tiền thật
print("Đang xử lý ảnh tiền thật...")
for img_file in tqdm(os.listdir(real_dir)):
try:
img_path = os.path.join(real_dir, img_file)
# Đọc ảnh dưới dạng grayscale
img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)
if img is None:
print(f"Không thể đọc ảnh: {img_path}")
continue
# Xử lý ảnh
processed_img = process_image(img)
# Thêm vào dữ liệu huấn luyện với nhãn 1 (thật)
training_data.append([processed_img, 1])
# Tăng cường dữ liệu (Data Augmentation)
augmented_images = augment_image(processed_img)
for aug_img in augmented_images:
training_data.append([aug_img, 1])
except Exception as e:
print(f"Lỗi khi xử lý ảnh {img_file}: {e}")
# Xử lý ảnh tiền giả
print("Đang xử lý ảnh tiền giả...")
for img_file in tqdm(os.listdir(fake_dir)):
try:
img_path = os.path.join(fake_dir, img_file)
# Đọc ảnh dưới dạng grayscale
img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)
if img is None:
print(f"Không thể đọc ảnh: {img_path}")
continue
# Xử lý ảnh
processed_img = process_image(img)
# Thêm vào dữ liệu huấn luyện với nhãn 0 (giả)
training_data.append([processed_img, 0])
# Tăng cường dữ liệu (Data Augmentation)
augmented_images = augment_image(processed_img)
for aug_img in augmented_images:
training_data.append([aug_img, 0])
except Exception as e:
print(f"Lỗi khi xử lý ảnh {img_file}: {e}")
# Xáo trộn dữ liệu
random.shuffle(training_data)
return training_data
def prepare_data_for_training(training_data):
"""Chuẩn bị dữ liệu cho việc huấn luyện"""
X = [] # features
y = [] # labels
for features, label in training_data:
X.append(features)
y.append(label)
# Reshape và chuẩn hóa dữ liệu
X = np.array(X).reshape(-1, IMG_SIZE, IMG_SIZE, 1)
X = X / 255.0 # Chuẩn hóa giá trị pixel về khoảng [0, 1]
y = np.array(y)
return X, y
# Bước 5: Định nghĩa mô hình CNN
def create_model(input_shape):
"""
Tạo mô hình CNN để phân loại tiền thật/giả
Args:
input_shape: Kích thước đầu vào của mô hình
Returns:
model: Mô hình CNN
"""
model = Sequential()
# Block 1
model.add(Conv2D(32, (3, 3), padding='same', input_shape=input_shape))
model.add(Activation('relu'))
model.add(Conv2D(32, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
# Block 2
model.add(Conv2D(64, (3, 3), padding='same'))
model.add(Activation('relu'))
model.add(Conv2D(64, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
# Block 3
model.add(Conv2D(128, (3, 3), padding='same'))
model.add(Activation('relu'))
model.add(Conv2D(128, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
# Fully connected layers
model.add(Flatten())
model.add(Dense(512))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(1)) # 1 node đầu ra cho binary classification
model.add(Activation('sigmoid'))
# Compile model
model.compile(
loss='binary_crossentropy',
optimizer='adam',
metrics=['accuracy']
)
return model
def train_model(X_train, y_train, X_val, y_val, batch_size=32, epochs=50, model_path='model.h5'):
"""
Huấn luyện mô hình
Args:
X_train, y_train: Dữ liệu huấn luyện
X_val, y_val: Dữ liệu validation
batch_size: Kích thước batch
epochs: Số epoch
model_path: Đường dẫn để lưu mô hình
Returns:
model: Mô hình đã huấn luyện
history: Lịch sử huấn luyện
"""
# Tạo mô hình
model = create_model(X_train.shape[1:])
# Callbacks
checkpoint = ModelCheckpoint(
model_path,
monitor='val_accuracy',
save_best_only=True,
mode='max',
verbose=1
)
early_stopping = EarlyStopping(
monitor='val_loss',
patience=10,
verbose=1,
restore_best_weights=True
)
reduce_lr = ReduceLROnPlateau(
monitor='val_loss',
factor=0.2,
patience=5,
min_lr=1e-6,
verbose=1
)
# Huấn luyện mô hình
history = model.fit(
X_train, y_train,
batch_size=batch_size,
epochs=epochs,
validation_data=(X_val, y_val),
callbacks=[checkpoint, early_stopping, reduce_lr],
verbose=1
)
return model, history
def plot_training_history(history):
"""Vẽ đồ thị lịch sử huấn luyện"""
# Accuracy
plt.figure(figsize=(12, 4))
plt.subplot(1, 2, 1)
plt.plot(history.history['accuracy'])
plt.plot(history.history['val_accuracy'])
plt.title('Model Accuracy')
plt.ylabel('Accuracy')
plt.xlabel('Epoch')
plt.legend(['Train', 'Validation'], loc='upper left')
# Loss
plt.subplot(1, 2, 2)
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('Model Loss')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend(['Train', 'Validation'], loc='upper left')
plt.tight_layout()
plt.savefig('/content/drive/MyDrive/VietnamCurrencyDetection/models/training_history.png')
plt.show()
# Bước 6: Dự đoán ảnh mới
def predict_image(model, image_path):
"""
Dự đoán ảnh
Args:
model: Mô hình đã huấn luyện
image_path: Đường dẫn đến ảnh
Returns:
prediction: Kết quả dự đoán (0-1)
processed_img: Ảnh đã xử lý
"""
try:
# Đọc ảnh
img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
if img is None:
raise ValueError(f"Không thể đọc ảnh: {image_path}")
# Xử lý ảnh
processed_img = process_image(img)
# Chuẩn hóa và reshape
normalized = processed_img / 255.0
input_img = np.array(normalized).reshape(-1, IMG_SIZE, IMG_SIZE, 1)
# Dự đoán
prediction = model.predict(input_img)[0][0]
return prediction, processed_img
except Exception as e:
print(f"Lỗi khi dự đoán ảnh: {e}")
return None, None
def display_prediction(image_path, prediction, processed_img):
"""Hiển thị kết quả dự đoán"""
if prediction is None or processed_img is None:
print("Không thể hiển thị kết quả dự đoán do lỗi xử lý ảnh.")
return
plt.figure(figsize=(10, 5))
# Hiển thị ảnh gốc
plt.subplot(1, 2, 1)
original_img = cv2.imread(image_path)
original_img = cv2.cvtColor(original_img, cv2.COLOR_BGR2RGB)
plt.imshow(original_img)
plt.title('Ảnh gốc')
plt.axis('off')
# Hiển thị ảnh đã xử lý
plt.subplot(1, 2, 2)
plt.imshow(processed_img, cmap='gray')
# Hiển thị kết quả dự đoán
if prediction >= 0.5:
result = f"THẬT ({prediction:.4f})"
color = 'green'
else:
result = f"GIẢ ({1-prediction:.4f})"
color = 'red'
plt.title(f'Kết quả: {result}', color=color)
plt.axis('off')
plt.tight_layout()
plt.show()
# Bước 7: Thực hiện huấn luyện
# Tạo dữ liệu huấn luyện
print("Bắt đầu tạo dữ liệu huấn luyện...")
training_data = create_training_data(REAL_DIR, FAKE_DIR)
print(f"Đã tạo {len(training_data)} mẫu dữ liệu.")
# Chuẩn bị dữ liệu cho việc huấn luyện
X, y = prepare_data_for_training(training_data)
print(f"Kích thước X: {X.shape}")
print(f"Kích thước y: {y.shape}")
# Chia dữ liệu thành tập huấn luyện và tập validation
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=42)
print(f"Kích thước X_train: {X_train.shape}")
print(f"Kích thước X_val: {X_val.shape}")
# Huấn luyện mô hình
print("Bắt đầu huấn luyện mô hình...")
model_path = '/content/drive/MyDrive/VietnamCurrencyDetection/models/vietnam_currency_model.h5'
model, history = train_model(X_train, y_train, X_val, y_val, batch_size=32, epochs=50, model_path=model_path)
# Vẽ đồ thị lịch sử huấn luyện
plot_training_history(history)
# Đánh giá mô hình trên tập validation
score = model.evaluate(X_val, y_val, verbose=0)
print(f"Validation Loss: {score[0]}")
print(f"Validation Accuracy: {score[1]}")
print(f"Đã lưu mô hình vào {model_path}")
# Bước 8: Kiểm tra mô hình với ảnh mới
# Tải lên ảnh để kiểm tra
print("Tải lên ảnh để kiểm tra mô hình:")
uploaded = files.upload()
for filename in uploaded.keys():
# Dự đoán
prediction, processed_img = predict_image(model, filename)
# Hiển thị kết quả
display_prediction(filename, prediction, processed_img)
# In kết quả
if prediction is not None:
if prediction >= 0.5:
print(f"Tờ tiền này là THẬT với độ tin cậy {prediction:.4f}")
else:
print(f"Tờ tiền này là GIẢ với độ tin cậy {1-prediction:.4f}")Editor is loading...
Leave a Comment