Công cụ filter giống với flask P2 Chúng ta có thể thêm nhiều phép biến đổi (transformation) và bộ lọc (filter) để tăng khả năng xử lý hình ảnh. Albumentations hỗ trợ nhiều loại phép biến đổi và bộ lọc như Blur, Sharpen, BrightnessContrast, và GaussianNoise. Chúng ta sẽ thêm các tùy chọn mới cho phép người dùng áp dụng nhiều biến đổi cùng lúc.
Dưới đây là các bước để cập nhật:
Thêm các phép biến đổi và bộ lọc như:
Cập nhật giao diện để hiển thị thêm các tùy chọn này và điều chỉnh các tham số liên quan.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Image Transformations</title> <style> .container { max-width: 800px; margin: 0 auto; text-align: center; } img { margin-top: 20px; border: 2px solid #ddd; } .params { margin: 20px 0; } label { margin-right: 10px; } input[type="range"] { width: 200px; } button { margin-top: 10px; padding: 10px 20px; cursor: pointer; } .output { font-weight: bold; margin-left: 10px; } </style> <script> // Hàm debounce để hạn chế gọi API liên tục function debounce(func, wait) { let timeout; return function(...args) { const context = this; clearTimeout(timeout); timeout = setTimeout(() => func.apply(context, args), wait); }; } // Hàm để upload ảnh function uploadImage() { const fileInput = document.getElementById('fileInput'); const formData = new FormData(); formData.append('file', fileInput.files[0]); fetch('/api/upload', { method: 'POST', body: formData }) .then(response => response.json()) .then(data => { if (data.image_path) { // Hiển thị ảnh sau khi upload thành công document.getElementById('image').src = data.image_path; document.getElementById('imagePath').value = data.image_path; } else { console.error(data.error); } }) .catch(error => console.error('Error:', error)); } // Hàm để áp dụng transform ảnh với debounce const applyTransform = debounce(function() { const imagePath = document.getElementById('imagePath').value; const p = parseFloat(document.getElementById('probability').value); const limit = parseInt(document.getElementById('limit').value); const blur = parseInt(document.getElementById('blur').value); const sharpen = parseInt(document.getElementById('sharpen').value); const brightness = parseFloat(document.getElementById('brightness').value); const contrast = parseFloat(document.getElementById('contrast').value); const noise = parseInt(document.getElementById('noise').value); const transformType = document.querySelector('input[name="transform"]:checked').value; if (!imagePath) { console.error('Image path is not set'); return; } fetch('/api/transform', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ transform: transformType, image_path: imagePath, params: { "p": p, "limit": limit, "blur": blur, "sharpen": sharpen, "brightness": brightness, "contrast": contrast, "noise": noise } }) }) .then(response => response.json()) .then(data => { if (data.processed_image_path) { // Thêm chuỗi ngẫu nhiên vào URL để tránh cache const randomParam = `?t=${new Date().getTime()}`; // Hiển thị ảnh sau khi biến đổi document.getElementById('image').src = data.processed_image_path + randomParam; } else { console.error(data.error); } }) .catch(error => console.error('Error:', error)); }, 500); // Debounce time set to 500ms // Cập nhật giá trị hiển thị khi thay đổi range function updateValue(id, value) { document.getElementById(id).innerText = value; applyTransform(); // Gọi lại hàm debounce khi giá trị thay đổi } </script> </head> <body> <div class="container"> <h1>Upload and Transform Image</h1> <!-- Form để tải lên ảnh --> <input type="file" id="fileInput" accept="image/*"> <button onclick="uploadImage()">Upload</button> <!-- Ẩn đường dẫn ảnh --> <input type="hidden" id="imagePath" value=""> <!-- Các tham số cho biến đổi --> <div class="params"> <label for="probability">Probability (p):</label> <input type="range" id="probability" min="0" max="1" step="0.1" value="1.0" oninput="updateValue('probabilityValue', this.value)"> <span id="probabilityValue" class="output">1.0</span> </div> <div class="params"> <label for="limit">Limit (Degrees):</label> <input type="range" id="limit" min="0" max="360" step="1" value="90" oninput="updateValue('limitValue', this.value)"> <span id="limitValue" class="output">90</span> </div> <div class="params"> <label for="blur">Blur:</label> <input type="range" id="blur" min="0" max="10" step="1" value="0" oninput="updateValue('blurValue', this.value)"> <span id="blurValue" class="output">0</span> </div> <div class="params"> <label for="sharpen">Sharpen:</label> <input type="range" id="sharpen" min="0" max="10" step="1" value="0" oninput="updateValue('sharpenValue', this.value)"> <span id="sharpenValue" class="output">0</span> </div> <div class="params"> <label for="brightness">Brightness:</label> <input type="range" id="brightness" min="0" max="2" step="0.1" value="1.0" oninput="updateValue('brightnessValue', this.value)"> <span id="brightnessValue" class="output">1.0</span> </div> <div class="params"> <label for="contrast">Contrast:</label> <input type="range" id="contrast" min="0" max="2" step="0.1" value="1.0" oninput="updateValue('contrastValue', this.value)"> <span id="contrastValue" class="output">1.0</span> </div> <div class="params"> <label for="noise">Gaussian Noise:</label> <input type="range" id="noise" min="0" max="100" step="5" value="0" oninput="updateValue('noiseValue', this.value)"> <span id="noiseValue" class="output">0</span> </div> <!-- Các nút transform với radio buttons để chọn --> <div class="params"> <label for="transform">Transformation:</label> <label><input type="radio" name="transform" value="horizontal_flip" checked> Horizontal Flip</label> <label><input type="radio" name="transform" value="vertical_flip"> Vertical Flip</label> <label><input type="radio" name="transform" value="rotate_90"> Rotate</label> </div> <!-- Hiển thị ảnh --> <div> <img id="image" src="https://placehold.co/600x400" alt="Image will appear here" style="max-width: 100%; height: auto;"> </div> </div> </body> </html>
Thêm các phép biến đổi mới:
Cập nhật API:
Hiển thị giá trị thanh trượt:
Với những thay đổi này, bạn đã mở rộng khả năng chỉnh sửa hình ảnh với nhiều loại biến đổi và bộ lọc đa dạng.
Để cập nhật hàm transform_image sao cho nó phù hợp với giao diện mới, ta cần xử lý các phép biến đổi và bộ lọc bổ sung từ các tham số trong payload. Dưới đây là cách điều chỉnh hàm này để áp dụng các phép biến đổi và bộ lọc được người dùng chọn:
Dưới đây là mã code cập nhật cho hàm transform_image:
from flask import request, jsonify import os import cv2 import matplotlib.pyplot as plt import albumentations as A import numpy as np @main.route('/api/transform', methods=['POST']) def transform_image(): # Lấy toàn bộ payload từ yêu cầu data = request.json # Xử lý các thông tin cơ bản transform_type = data.get('transform') image_path = data.get('image_path') params = data.get('params', {}) if not image_path or not os.path.exists(image_path): return jsonify({"error": "Invalid image path"}), 400 # Lấy giá trị từ params p = params.get('p', 1.0) limit = params.get('limit', 90) blur = params.get('blur', 0) sharpen = params.get('sharpen', 0) brightness = params.get('brightness', 1.0) contrast = params.get('contrast', 1.0) noise = params.get('noise', 0) # Đọc và xử lý ảnh image = cv2.imread(image_path) image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) # Tạo danh sách các phép biến đổi transforms = [] if transform_type == 'horizontal_flip': transforms.append(A.HorizontalFlip(p=p)) elif transform_type == 'vertical_flip': transforms.append(A.VerticalFlip(p=p)) elif transform_type == 'rotate_90': transforms.append(A.Rotate(limit=(limit, limit), p=p)) # Thêm các bộ lọc và biến đổi bổ sung if blur > 0: transforms.append(A.GaussianBlur(blur_limit=blur, p=1.0)) if sharpen > 0: transforms.append(A.Sharpen(p=1.0)) if brightness != 1.0 or contrast != 1.0: transforms.append(A.RandomBrightnessContrast(brightness_limit=(brightness-1, brightness-1), contrast_limit=(contrast-1, contrast-1), p=1.0)) if noise > 0: transforms.append(A.GaussNoise(var_limit=(noise, noise), p=1.0)) # Áp dụng tất cả các phép biến đổi if transforms: transform = A.Compose(transforms) augmented = transform(image=image) image = augmented['image'] # Lưu ảnh đã xử lý vào thư mục processed_images processed_image_path = os.path.join(PROCESSED_FOLDER, 'processed_image.jpg') plt.imsave(processed_image_path, image) return jsonify({"message": "Image transformed successfully", "processed_image_path": processed_image_path}), 200
Thay đổi cách xử lý biến đổi:
Thêm các bộ lọc:
Áp dụng các biến đổi:
Với những thay đổi này, hàm transform_image giờ có thể xử lý nhiều phép biến đổi và bộ lọc khác nhau dựa trên các tham số từ payload.
Lỗi này xảy ra vì GaussianBlur trong Albumentations yêu cầu giá trị của blur_limit phải là số lẻ hoặc bằng 0. Khi bạn chỉ định một giá trị như (0, 8), có thể một số giá trị trong khoảng đó không phải là số lẻ, hoặc giá trị là 0 mà vẫn không hợp lệ trong một số trường hợp.
Để khắc phục lỗi này, bạn cần đảm bảo rằng giá trị blur_limit luôn là số lẻ hoặc 0. Dưới đây là cách chỉnh sửa để đảm bảo điều đó:
Chuyển giá trị blur thành số lẻ:
Thay đổi mã nguồn để xử lý các giá trị của blur_limit đúng cách.
Dưới đây là mã nguồn cập nhật cho hàm transform_image:
from flask import request, jsonify import os import cv2 import matplotlib.pyplot as plt import albumentations as A import numpy as np @main.route('/api/transform', methods=['POST']) def transform_image(): # Lấy toàn bộ payload từ yêu cầu data = request.json # Xử lý các thông tin cơ bản transform_type = data.get('transform') image_path = data.get('image_path') params = data.get('params', {}) if not image_path or not os.path.exists(image_path): return jsonify({"error": "Invalid image path"}), 400 # Lấy giá trị từ params p = params.get('p', 1.0) limit = params.get('limit', 90) blur = params.get('blur', 0) sharpen = params.get('sharpen', 0) brightness = params.get('brightness', 1.0) contrast = params.get('contrast', 1.0) noise = params.get('noise', 0) # Đọc và xử lý ảnh image = cv2.imread(image_path) image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) # Tạo danh sách các phép biến đổi transforms = [] if transform_type == 'horizontal_flip': transforms.append(A.HorizontalFlip(p=p)) elif transform_type == 'vertical_flip': transforms.append(A.VerticalFlip(p=p)) elif transform_type == 'rotate_90': transforms.append(A.Rotate(limit=(limit, limit), p=p)) # Thêm các bộ lọc và biến đổi bổ sung if blur > 0: # Đảm bảo blur_limit luôn là số lẻ hoặc 0 blur_limit = (blur, blur) if blur % 2 == 1 else (blur - 1, blur - 1) transforms.append(A.GaussianBlur(blur_limit=blur_limit, p=1.0)) if sharpen > 0: transforms.append(A.Sharpen(p=1.0)) if brightness != 1.0 or contrast != 1.0: transforms.append(A.RandomBrightnessContrast(brightness_limit=(brightness-1, brightness-1), contrast_limit=(contrast-1, contrast-1), p=1.0)) if noise > 0: transforms.append(A.GaussNoise(var_limit=(noise, noise), p=1.0)) # Áp dụng tất cả các phép biến đổi if transforms: transform = A.Compose(transforms) augmented = transform(image=image) image = augmented['image'] # Lưu ảnh đã xử lý vào thư mục processed_images processed_image_path = os.path.join(PROCESSED_FOLDER, 'processed_image.jpg') plt.imsave(processed_image_path, image) return jsonify({"message": "Image transformed successfully", "processed_image_path": processed_image_path}), 200
Chỉnh sửa blur_limit:
Áp dụng các biến đổi và bộ lọc:
Với thay đổi này, bạn sẽ tránh được lỗi liên quan đến giá trị không hợp lệ của blur_limit.
Leave A Comment