prthm11 commited on
Commit
d25f03f
·
verified ·
1 Parent(s): b600ed5

Upload 2 files

Browse files
live_streaming_flask.py ADDED
@@ -0,0 +1,151 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, render_template, Response, flash, redirect, url_for
2
+ import cv2
3
+ from unstructured.partition.pdf import partition_pdf
4
+ import json, base64, io, os
5
+ from PIL import Image
6
+ from imutils.perspective import four_point_transform
7
+ from dotenv import load_dotenv
8
+ import pytesseract
9
+
10
+ load_dotenv()
11
+
12
+ app = Flask(__name__)
13
+ app.secret_key = os.getenv("SECRET_KEY")
14
+ pytesseract.pytesseract.tesseract_cmd = r"C:\Program Files\Tesseract-OCR\tesseract.exe"
15
+ poppler_path=r"C:\poppler-23.11.0\Library\bin"
16
+
17
+ count = 0
18
+ OUTPUT_FOLDER = "OUTPUTS"
19
+ IMAGE_FOLDER_PATH = os.path.join(OUTPUT_FOLDER, "SCANNED_IMAGE")
20
+ DETECTED_IMAGE_FOLDER_PATH = os.path.join(OUTPUT_FOLDER,"DETECTED_IMAGE")
21
+ PDF_FOLDER_PATH = os.path.join(OUTPUT_FOLDER, "SCANNED_PDF")
22
+ JSON_FOLDER_PATH = os.path.join(OUTPUT_FOLDER, "EXTRACTED_JSON")
23
+
24
+ for path in [OUTPUT_FOLDER, IMAGE_FOLDER_PATH, DETECTED_IMAGE_FOLDER_PATH, PDF_FOLDER_PATH, JSON_FOLDER_PATH]:
25
+ os.makedirs(path, exist_ok=True)
26
+
27
+ # camera = cv2.VideoCapture('rtsp://freja.hiof.no:1935/rtplive/_definst_/hessdalen03.stream') # use 0 for web camera
28
+ # for cctv camera use rtsp://username:password@ip_address:554/user=username_password='password'_channel=channel_number_stream=0.sdp' instead of camera
29
+ # for local webcam use
30
+ camera= cv2.VideoCapture(0)
31
+
32
+ # Increase resolution if supported by the webcam
33
+ camera.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
34
+ camera.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)
35
+ camera.set(cv2.CAP_PROP_FPS, 30)
36
+
37
+ # --- FUNCTION: Detect document contour ---
38
+ def detect_document_contour(image):
39
+ gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
40
+ blur = cv2.GaussianBlur(gray, (5, 5), 0)
41
+ _, thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
42
+
43
+ contours, _ = cv2.findContours(thresh, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
44
+ contours = sorted(contours, key=cv2.contourArea, reverse=True)
45
+
46
+ for contour in contours:
47
+ area = cv2.contourArea(contour)
48
+ if area > 1000:
49
+ peri = cv2.arcLength(contour, True)
50
+ approx = cv2.approxPolyDP(contour, 0.02 * peri, True)
51
+ if len(approx) == 4:
52
+ return approx
53
+ return None
54
+
55
+ # --- FUNCTION: Extract images from saved PDF ---
56
+ def extract_images_from_pdf(pdf_path, output_json_path):
57
+ elements = partition_pdf(
58
+ filename=pdf_path,
59
+ strategy="hi_res",
60
+ extract_image_block_types=["Image"], # or ["Image", "Table"]
61
+ extract_image_block_to_payload=True, # Set to True to get base64 in output
62
+ )
63
+ with open(output_json_path, "w") as f:
64
+ json.dump([element.to_dict() for element in elements], f, indent=4)
65
+
66
+ # Display extracted images
67
+ with open(output_json_path, 'r') as file:
68
+ file_elements = json.load(file)
69
+
70
+ extracted_images_dir = os.path.join(os.path.dirname(output_json_path), "extracted_images")
71
+ os.makedirs(extracted_images_dir, exist_ok=True)
72
+
73
+ for i, element in enumerate(file_elements):
74
+ if "image_base64" in element["metadata"]:
75
+ image_data = base64.b64decode(element["metadata"]["image_base64"])
76
+ image = Image.open(io.BytesIO(image_data))
77
+ image.show(title=f"Extracted Image {i+1}")
78
+ # image.save(DETECTED_IMAGE_FOLDER_PATH, f"Extracted Image {i+1}.png")
79
+
80
+ display = None
81
+ scale = 0.5
82
+ contour = None
83
+
84
+ def gen_frames(): # generate frame by frame from camera
85
+ global display
86
+
87
+ while True:
88
+ # Capture frame-by-frame
89
+ success, frame = camera.read() # read the camera frame
90
+ if not success:
91
+ break
92
+ else:
93
+ display = frame.copy()
94
+ contour = detect_document_contour(display)
95
+
96
+ if contour is not None:
97
+ cv2.drawContours(display, [contour], -1, (0, 255, 0), 3)
98
+
99
+ resized = cv2.resize(display, (int(scale * display.shape[1]), int(scale * display.shape[0])))
100
+ cv2.imshow("📷 Scan Document - Press 's' to Save, ESC to Exit", resized)
101
+
102
+ ret, buffer = cv2.imencode('.jpg', resized)
103
+
104
+ frame = buffer.tobytes()
105
+ yield (b'--frame\r\n'
106
+ b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n') # concat frame one by one and show result
107
+
108
+ # --- Route: Scan Document ---
109
+ @app.route("/capture", methods=['POST'])
110
+ def capture_document():
111
+ global count, display
112
+
113
+ if display is None:
114
+ flash("❌ No frame captured!", "error")
115
+ return redirect(url_for("index"))
116
+
117
+ frame = display.copy()
118
+ contour = detect_document_contour(frame)
119
+
120
+ if contour is None:
121
+ flash("❌ No document contour found!", "error")
122
+ return redirect(url_for("index"))
123
+
124
+ warped = four_point_transform(frame, contour.reshape(4, 2))
125
+ image_path = os.path.join(IMAGE_FOLDER_PATH, f"scanned_colored_{count}.jpg")
126
+ pdf_path = os.path.join(PDF_FOLDER_PATH, f"scanned_colored_{count}.pdf")
127
+ json_path = os.path.join(JSON_FOLDER_PATH, f"scanned_{count}.json")
128
+ # json_path = os.path.join(DETECTED_IMAGE_FOLDER_PATH, f"scanned_{count}.json")
129
+
130
+ cv2.imwrite(image_path, warped)
131
+ img = Image.open(image_path).convert("RGB")
132
+ img.save(pdf_path)
133
+
134
+ extract_images_from_pdf(pdf_path, json_path)
135
+
136
+ flash("✅ Document scanned and saved!", "success")
137
+ count += 1
138
+ return redirect(url_for("index"))
139
+
140
+ @app.route('/video_feed')
141
+ def video_feed():
142
+ #Video streaming route. Put this in the src attribute of an img tag
143
+ return Response(gen_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')
144
+
145
+ @app.route('/')
146
+ def index():
147
+ """Video streaming home page."""
148
+ return render_template('live_streaming_index.html')
149
+
150
+ if __name__ == '__main__':
151
+ app.run(debug=True)
templates/live_streaming_index.html ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <!-- Required meta tags -->
6
+ <meta charset="utf-8">
7
+ <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
8
+
9
+ <!-- Bootstrap CSS -->
10
+ <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"
11
+ integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
12
+
13
+ <title>Live Streaming Demonstration</title>
14
+ </head>
15
+
16
+ <body>
17
+ <div class="container">
18
+ <div class="row">
19
+ <div class="col-lg-8 offset-lg-2">
20
+ <h3 class="mt-3">Live Streaming</h3>
21
+ <img src="{{ url_for('video_feed') }}" width="100%" class="mb-3">
22
+ <form action="{{ url_for('capture_document') }}" method="post">
23
+ <button type="submit" class="btn btn-success btn-lg">📸 Capture Image</button>
24
+ </form>
25
+ {% with messages = get_flashed_messages(with_categories=true) %}
26
+ {% for category, message in messages %}
27
+ {% if category == 'error' %}
28
+ <p style="color: red;">{{ message }}</p>
29
+ {% else %}
30
+ <p style="color: green;">{{ message }}</p>
31
+ {% endif %}
32
+ {% endfor %}
33
+ {% endwith %}
34
+ </div>
35
+ </div>
36
+ </div>
37
+ </body>
38
+
39
+ </html>