HiralShah62 commited on
Commit
860c4dc
Β·
verified Β·
1 Parent(s): b0cd764

Upload 7 files

Browse files
Files changed (7) hide show
  1. README.md +77 -10
  2. app.py +9 -0
  3. detect.py +124 -0
  4. home.py +17 -0
  5. refine.py +163 -0
  6. requirements.txt +9 -0
  7. yolo11n-custom.pt +3 -0
README.md CHANGED
@@ -1,13 +1,80 @@
 
 
 
 
 
 
1
  ---
2
- title: License Plate Detection System
3
- emoji: πŸ“ˆ
4
- colorFrom: green
5
- colorTo: red
6
- sdk: streamlit
7
- sdk_version: 1.43.2
8
- app_file: app.py
9
- pinned: false
10
- license: apache-2.0
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  ---
12
 
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 🚘 License Plate Detection & Refinement
2
+
3
+ A **Streamlit-based application** for detecting and refining license plate images using **YOLO for detection** and **OpenCV for image enhancements**.
4
+
5
+ [![Open in Streamlit](https://static.streamlit.io/badges/streamlit_badge_black_white.svg)](your-streamlit-app-link)
6
+
7
  ---
8
+
9
+ ## πŸ”§ Features
10
+
11
+ ### **🚘 Real-Time License Plate Detection**
12
+ - Upload an **image** or **video**, or use a **webcam** for real-time detection.
13
+ - Uses **YOLOv11** for accurate license plate detection.
14
+ - Extracts text using **EasyOCR**.
15
+ - Displays detected plates in a structured table.
16
+
17
+ ### **πŸ›  Refine Image for Detection**
18
+ - Upload an image and apply **pre-processing techniques** to enhance detection.
19
+ - Select from detected license plates to refine specific sections.
20
+ - **Image enhancement options:**
21
+ - **Noise Reduction** (Bilateral & Non-Local Means Denoising)
22
+ - **Sharpening** (Enhances edges for better OCR accuracy)
23
+ - **Grayscale Conversion** (Improves contrast)
24
+ - **Adaptive Thresholding** (Dynamic brightness adjustment)
25
+ - **Edge Detection** (Canny filter for better boundary detection)
26
+ - **Invert Colors** (Helpful for light text on dark backgrounds)
27
+ - **Auto Enhancement** (Applies recommended adjustments automatically)
28
+ - **Gamma Correction, CLAHE, Histogram Equalization, Scaling, Blur, Contrast & Brightness adjustments**
29
+
30
  ---
31
 
32
+ ## πŸ“Œ How to Run Locally
33
+
34
+ ### **1️⃣ Install dependencies**
35
+ ```sh
36
+ pip install -r requirements.txt
37
+ ```
38
+
39
+ ### **2️⃣ Run the application**
40
+ ```sh
41
+ streamlit run app.py
42
+ ```
43
+
44
+ ---
45
+
46
+ ## πŸ“ Project Structure
47
+ ```
48
+ πŸ“‚ License-Plate-Detection
49
+ │── app.py # Main navigation & home page
50
+ │── pages/
51
+ β”‚ β”œβ”€β”€ detect.py # License plate detection module
52
+ β”‚ β”œβ”€β”€ refine.py # Image enhancement module
53
+ │── requirements.txt # Required Python packages
54
+ │── README.md # Project documentation
55
+ ```
56
+
57
+ ---
58
+
59
+ ## πŸš€ Deployment
60
+ You can deploy this app on **Streamlit Cloud** or **Hugging Face Spaces**:
61
+
62
+ 1. **Fork & Push to GitHub**
63
+ 2. **Deploy via Streamlit Sharing / Hugging Face Spaces**
64
+
65
+ [![Deploy on Hugging Face](https://huggingface.co/datasets/huggingface/badges/resolve/main/hf-badge-open.svg)](your-huggingface-link)
66
+
67
+ ---
68
+
69
+ ## πŸ“Œ Future Enhancements
70
+ - **Real-time tracking of license plates**.
71
+ - **OCR post-processing to correct errors**.
72
+ - **Additional denoising & image restoration techniques**.
73
+
74
+ ---
75
+
76
+ ## πŸ“ License
77
+ This project is **open-source** under the **MIT License**. Feel free to modify and improve it!
78
+
79
+ 🌟 If you like this project, don’t forget to **star the repository**!
80
+
app.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+
3
+ pages = [
4
+ st.Page("home.py", title="Home", icon="🏠"),
5
+ st.Page("detect.py", title="Real-Time License Plate Detection", icon="🚘"),
6
+ st.Page("refine.py", title="Refine Image for Detection", icon="πŸ–ΌοΈ")
7
+ ]
8
+ nav = st.navigation(pages, position="sidebar", expanded=False)
9
+ nav.run()
detect.py ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from ultralytics import YOLO
3
+ import cv2
4
+ import easyocr
5
+ import numpy as np
6
+ import pandas as pd
7
+ from PIL import Image
8
+ import tempfile
9
+
10
+ @st.cache_resource
11
+ def load_model():
12
+ model = YOLO('yolo11n-custom.pt')
13
+ model.fuse()
14
+ return model
15
+
16
+ model = load_model()
17
+
18
+ reader = easyocr.Reader(['en'])
19
+
20
+ def detect_license_plate(image):
21
+ results = model.predict(image, conf=0.15, iou=0.3, classes=[0])
22
+ plate_texts = []
23
+ img_array = np.array(image)
24
+ # img = cv2.imread(image_path)
25
+ img = cv2.cvtColor(img_array, cv2.COLOR_RGB2BGR)
26
+ img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
27
+
28
+ img_height, img_width, _ = img.shape
29
+
30
+ for result in results:
31
+ for bbox in result.boxes.xyxy:
32
+ x1, y1, x2, y2 = map(int, bbox.tolist())
33
+ plate = img[int(y1):int(y2), int(x1):int(x2)]
34
+ scale=2
35
+ height, width = plate.shape[:2]
36
+ plate = cv2.resize(plate, (width * scale, height * scale), interpolation=cv2.INTER_CUBIC)
37
+
38
+ text = reader.readtext(plate, detail=0, allowlist="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-")
39
+ text = " ".join(text).upper()
40
+
41
+ text_scale = max(1, width / 250)
42
+ thickness = max(2, width // 200)
43
+ cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), thickness)
44
+ (text_width, text_height), _ = cv2.getTextSize(text, cv2.FONT_HERSHEY_SIMPLEX, text_scale, thickness)
45
+ text_x = x1 + (width - text_width) // 2 # Centered horizontally
46
+ text_y = y1 - 10 if y1 > 50 else y2 + text_height + 20 # Above unless too high
47
+ text_box_y1 = text_y - text_height - 5
48
+ text_box_y2 = text_y + 5
49
+ cv2.rectangle(img, (text_x - 8, text_box_y1 - 3), (text_x + text_width + 8, text_box_y2 + 3), (0, 0, 0), -1)
50
+ cv2.rectangle(img, (text_x - 5, text_box_y1), (text_x + text_width + 5, text_box_y2), (255, 255, 255), -1)
51
+ cv2.putText(img, text, (text_x, text_y), cv2.FONT_HERSHEY_SIMPLEX, text_scale, (0, 0, 0), thickness)
52
+
53
+ plate_texts.append(text)
54
+ image = img
55
+ return image, plate_texts
56
+
57
+ st.title("🚘 Real-Time License Plate Detection", anchor=False)
58
+
59
+ st.write("For better license plate detection, ensure you use high-quality images. If detection is unclear, try enhancing the image first. Use the Refine Image for Detection tool.")
60
+
61
+ st.write("Upload an image, upload a video, or use your webcam for real-time license plate detection.")
62
+
63
+ option = st.radio("Choose Input Source:", ("Upload Image", "Upload Video", "Webcam"), horizontal=True )
64
+
65
+
66
+ if option == "Upload Image":
67
+ uploaded_file = st.file_uploader("Upload an image", type=["jpg", "png", "jpeg"])
68
+ if uploaded_file:
69
+ img = Image.open(uploaded_file)
70
+ st.write("Processing...")
71
+
72
+ processed_img, plate_texts = detect_license_plate(img)
73
+
74
+ st.image(processed_img, caption="Detected Plates Image", use_container_width=True)
75
+ st.write("**Detected License Plates:**")
76
+ if plate_texts:
77
+ plates = pd.DataFrame({"License Plate": plate_texts})
78
+ plates.index = plates.index + 1
79
+ st.table(plates)
80
+ else:
81
+ st.write("No license plates detected.")
82
+
83
+ elif option == "Upload Video":
84
+ uploaded_video = st.file_uploader("Choose a video...", type=["mp4", "avi", "mov"])
85
+ if uploaded_video is not None:
86
+ st.write("Processing video...")
87
+ tfile = tempfile.NamedTemporaryFile(delete=False)
88
+ tfile.write(uploaded_video.read())
89
+ cap = cv2.VideoCapture(tfile.name)
90
+ frame_placeholder = st.empty()
91
+
92
+ while cap.isOpened():
93
+ ret, frame = cap.read()
94
+ if not ret:
95
+ break
96
+ processed_frame, plate_texts = detect_license_plate(frame)
97
+
98
+ frame_placeholder.image(processed_frame, caption="Detected Plates Video", use_container_width=True)
99
+ cap.release()
100
+
101
+ elif option == "Webcam":
102
+ if "running" not in st.session_state:
103
+ st.session_state.running = True
104
+ if st.button("Stop"):
105
+ st.session_state.running = False
106
+
107
+ st.write("Starting Webcam... Press **Stop** to end.")
108
+ cap = cv2.VideoCapture(0)
109
+ frame_placeholder = st.empty()
110
+
111
+ while cap.isOpened():
112
+ ret, frame = cap.read()
113
+ if not ret:
114
+ st.warning("Failed to capture webcam feed.")
115
+ break
116
+
117
+ processed_frame, plate_texts = detect_license_plate(frame)
118
+
119
+ frame_placeholder.image(processed_frame, channels="BGR", caption="Webcam Feed", use_container_width=True)
120
+
121
+ if not st.session_state.running:
122
+ break
123
+
124
+ cap.release()
home.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+
3
+ st.title("Welcome to License Plate Detection App", anchor=False)
4
+ st.write("Select a feature below to detect or enhance license plate images.")
5
+
6
+ # Buttons for navigation
7
+ col1, col2 = st.columns(2)
8
+
9
+ with col1:
10
+ if st.button("🚘 Detect License Plates"):
11
+ st.switch_page("detect.py") # Navigates to the detection page
12
+ st.caption("Upload an image, video, or use a webcam for real-time detection.")
13
+
14
+ with col2:
15
+ if st.button("πŸ–ΌοΈ Enhance Image for Detection"):
16
+ st.switch_page("refine.py") # Navigates to the image enhancement page
17
+ st.caption("Improve image quality for better license plate recognition.")
refine.py ADDED
@@ -0,0 +1,163 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from ultralytics import YOLO
3
+ import cv2
4
+ import easyocr
5
+ import numpy as np
6
+ import pandas as pd
7
+ from PIL import Image
8
+ import tempfile
9
+
10
+ # Upload image
11
+ @st.cache_resource
12
+ def load_model():
13
+ model = YOLO('yolo11n-custom.pt')
14
+ model.fuse()
15
+ return model
16
+
17
+ model = load_model()
18
+
19
+ reader = easyocr.Reader(['en'])
20
+ def apply_filters(image, noise, sharpen, grayscale, threshold, edges, invert, auto, blur, contrast, brightness, scale, denoise, hist_eq, gamma, clahe):
21
+ img = np.array(image)
22
+
23
+ # Auto Enhancement
24
+ if auto:
25
+ lab = cv2.cvtColor(img, cv2.COLOR_RGB2LAB)
26
+ l, a, b = cv2.split(lab)
27
+ clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8, 8))
28
+ l = clahe.apply(l)
29
+ img = cv2.merge((l, a, b))
30
+ img = cv2.cvtColor(img, cv2.COLOR_LAB2RGB)
31
+
32
+
33
+ # Scaling
34
+ if scale != 1.0:
35
+ height, width = img.shape[:2]
36
+ img = cv2.resize(img, (int(width * scale), int(height * scale)))
37
+
38
+ # Noise Reduction (Bilateral Filtering)
39
+ if noise:
40
+ img = cv2.bilateralFilter(img, 9, 75, 75)
41
+
42
+ # Noise Reduction (Non-Local Means)
43
+ if denoise:
44
+ img = cv2.fastNlMeansDenoisingColored(img, None, 10, 10, 7, 21)
45
+
46
+ # Sharpening
47
+ if sharpen:
48
+ kernel = np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]])
49
+ img = cv2.filter2D(img, -1, kernel)
50
+
51
+ # Convert to Grayscale
52
+ if grayscale or threshold or hist_eq or clahe:
53
+ img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
54
+
55
+ # Histogram Equalization
56
+ if hist_eq:
57
+ img = cv2.equalizeHist(img)
58
+
59
+ # CLAHE (Contrast Limited Adaptive Histogram Equalization)
60
+ if clahe:
61
+ clahe_filter = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8, 8))
62
+ img = clahe_filter.apply(img)
63
+
64
+ # Adaptive Thresholding
65
+ if threshold:
66
+ img = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
67
+
68
+ # Edge Detection
69
+ if edges:
70
+ img = cv2.Canny(img, 100, 200)
71
+
72
+ # Invert Colors
73
+ if invert:
74
+ img = cv2.bitwise_not(img)
75
+
76
+ # Blur
77
+ if gamma != 1.0:
78
+ inv_gamma = 1.0 / gamma
79
+ table = np.array([(i / 255.0) ** inv_gamma * 255 for i in np.arange(0, 256)]).astype("uint8")
80
+ img = cv2.LUT(img, table)
81
+
82
+ # Blur
83
+ if blur:
84
+ img = cv2.GaussianBlur(img, (2*blur + 1, 2*blur + 1), 0)
85
+
86
+ # Contrast & Brightness
87
+ if contrast != 1.0 or brightness != 0:
88
+ img = cv2.convertScaleAbs(img, alpha=contrast, beta=brightness)
89
+
90
+ return img
91
+
92
+ st.title("πŸ–ΌοΈ Refine Image for Detection")
93
+ st.write("Enhance the license plate image for better recognition.")
94
+
95
+ uploaded_file = st.file_uploader("πŸ“€ Upload an image", type=["jpg", "png", "jpeg"])
96
+
97
+ if uploaded_file:
98
+ # Read image
99
+ img = Image.open(uploaded_file)
100
+ img = np.array(img)
101
+
102
+ # Detect license plates
103
+ st.write("πŸ” Detecting license plates...")
104
+ results = model.predict(img, conf=0.15, iou=0.3, classes=[0])
105
+ plates = results[0].boxes.xyxy if len(results) > 0 else []
106
+
107
+ if len(plates) == 0:
108
+ st.error("❌ No license plates detected. Try another image.")
109
+ else:
110
+ st.write("πŸ“Œ **Select a License Plate by Clicking Below**")
111
+
112
+ # Show detected plates in a grid
113
+ if "selected_plate_index" not in st.session_state:
114
+ st.session_state.selected_plate_index = 0
115
+
116
+ selected_plate_index = st.session_state.get("selected_plate_index", 0)
117
+ cols = st.columns(len(plates)) # Create dynamic columns
118
+
119
+ for i, (x1, y1, x2, y2) in enumerate(plates):
120
+ plate_img = img[int(y1):int(y2), int(x1):int(x2)]
121
+ plate_img = Image.fromarray(plate_img)
122
+
123
+ with cols[i]: # Place each image in a column
124
+ st.image(plate_img, caption=f"Plate {i+1}", use_container_width =True)
125
+ if st.button(f"Select Plate {i+1}", key=f"plate_{i}"):
126
+ st.session_state["selected_plate_index"] = i
127
+
128
+ # Get the selected plate
129
+ selected_index = st.session_state["selected_plate_index"]
130
+ x1, y1, x2, y2 = map(int, plates[selected_index])
131
+ cropped_plate = img[y1:y2, x1:x2]
132
+ refined_img = cropped_plate.copy()
133
+
134
+ # Sidebar for enhancements
135
+ st.sidebar.header("πŸ”§ Enhancement Options")
136
+ blur = st.sidebar.slider("πŸ”Ή Blur", 0, 10, 0)
137
+ contrast = st.sidebar.slider("πŸ”Ή Contrast", 0.5, 2.0, 1.0)
138
+ brightness = st.sidebar.slider("πŸ”Ή Brightness", 0.5, 2.0, 1.0)
139
+ gamma = st.sidebar.slider("Gamma Correction", 0.1, 3.0, 1.0, 0.1)
140
+ scale = st.sidebar.slider("πŸ”Ή Scale", 1.0, 10.0, 5.0)
141
+ noise = st.sidebar.checkbox("Noise Reduction (Bilateral)")
142
+ denoise = st.sidebar.checkbox("Denoise (Non-Local Means)")
143
+ sharpen = st.sidebar.checkbox("Sharpening")
144
+ hist_eq = st.sidebar.checkbox("Histogram Equalization")
145
+ clahe = st.sidebar.checkbox("CLAHE (Advanced Contrast)")
146
+ grayscale = st.sidebar.checkbox("Grayscale Conversion")
147
+ threshold = st.sidebar.checkbox("Adaptive Thresholding")
148
+ edges = st.sidebar.checkbox("Edge Detection")
149
+ invert = st.sidebar.checkbox("Invert Colors")
150
+ auto = st.sidebar.checkbox("Auto Enhancement")
151
+
152
+ refined_img = apply_filters(refined_img, noise, sharpen, grayscale, threshold, edges, invert, auto, blur, contrast, brightness, scale, denoise, hist_eq, gamma, clahe)
153
+
154
+ st.image(refined_img, caption="Refined License Plate", use_container_width=True)
155
+
156
+ if st.button("πŸ“– Detect License Plate Text"):
157
+ with st.spinner("πŸ”Ž Reading text..."):
158
+ ocr_result = reader.readtext(np.array(refined_img), detail=0, allowlist="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-")
159
+ plate_text = " ".join(ocr_result).upper() if ocr_result else "❌ No text detected."
160
+
161
+ # Show detected text
162
+ st.subheader("πŸ“œ Detected License Plate:")
163
+ st.code(plate_text, language="plaintext")
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ streamlit
2
+ opencv-python
3
+ torch
4
+ torchvision
5
+ easyocr
6
+ numpy
7
+ pandas
8
+ pillow
9
+ ultralytics
yolo11n-custom.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c5ebaab2bc7c2036d97706cd1992389998de338961d0485879d0d128755c52e2
3
+ size 5477537