Bikas0 commited on
Commit
8df2f3a
·
1 Parent(s): c18ed2a

Card Cropping

Browse files
Dockerfile ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use the official Python image from the Docker Hub
2
+ FROM python:3.11.5-slim
3
+
4
+ # Upgrade pip to the latest version and install dependencies in one RUN command
5
+ RUN apt-get update && \
6
+ apt-get install -y git libgl1-mesa-glx libglib2.0-0 && \
7
+ python -m pip install --upgrade pip && \
8
+ apt-get clean && \
9
+ rm -rf /var/lib/apt/lists/*
10
+
11
+ # Set the working directory in the container
12
+ WORKDIR /app
13
+
14
+ # Copy the current directory contents into the container at /app
15
+ COPY . /app
16
+
17
+ # Install any needed packages specified in requirements.txt
18
+ RUN pip install --no-cache-dir -r requirements.txt
19
+
20
+ # Make port 7860 available to the world outside this container
21
+ EXPOSE 7860
22
+
23
+ # Define environment variable (corrected the syntax for environment variable name and value)
24
+ # ENV FLASK_APP=app.py
25
+
26
+ # Command to run the application
27
+ CMD ["gunicorn", "--bind", "0.0.0.0:7860", "app:app"]
app.py ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, jsonify, render_template, send_from_directory
2
+ import cv2
3
+ from ultralytics import YOLO
4
+ import os
5
+ import time
6
+
7
+ app = Flask(__name__)
8
+
9
+ # Initialize YOLO model
10
+ inst_model = YOLO('model/seg.pt')
11
+
12
+ # Function to perform YOLO prediction and crop detected card images
13
+ def detect_and_crop(image_path, output_folder):
14
+ # Read the image
15
+ frame = cv2.imread(image_path)
16
+
17
+ # Perform YOLO prediction
18
+ instance_results = inst_model.predict(frame)
19
+ result = instance_results[0]
20
+
21
+ if result.boxes and len(result.boxes) > 0:
22
+ # Loop through detected boxes
23
+ for box in result.boxes:
24
+ class_id = int(box.cls[0].item())
25
+ conf = box.conf[0].item()
26
+
27
+ # Check if the detected object is a card with high confidence
28
+ if class_id == 0 and conf >= 0.70:
29
+ # Crop the detected card
30
+ x1, y1, x2, y2 = box.xyxy[0]
31
+ cropped_card = frame[int(y1):int(y2), int(x1):int(x2)]
32
+
33
+ # Save the cropped card to the output folder
34
+ output_filename = os.path.join(output_folder, "cropped_card.jpg")
35
+ if os.path.exists(output_filename):
36
+ os.remove(output_filename)
37
+ cv2.imwrite(output_filename, cropped_card)
38
+ return output_filename
39
+ return None
40
+
41
+ @app.route('/')
42
+ def index():
43
+ return render_template('index.html')
44
+
45
+ @app.route('/detect-and-crop', methods=['POST'])
46
+ def detect_and_crop_endpoint():
47
+ if 'image' not in request.files:
48
+ return jsonify({'error': 'No image provided'}), 400
49
+
50
+ file = request.files['image']
51
+
52
+ # Create the output folder if it doesn't exist
53
+ output_folder = 'output'
54
+ if not os.path.exists(output_folder):
55
+ os.makedirs(output_folder)
56
+ else:
57
+ # Clear previous images in the output folder
58
+ files_in_output_folder = os.listdir(output_folder)
59
+ for file_in_folder in files_in_output_folder:
60
+ file_path = os.path.join(output_folder, file_in_folder)
61
+ os.remove(file_path)
62
+
63
+ # Save the uploaded file to a temporary location
64
+ input_image_path = os.path.join(output_folder, file.filename)
65
+ file.save(input_image_path)
66
+
67
+ start = time.time()
68
+
69
+ # Call the function to detect and crop card images
70
+ output_filename = detect_and_crop(input_image_path, output_folder)
71
+
72
+ end = time.time()
73
+ processing_time = end - start
74
+
75
+ if output_filename:
76
+ return jsonify({
77
+ 'message': 'Cropped image saved successfully',
78
+ 'output_filename': "cropped_card.jpg",
79
+ 'processing_time': processing_time
80
+ }), 200
81
+ else:
82
+ return jsonify({'message': 'No cards detected in the image'}), 200
83
+
84
+ @app.route('/output/<filename>')
85
+ def send_output_file(filename):
86
+ return send_from_directory('output', filename)
87
+
88
+ if __name__ == '__main__':
89
+ app.run(debug=True, host="0.0.0.0")
model/seg.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f64ce3694921b1b18981abbd511de12ce0098f011ae04695006d4ef37e497c41
3
+ size 6805219
reqiurements.txt ADDED
Binary file (122 Bytes). View file
 
static/360_F_517815080_tD3cmJRmhhztVmeHrnJd3DA4HT1Zkks7 (1).jpg ADDED
static/depositphotos_489854724-stock-illustration-light-multicolor-rainbow-vector-abstract.jpg ADDED
templates/index.html ADDED
@@ -0,0 +1,230 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Card cropping</title>
7
+ <style>
8
+ body {
9
+ font-family: Arial, sans-serif;
10
+ text-align: center;
11
+ margin: 0;
12
+ padding: 0;
13
+ position: relative;
14
+ background-image: url('static/depositphotos_489854724-stock-illustration-light-multicolor-rainbow-vector-abstract.jpg');
15
+ background-size: 2300px;
16
+ background-repeat: no-repeat;
17
+ background-position: center;
18
+ background-color: rgba(255, 255, 255, 0.2);
19
+ backdrop-filter: blur(7px);
20
+ min-height: 100vh; /* Ensure page takes at least viewport height */
21
+ }
22
+
23
+ form {
24
+ margin-bottom: 20px;
25
+ }
26
+
27
+ /* File uploader and predict button styles */
28
+ .file-upload-label {
29
+ padding: 10px;
30
+ }
31
+
32
+ #predictBtn {
33
+ padding: 10px 20px;
34
+ margin-top: 10px;
35
+ background-color: #007bff;
36
+ color: white;
37
+ border: none;
38
+ border-radius: 5px;
39
+ cursor: pointer;
40
+ font-size: 16px;
41
+ transition: background-color 0.3s;
42
+ }
43
+
44
+ #predictBtn:hover {
45
+ background-color: #0056b3;
46
+ }
47
+
48
+ #predictBtn:active {
49
+ background-color: #004f9f;
50
+ }
51
+
52
+ #predictBtn:focus {
53
+ outline: none;
54
+ }
55
+
56
+ .file-upload-input {
57
+ display: none;
58
+ }
59
+
60
+ .file-upload-icon {
61
+ font-size: 30px;
62
+ margin-right: 1px;
63
+ }
64
+
65
+ .image-container {
66
+ display: flex;
67
+ justify-content: center;
68
+ align-items: center;
69
+ margin-bottom: 20px;
70
+ position: relative;
71
+ }
72
+
73
+ .image-wrapper {
74
+ position: relative;
75
+ margin: 0 50px; /* Increased space between the images */
76
+ }
77
+
78
+ .image-label {
79
+ text-align: center;
80
+ background-color: #ffffff;
81
+ padding: 5px 10px;
82
+ border-radius: 5px;
83
+ font-weight: bold;
84
+ margin-top: 10px;
85
+ display: none; /* Initially hide labels */
86
+ }
87
+
88
+ .image-container img {
89
+ height: auto;
90
+ display: none; /* Initially hide images */
91
+ }
92
+
93
+ #uploadedImage {
94
+ max-width: 200px; /* Smaller size for uploaded image */
95
+ }
96
+
97
+ #croppedImage {
98
+ max-width: 250px;
99
+ }
100
+
101
+ #result {
102
+ margin-top: 20px;
103
+ position: relative;
104
+ }
105
+
106
+ #loading {
107
+ position: absolute;
108
+ top: 50%;
109
+ left: 50%;
110
+ transform: translate(-50%, -50%);
111
+ display: none;
112
+ }
113
+
114
+ #logo {
115
+ position: absolute;
116
+ bottom: 5px;
117
+ right: 5px;
118
+ max-width: 100px; /* Increase logo size */
119
+ height: auto;
120
+ }
121
+
122
+ .footprint {
123
+ position: fixed;
124
+ bottom: 0;
125
+ left: 0;
126
+ width: 100%;
127
+ text-align: center;
128
+ background-color: rgba(255, 255, 255, 0.2);
129
+ padding: 10px 0;
130
+ z-index: 1;
131
+ }
132
+
133
+ .footprint img {
134
+ max-width: 100px;
135
+ height: auto;
136
+ margin-left: auto; /* Push the logo to the right */
137
+ display: inline-block;
138
+ vertical-align: middle; /* Align the logo vertically with the text */
139
+ }
140
+ </style>
141
+ </head>
142
+ <body>
143
+ <br>
144
+ <br>
145
+ <h1>Visiting Card/Id Card Cropping System</h1>
146
+ <form id="uploadForm" enctype="multipart/form-data">
147
+ <label for="file-upload" class="file-upload-label">
148
+ <input type="file" name="image" id="file-upload" class="file-upload-input" accept="image/*" required>
149
+ <span class="file-upload-icon">📤</span> Choose an image
150
+ </label>
151
+ <button id="predictBtn" type="submit">Predict</button>
152
+ </form>
153
+ <div id="result">
154
+ <div id="loading">
155
+ <img src="path_to_loader_icon.gif" alt="Loader">
156
+ </div>
157
+ <p id="message"></p>
158
+ <div class="image-container">
159
+ <div class="image-wrapper">
160
+ <img id="uploadedImage" src="" alt="Uploaded Image">
161
+ <div class="image-label" id="uploadedLabel">Uploaded Image</div>
162
+ </div>
163
+ <div class="image-wrapper">
164
+ <img id="croppedImage" src="" alt="Cropped Image">
165
+ <div class="image-label" id="croppedLabel">Output</div>
166
+ </div>
167
+ </div>
168
+ </div>
169
+
170
+ <!-- Footprint -->
171
+ <div class="footprint">
172
+ <p>Copyright © XYZ It Ltd. 2024</p>
173
+ <img src="static/360_F_517815080_tD3cmJRmhhztVmeHrnJd3DA4HT1Zkks7 (1).jpg" alt="Company Logo">
174
+ </div>
175
+ <script>
176
+ document.getElementById('uploadForm').addEventListener('submit', async function(event) {
177
+ event.preventDefault();
178
+ const formData = new FormData(this);
179
+
180
+ // Show loading icon when form is submitted
181
+ document.getElementById('loading').style.display = 'block';
182
+
183
+ const fileInput = document.getElementById('file-upload');
184
+ const file = fileInput.files[0];
185
+ let uploadedImageSrc = '';
186
+ if (file) {
187
+ const reader = new FileReader();
188
+ reader.onload = function(e) {
189
+ uploadedImageSrc = e.target.result;
190
+ }
191
+ reader.readAsDataURL(file);
192
+ }
193
+
194
+ const response = await fetch('/detect-and-crop', {
195
+ method: 'POST',
196
+ body: formData
197
+ });
198
+
199
+ const result = await response.json();
200
+ document.getElementById('message').textContent = result.message;
201
+
202
+ if (uploadedImageSrc) {
203
+ const uploadedImage = document.getElementById('uploadedImage');
204
+ const uploadedLabel = document.getElementById('uploadedLabel');
205
+ uploadedImage.src = uploadedImageSrc;
206
+ uploadedImage.style.display = 'block';
207
+ uploadedLabel.style.display = 'block';
208
+ }
209
+
210
+ if (result.output_filename) {
211
+ const imageUrl = `/output/${result.output_filename}?${Date.now()}`;
212
+ const croppedImage = document.getElementById('croppedImage');
213
+ const croppedLabel = document.getElementById('croppedLabel');
214
+ croppedImage.src = imageUrl;
215
+ croppedImage.style.display = 'block';
216
+ croppedLabel.style.display = 'block';
217
+ } else {
218
+ // Clear the src attribute when no output image available
219
+ const croppedImage = document.getElementById('croppedImage');
220
+ const croppedLabel = document.getElementById('croppedLabel');
221
+ croppedImage.src = '';
222
+ croppedImage.style.display = 'none';
223
+ croppedLabel.style.display = 'none';
224
+ }
225
+
226
+ document.getElementById('loading').style.display = 'none';
227
+ });
228
+ </script>
229
+ </body>
230
+ </html>