| import os |
| |
| os.environ["CUDA_VISIBLE_DEVICES"] = "-1" |
|
|
| from flask import Flask, request, render_template, redirect, url_for, jsonify |
| from werkzeug.utils import secure_filename |
| from PIL import Image |
| import torch |
| import torch.nn as nn |
| import torchvision.transforms as transforms |
| from torchvision.utils import save_image |
| from io import BytesIO |
| import cv2 |
| import numpy as np |
|
|
|
|
| |
| app = Flask(__name__) |
|
|
| |
| device = torch.device("cpu") |
|
|
| |
| class AttentionBlock(nn.Module): |
| def __init__(self, in_channels): |
| super(AttentionBlock, self).__init__() |
| self.query_conv = nn.Conv2d(in_channels, in_channels // 8, kernel_size=1) |
| self.key_conv = nn.Conv2d(in_channels, in_channels // 8, kernel_size=1) |
| self.value_conv = nn.Conv2d(in_channels, in_channels, kernel_size=1) |
| self.gamma = nn.Parameter(torch.zeros(1)) |
|
|
| def forward(self, x): |
| batch_size, C, height, width = x.size() |
| query = self.query_conv(x).view(batch_size, -1, height * width) |
| key = self.key_conv(x).view(batch_size, -1, height * width) |
| value = self.value_conv(x).view(batch_size, -1, height * width) |
|
|
| energy = torch.bmm(query.permute(0, 2, 1), key) |
| attention = torch.softmax(energy, dim=-1) |
|
|
| out = torch.bmm(value, attention.permute(0, 2, 1)) |
| out = out.view(batch_size, C, height, width) |
| out = self.gamma * out + x |
| return out |
|
|
| |
| class Encoder(nn.Module): |
| def __init__(self, input_nc): |
| super(Encoder, self).__init__() |
| self.encoder = nn.Sequential( |
| nn.Conv2d(input_nc, 64, kernel_size=7, stride=1, padding=3), |
| nn.InstanceNorm2d(64), |
| nn.ReLU(inplace=True), |
| nn.Conv2d(64, 128, kernel_size=3, stride=2, padding=1), |
| nn.InstanceNorm2d(128), |
| nn.ReLU(inplace=True), |
| nn.Conv2d(128, 256, kernel_size=3, stride=2, padding=1), |
| nn.InstanceNorm2d(256), |
| nn.ReLU(inplace=True), |
| ) |
|
|
| def forward(self, x): |
| return self.encoder(x) |
|
|
|
|
| class Decoder(nn.Module): |
| def __init__(self, output_nc): |
| super(Decoder, self).__init__() |
| self.decoder = nn.Sequential( |
| nn.ConvTranspose2d(256, 128, kernel_size=3, stride=2, padding=1, output_padding=1), |
| nn.InstanceNorm2d(128), |
| nn.ReLU(inplace=True), |
| nn.ConvTranspose2d(128, 64, kernel_size=3, stride=2, padding=1, output_padding=1), |
| nn.InstanceNorm2d(64), |
| nn.ReLU(inplace=True), |
| nn.Conv2d(64, output_nc, kernel_size=7, stride=1, padding=3), |
| nn.Tanh() |
| ) |
|
|
| def forward(self, x): |
| return self.decoder(x) |
|
|
| |
| class Generator(nn.Module): |
| def __init__(self, input_nc, output_nc): |
| super(Generator, self).__init__() |
| self.encoder = Encoder(input_nc) |
| self.attention = AttentionBlock(256) |
| self.decoder = Decoder(output_nc) |
|
|
| def forward(self, x): |
| x = self.encoder(x) |
| x = self.attention(x) |
| x = self.decoder(x) |
| return x |
|
|
|
|
| |
| |
| G1 = Generator(input_nc=1, output_nc=3).to(device) |
| import os |
| G1.load_state_dict(torch.load(os.path.join("weights", "best_G1.pth"), map_location=device)) |
| G1.to(device) |
| G1.eval() |
|
|
|
|
| |
| transform = transforms.Compose([ |
| transforms.Resize((256, 256)), |
| transforms.ToTensor(), |
| transforms.Normalize((0.5,), (0.5,)), |
| ]) |
|
|
| |
| def sliding_window_colorization(input_image, model, patch_size=64, overlap=32): |
| img_width, img_height = input_image.size |
| patches = [] |
|
|
| |
| for y in range(0, img_height - patch_size + 1, patch_size - overlap): |
| for x in range(0, img_width - patch_size + 1, patch_size - overlap): |
| patch = input_image.crop((x, y, x + patch_size, y + patch_size)) |
| patch = transform(patch).unsqueeze(0).to(device) |
| |
| |
| with torch.no_grad(): |
| colorized_patch = model(patch) |
|
|
| patches.append((x, y, colorized_patch)) |
|
|
| |
| if img_width % patch_size != 0: |
| x = img_width - patch_size |
| for y in range(0, img_height - patch_size + 1, patch_size - overlap): |
| patch = input_image.crop((x, y, x + patch_size, y + patch_size)) |
| patch = transform(patch).unsqueeze(0).to(device) |
| with torch.no_grad(): |
| colorized_patch = model(patch) |
| patches.append((x, y, colorized_patch)) |
|
|
| if img_height % patch_size != 0: |
| y = img_height - patch_size |
| for x in range(0, img_width - patch_size + 1, patch_size - overlap): |
| patch = input_image.crop((x, y, x + patch_size, y + patch_size)) |
| patch = transform(patch).unsqueeze(0).to(device) |
| with torch.no_grad(): |
| colorized_patch = model(patch) |
| patches.append((x, y, colorized_patch)) |
|
|
| |
| output_image = torch.zeros((1, 3, img_height, img_width), device=device) |
| count_map = torch.zeros((1, 3, img_height, img_width), device=device) |
|
|
| for (x, y, colorized_patch) in patches: |
| output_image[:, :, y:y + patch_size, x:x + patch_size] += colorized_patch |
| count_map[:, :, y:y + patch_size, x:x + patch_size] += 1 |
|
|
| output_image /= count_map |
| return output_image |
|
|
| |
| def calculate_greenery_rate(image_path): |
|
|
| |
| image = cv2.imread(image_path) |
| if image is None: |
| raise FileNotFoundError(f"Image not found at path: {image_path}") |
|
|
| |
| hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) |
|
|
| |
| lower_green = np.array([30, 40, 40]) |
| upper_green = np.array([90, 255, 255]) |
|
|
|
|
| |
| green_mask = cv2.inRange(hsv_image, lower_green, upper_green) |
|
|
| |
| green_pixel_count = np.sum(green_mask > 0) |
|
|
| |
| total_pixel_count = image.shape[0] * image.shape[1] |
|
|
| |
| greenery_rate = (green_pixel_count / total_pixel_count) * 100 |
|
|
| return greenery_rate |
|
|
| |
| @app.route('/') |
| def index(): |
| return render_template('index.html') |
|
|
| @app.route('/upload', methods=['POST']) |
| def upload_image(): |
| if 'file' not in request.files: |
| return "No file part" |
| file = request.files['file'] |
| if file.filename == '': |
| return "No selected file" |
| if file: |
| uploaded_image_path = os.path.join("static", "uploaded_image.png") |
| file.save(uploaded_image_path) |
|
|
| |
| image = Image.open(uploaded_image_path).convert("L") |
|
|
| |
| colorized_image = sliding_window_colorization(image, G1, patch_size=256, overlap=32) |
| |
| |
| colorized_image = colorized_image * 0.5 + 0.5 |
| colorized_image_path = os.path.join("static", "colorized_image.png") |
| save_image(colorized_image, colorized_image_path) |
|
|
| |
| greenery_rate = calculate_greenery_rate(colorized_image_path) |
|
|
| return render_template( |
| 'result.html', |
| uploaded_image_url="/static/uploaded_image.png", |
| colorized_image_url="/static/colorized_image.png", |
| greenery_rate=f"{greenery_rate:.2f}%" |
| ) |
|
|
| |
| UPLOAD_FOLDER = 'static/uploads' |
| app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER |
|
|
| @app.route('/greenery', methods=['GET']) |
| def greenery_rate_page(): |
| return render_template('greenery.html') |
|
|
|
|
| @app.route('/greenery-upload', methods=['POST']) |
| def greenery_upload(): |
| if 'file' not in request.files: |
| return redirect(request.url) |
| file = request.files['file'] |
| if file.filename == '': |
| return redirect(request.url) |
| if file: |
| |
| filename = secure_filename(file.filename) |
| filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename) |
| file.save(filepath) |
|
|
| |
| greenery_rate = calculate_greenery_rate(filepath) |
|
|
| |
| uploaded_image_url = url_for('static', filename=f'uploads/{filename}') |
| return render_template('greenery.html', uploaded_image_url=uploaded_image_url, greenery_rate=f"{greenery_rate:.2f}%") |
|
|
| |
| faq_data = [ |
| { |
| "question": "What is SAR?", |
| "keywords": ["sar", "what"], |
| "response": "SAR stands for Synthetic Aperture Radar. It is a type of radar used to create two-dimensional images or three-dimensional reconstructions of objects.", |
| }, |
| { |
| "question": "Advantages of SAR", |
| "keywords": ["advantages", "sar"], |
| "response": "Advantages of SAR include all-weather imaging, ability to penetrate clouds and darkness, and high-resolution imaging over large areas.", |
| }, |
| { |
| "question": "Disadvantages of SAR", |
| "keywords": ["disadvantages", "sar", "cons"], |
| "response": "Disadvantages of SAR include high operational costs, susceptibility to speckle noise, and complexity in data interpretation.", |
| }, |
| { |
| "question": "Applications of SAR", |
| "keywords": ["applications", "sar", "usage"], |
| "response": "Applications of SAR include disaster management, environmental monitoring, urban planning, agriculture, and military surveillance.", |
| }, |
| { |
| "question": "SAR Image Colorization", |
| "keywords": ["sar", "colorization"], |
| "response": "SAR image colorization involves using algorithms or deep learning models to add colors to grayscale SAR images for better visual interpretation.", |
| }, |
| { |
| "question": "Limitations of SAR", |
| "keywords": ["limitations", "sar"], |
| "response": "Limitations of SAR include difficulty in interpretation due to speckle noise and high computational costs for processing.", |
| }, |
| { |
| "question": "Pros and Cons of SAR", |
| "keywords": ["pros", "cons", "sar"], |
| "response": "Pros of SAR include all-weather capability, cloud penetration, and high-resolution imaging. Cons include high costs, noise, and complexity in interpretation.", |
| }, |
| { |
| "question": "Components of a SAR system", |
| "keywords": ["components", "sar", "system"], |
| "response": "A SAR system typically consists of a radar antenna, transmitter, receiver, signal processor, and platform (airborne or satellite-based).", |
| }, |
| { |
| "question": "SAR for disaster management", |
| "keywords": ["sar", "disaster", "management"], |
| "response": "SAR is used in disaster management for monitoring floods, landslides, and earthquakes, providing timely information for relief and recovery operations.", |
| }, |
| ] |
|
|
| @app.route('/chatbot') |
| def chatbot(): |
| return render_template('chatbot.html') |
|
|
| @app.route('/chatbot/ask', methods=['POST']) |
| def chatbot_ask(): |
| user_question = request.json.get('question', '').lower() |
|
|
| |
| best_match = None |
| max_score = 0 |
|
|
| for entry in faq_data: |
| score = sum(keyword in user_question for keyword in entry["keywords"]) |
| if score > max_score: |
| best_match = entry |
| max_score = score |
|
|
| |
| response = best_match["response"] if best_match else "Sorry, I couldn't find an answer to your question." |
| return jsonify({'response': response}) |
|
|
| if __name__ == '__main__': |
| app.run(debug=True) |