RafidMehda's picture
Update app.py
ae8ca5c verified
import streamlit as st
import os
import requests
import numpy as np
from PIL import Image, ImageDraw
import io
import random
##############################################################################
# 1. Attempt to import YOLOv10 from the ultralytics package (THU-MIG/yolov10)
##############################################################################
try:
from ultralytics import YOLOv10
except ImportError:
st.error("Could not import YOLOv10. Please confirm THU-MIG/yolov10 installation in requirements.txt.")
st.stop()
##############################################################################
# 2. Chaotic Logistic Map Encryption Functions
##############################################################################
def logistic_map(r, x):
return r * x * (1 - x)
def generate_key(seed, n):
key = []
x = seed
for _ in range(n):
x = logistic_map(3.9, x)
key.append(int(x * 255) % 256)
return np.array(key, dtype=np.uint8)
def shuffle_pixels(img_array, seed):
h, w, c = img_array.shape
num_pixels = h * w
flattened = img_array.reshape(-1, c)
indices = np.arange(num_pixels)
random.seed(seed)
random.shuffle(indices)
shuffled = flattened[indices]
return shuffled.reshape(h, w, c), indices
def encrypt_image(img_array, seed):
"""
Encrypt the given image array using a two-layer XOR + pixel shuffling approach.
"""
h, w, c = img_array.shape
flat_image = img_array.flatten()
# First chaotic key
chaotic_key_1 = generate_key(seed, len(flat_image))
# XOR-based encryption (first layer)
encrypted_flat_1 = [p ^ chaotic_key_1[i] for i, p in enumerate(flat_image)]
encrypted_array_1 = np.array(encrypted_flat_1, dtype=np.uint8).reshape(h, w, c)
# Shuffle
shuffled_array, _ = shuffle_pixels(encrypted_array_1, seed)
# Second chaotic key
chaotic_key_2 = generate_key(seed * 1.1, len(flat_image))
shuffled_flat = shuffled_array.flatten()
encrypted_flat_2 = [p ^ chaotic_key_2[i] for i, p in enumerate(shuffled_flat)]
doubly_encrypted_array = np.array(encrypted_flat_2, dtype=np.uint8).reshape(h, w, c)
return doubly_encrypted_array
##############################################################################
# 3. YOLOv10 License Plate Detection
##############################################################################
@st.cache_data(show_spinner=False)
def load_model(weights_path: str):
"""
Loads the YOLOv10 model from local .pt weights (Ultralytics style).
"""
model = YOLOv10(weights_path) # e.g., 'best.pt'
return model
def detect_license_plates(model, pil_image):
"""
Runs YOLOv10 detection on the PIL image using ultralytics-style output:
results -> list of ultralytics.engine.results.Results
each Results has .boxes, .masks, .names, etc.
We'll handle only the first Results object (single image).
"""
np_image = np.array(pil_image)
results = model.predict(np_image)
# 1) Check how many Results objects we have
if not results:
print("No results returned by model.")
return pil_image, []
# 2) Take the first Results object
r = results[0]
# Debug: print the entire Results object
print("Raw model output (first Results object):", r)
# 3) If r.boxes is None or empty, we have no detections
if not hasattr(r, 'boxes') or r.boxes is None or len(r.boxes) == 0:
print("No boxes found in results[0].")
return pil_image, []
# 4) Parse bounding boxes
bboxes = []
draw = ImageDraw.Draw(pil_image)
# r.boxes is an ultralytics.engine.results.Boxes object
# We can iterate over each box in r.boxes:
for box in r.boxes:
# box has .xyxy, .conf, .cls as 1D tensors
# e.g. box.xyxy[0] is [x1, y1, x2, y2]
# box.conf[0] is confidence
# box.cls[0] is class ID
coords = box.xyxy[0].tolist() # [x1, y1, x2, y2]
conf = float(box.conf[0])
cls_id = int(box.cls[0])
# If your license plate class is 0:
if cls_id == 0:
x1, y1, x2, y2 = map(int, coords)
bboxes.append((x1, y1, x2, y2))
# Optional: draw bounding box for visualization
draw.rectangle([x1, y1, x2, y2], outline="red", width=2)
return pil_image, bboxes
##############################################################################
# 4. Streamlit App
##############################################################################
def main():
st.title("YOLOv10 + Chaotic Encryption Demo")
st.write(
"""
**Instructions**:
1. Provide an image (URL or file upload).
2. If a license plate is detected, only that region will be **encrypted** using Chaotic Logistic Map.
3. Download the final result.
"""
)
# A. Model weights path
default_model_path = "best.pt"
model_path = st.sidebar.text_input("YOLOv10 Weights (.pt)", value=default_model_path)
if not os.path.isfile(model_path):
st.warning(f"Model file '{model_path}' not found. Upload or provide a correct path.")
st.stop()
with st.spinner("Loading YOLOv10 model..."):
model = load_model(model_path)
st.success("Model loaded successfully!")
# B. Image input
st.subheader("Image Input")
image_url = st.text_input("Image URL (optional)")
uploaded_file = st.file_uploader("Or upload an image file", type=["jpg", "jpeg", "png"])
# C. Encryption seed slider
key_seed = st.slider("Encryption Key Seed (0 < seed < 1)", 0.001, 0.999, 0.5, step=0.001)
if st.button("Detect & Encrypt"):
# 1) Load the image from URL or file
if image_url and not uploaded_file:
try:
response = requests.get(image_url, timeout=10)
image_bytes = io.BytesIO(response.content)
pil_image = Image.open(image_bytes).convert("RGB")
except Exception as e:
st.error(f"Failed to load image from URL. Error: {str(e)}")
return
elif uploaded_file:
pil_image = Image.open(uploaded_file).convert("RGB")
else:
st.warning("Please either paste a valid URL or upload an image.")
return
st.image(pil_image, caption="Original Image", use_container_width=True)
# 2) Detect plates
with st.spinner("Detecting license plates..."):
image_with_boxes, bboxes = detect_license_plates(model, pil_image.copy())
st.image(image_with_boxes, caption="Detected Plate(s)", use_container_width=True)
if not bboxes:
st.warning("No license plates detected.")
return
# 3) Encrypt bounding box regions
with st.spinner("Encrypting license plates..."):
np_img = np.array(pil_image)
encrypted_np = np_img.copy()
for (x1, y1, x2, y2) in bboxes:
plate_region = encrypted_np[y1:y2, x1:x2]
encrypted_region = encrypt_image(plate_region, key_seed)
encrypted_np[y1:y2, x1:x2] = encrypted_region
encrypted_image = Image.fromarray(encrypted_np)
st.image(encrypted_image, caption="Encrypted Image", use_container_width=True)
# 4) Download link
buf = io.BytesIO()
encrypted_image.save(buf, format="PNG")
buf.seek(0)
st.download_button(
label="Download Encrypted Image",
data=buf,
file_name="encrypted_plate.png",
mime="image/png"
)
if __name__ == "__main__":
main()