RafidMehda commited on
Commit
f42dfe1
·
verified ·
1 Parent(s): 4e039d8

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +229 -0
app.py ADDED
@@ -0,0 +1,229 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import os
3
+ import requests
4
+ import numpy as np
5
+ from PIL import Image, ImageDraw
6
+ import io
7
+ import random
8
+ from ultralytics import YOLO
9
+
10
+ ###############################################################################
11
+ # 1. Chaotic Logistic Map Encryption Functions
12
+ ###############################################################################
13
+
14
+ def logistic_map(r, x):
15
+ return r * x * (1 - x)
16
+
17
+ def generate_key(seed, n):
18
+ """
19
+ Generate a chaotic key (array of size n) using a logistic map and the given seed.
20
+ """
21
+ key = []
22
+ x = seed
23
+ for _ in range(n):
24
+ x = logistic_map(3.9, x)
25
+ key.append(int(x * 255) % 256) # map float to 0-255
26
+ return np.array(key, dtype=np.uint8)
27
+
28
+ def shuffle_pixels(img_array, seed):
29
+ """
30
+ Shuffle the pixels in img_array based on a random sequence seeded by 'seed'.
31
+ """
32
+ h, w, c = img_array.shape
33
+ num_pixels = h * w
34
+ flattened = img_array.reshape(-1, c)
35
+ indices = np.arange(num_pixels)
36
+
37
+ random.seed(seed)
38
+ random.shuffle(indices)
39
+
40
+ shuffled = flattened[indices]
41
+ return shuffled.reshape(h, w, c), indices
42
+
43
+ def encrypt_image(img_array, seed):
44
+ """
45
+ Encrypt the given image array using a two-layer XOR + pixel shuffling approach.
46
+ """
47
+ h, w, c = img_array.shape
48
+ flat_image = img_array.flatten()
49
+
50
+ # First chaotic key
51
+ chaotic_key_1 = generate_key(seed, len(flat_image))
52
+ # XOR-based encryption (first layer)
53
+ encrypted_flat_1 = [p ^ chaotic_key_1[i] for i, p in enumerate(flat_image)]
54
+ encrypted_array_1 = np.array(encrypted_flat_1, dtype=np.uint8).reshape(h, w, c)
55
+
56
+ # Shuffle
57
+ shuffled_array, _ = shuffle_pixels(encrypted_array_1, seed)
58
+
59
+ # Second chaotic key
60
+ chaotic_key_2 = generate_key(seed * 1.1, len(flat_image))
61
+ shuffled_flat = shuffled_array.flatten()
62
+ encrypted_flat_2 = [p ^ chaotic_key_2[i] for i, p in enumerate(shuffled_flat)]
63
+ doubly_encrypted_array = np.array(encrypted_flat_2, dtype=np.uint8).reshape(h, w, c)
64
+
65
+ return doubly_encrypted_array
66
+
67
+ ###############################################################################
68
+ # 2. YOLOv8 License Plate Detection
69
+ ###############################################################################
70
+
71
+ @st.cache_resource(show_spinner=False)
72
+ def load_model(weights_path: str):
73
+ """
74
+ Loads the YOLOv8 model from local .pt weights.
75
+ """
76
+ model = YOLO(weights_path)
77
+ return model
78
+
79
+ def detect_license_plates(model, pil_image):
80
+ """
81
+ Runs YOLOv8 detection on the PIL image.
82
+ Returns:
83
+ - image_with_boxes: PIL image with bounding boxes drawn
84
+ - bboxes: list of (x1, y1, x2, y2) for detected license plates
85
+ """
86
+ np_image = np.array(pil_image)
87
+ results = model.predict(np_image) # YOLOv8 inference
88
+
89
+ # *** DEBUG: Print the raw model output ***
90
+ print("Raw model output:", results)
91
+
92
+ # Check if any detections are made
93
+ if not results or len(results) == 0:
94
+ print("No detections made.")
95
+ return pil_image, []
96
+
97
+ # Assuming single image input, get the first result
98
+ result = results[0]
99
+
100
+ # Check if 'boxes' attribute exists and is not empty
101
+ if not hasattr(result, 'boxes') or result.boxes is None or len(result.boxes) == 0:
102
+ print("No boxes found in results[0].")
103
+ return pil_image, []
104
+
105
+ bboxes = []
106
+ draw = ImageDraw.Draw(pil_image)
107
+
108
+ # Iterate over each detected box
109
+ for box in result.boxes:
110
+ # box.xyxy is a tensor with [x1, y1, x2, y2]
111
+ # box.conf is the confidence
112
+ # box.cls is the class ID
113
+ coords = box.xyxy[0].tolist() # [x1, y1, x2, y2]
114
+ conf = box.conf[0].item()
115
+ cls_id = int(box.cls[0].item())
116
+ cls_name = model.names.get(cls_id, "Unknown")
117
+
118
+ # If the detected class is 'LicensePlate'
119
+ # Adjust the class name or ID as per your model's configuration
120
+ if cls_name.lower() == "licenseplate" or cls_id == 0:
121
+ x1, y1, x2, y2 = map(int, coords)
122
+ bboxes.append((x1, y1, x2, y2))
123
+ # Draw bounding box for visualization
124
+ draw.rectangle([x1, y1, x2, y2], outline="red", width=2)
125
+
126
+ return pil_image, bboxes
127
+
128
+ ###############################################################################
129
+ # 3. Streamlit App
130
+ ###############################################################################
131
+ def main():
132
+ st.title("YOLOv8 + Chaotic Encryption Demo")
133
+ st.write(
134
+ """
135
+ **Instructions**:
136
+ 1. Provide an image (URL or file upload).
137
+ 2. If a license plate is detected, only that region will be **encrypted** using Chaotic Logistic Map.
138
+ 3. Download the final result.
139
+ """
140
+ )
141
+
142
+ # A. Model weights path
143
+ default_model_path = "best.pt" # Adjust if your model file is named differently
144
+ model_path = st.sidebar.text_input("YOLOv8 Weights (.pt)", value=default_model_path)
145
+
146
+ if not os.path.isfile(model_path):
147
+ st.warning(f"Model file '{model_path}' not found. Please upload or provide a correct path.")
148
+ st.stop()
149
+
150
+ with st.spinner("Loading YOLOv8 model..."):
151
+ model = load_model(model_path)
152
+ st.success("Model loaded successfully!")
153
+
154
+ # B. Image input
155
+ st.subheader("Image Input")
156
+ image_url = st.text_input("Image URL (optional)")
157
+ uploaded_file = st.file_uploader("Or upload an image file", type=["jpg", "jpeg", "png"])
158
+
159
+ # C. Encryption seed slider
160
+ key_seed = st.slider("Encryption Key Seed (0 < seed < 1)", 0.001, 0.999, 0.5, step=0.001)
161
+
162
+ if st.button("Detect & Encrypt"):
163
+ # 1) Load the image from URL or file
164
+ if image_url and not uploaded_file:
165
+ try:
166
+ response = requests.get(image_url, timeout=10)
167
+ response.raise_for_status()
168
+ image_bytes = io.BytesIO(response.content)
169
+ pil_image = Image.open(image_bytes).convert("RGB")
170
+ except Exception as e:
171
+ st.error(f"Failed to load image from URL. Error: {str(e)}")
172
+ return
173
+ elif uploaded_file:
174
+ try:
175
+ pil_image = Image.open(uploaded_file).convert("RGB")
176
+ except Exception as e:
177
+ st.error(f"Failed to open uploaded image. Error: {str(e)}")
178
+ return
179
+ else:
180
+ st.warning("Please either paste a valid URL or upload an image.")
181
+ return
182
+
183
+ st.image(pil_image, caption="Original Image", use_container_width=True)
184
+
185
+ # 2) Detect plates
186
+ with st.spinner("Detecting license plates..."):
187
+ image_with_boxes, bboxes = detect_license_plates(model, pil_image.copy())
188
+
189
+ st.image(image_with_boxes, caption="Detected Plate(s)", use_container_width=True)
190
+ if not bboxes:
191
+ st.warning("No license plates detected.")
192
+ return
193
+
194
+ # 3) Encrypt bounding box regions
195
+ with st.spinner("Encrypting license plates..."):
196
+ np_img = np.array(pil_image)
197
+ encrypted_np = np_img.copy()
198
+ for (x1, y1, x2, y2) in bboxes:
199
+ # Ensure coordinates are within image bounds
200
+ x1 = max(x1, 0)
201
+ y1 = max(y1, 0)
202
+ x2 = min(x2, encrypted_np.shape[1])
203
+ y2 = min(y2, encrypted_np.shape[0])
204
+
205
+ plate_region = encrypted_np[y1:y2, x1:x2]
206
+ if plate_region.size == 0:
207
+ st.warning(f"Detected plate region ({x1}, {y1}, {x2}, {y2}) is invalid or empty.")
208
+ continue
209
+
210
+ encrypted_region = encrypt_image(plate_region, key_seed)
211
+ encrypted_np[y1:y2, x1:x2] = encrypted_region
212
+
213
+ encrypted_image = Image.fromarray(encrypted_np)
214
+
215
+ st.image(encrypted_image, caption="Encrypted Image", use_container_width=True)
216
+
217
+ # 4) Download link
218
+ buf = io.BytesIO()
219
+ encrypted_image.save(buf, format="PNG")
220
+ buf.seek(0)
221
+ st.download_button(
222
+ label="Download Encrypted Image",
223
+ data=buf,
224
+ file_name="encrypted_plate.png",
225
+ mime="image/png"
226
+ )
227
+
228
+ if __name__ == "__main__":
229
+ main()