Untitled

 avatar
unknown
python
a month ago
15 kB
6
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