bekzhanK1 commited on
Commit
26dd2fe
Β·
1 Parent(s): 7fefcdd

Optimize pipeline: load models once per PDF instead of per page for 10x speed improvement

Browse files
Files changed (2) hide show
  1. pipeline.py +80 -9
  2. stamp_detector/detect.py +21 -18
pipeline.py CHANGED
@@ -31,6 +31,10 @@ from qr.qr_extraction import process_image_no_save as process_qr
31
  from signature.inference import detect_signatures
32
  from stamp_detector.detect import detect_stamps_no_save
33
 
 
 
 
 
34
 
35
  def pdf_to_images(pdf_path: str, dpi: int = 200) -> List[np.ndarray]:
36
  """
@@ -68,13 +72,56 @@ def pdf_to_images(pdf_path: str, dpi: int = 200) -> List[np.ndarray]:
68
  return images
69
 
70
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  def process_pdf_pipeline(
72
  pdf_path: str,
73
  output_dir: str = "pipeline_outputs",
74
  stamp_model_path: str = "stamp_detector/stamp_model.pt",
75
  stamp_conf: float = 0.25,
76
  dpi: int = 200,
77
- save_intermediate: bool = False
 
78
  ) -> Dict[str, Any]:
79
  """
80
  Process a PDF file by converting each page to an image and running the pipeline.
@@ -86,6 +133,7 @@ def process_pdf_pipeline(
86
  stamp_conf: Confidence threshold for stamp detection
87
  dpi: DPI for PDF to image conversion
88
  save_intermediate: Whether to save intermediate results
 
89
 
90
  Returns:
91
  Combined results dictionary for all pages
@@ -104,8 +152,17 @@ def process_pdf_pipeline(
104
  print(f"Processing PDF: {pdf_path.name}")
105
  print(f"{'='*70}\n")
106
 
 
 
 
 
 
 
 
 
 
107
  # Convert PDF to images
108
- print(f"πŸ“„ Converting PDF pages to images (DPI: {dpi})...")
109
  try:
110
  page_images = pdf_to_images(str(pdf_path), dpi=dpi)
111
  print(f"βœ“ Converted {len(page_images)} page(s) to images\n")
@@ -126,12 +183,13 @@ def process_pdf_pipeline(
126
  temp_img_path = temp_dir / f"page_{page_num}.jpg"
127
  cv2.imwrite(str(temp_img_path), img)
128
 
129
- # Process the page
130
  try:
131
  page_result = process_image_pipeline(
132
  str(temp_img_path),
133
  output_dir=output_dir,
134
- stamp_model_path=stamp_model_path,
 
135
  stamp_conf=stamp_conf,
136
  save_intermediate=save_intermediate
137
  )
@@ -189,7 +247,9 @@ def process_image_pipeline(
189
  signature_model_path: Optional[str] = None,
190
  stamp_model_path: str = "stamp_detector/stamp_model.pt",
191
  stamp_conf: float = 0.25,
192
- save_intermediate: bool = False
 
 
193
  ) -> Dict[str, Any]:
194
  """
195
  Process a single image through all three detection models.
@@ -254,9 +314,16 @@ def process_image_pipeline(
254
  print(f"\nπŸ”· Step 2/3: Signature Detection")
255
  print("-" * 70)
256
  try:
 
 
 
 
 
 
 
257
  sig_result = detect_signatures(
258
  str(image_path),
259
- model=None, # Will auto-load
260
  output_dir=None, # Don't save
261
  signatures_dir=None, # Don't save
262
  save_crops=False # Don't save crops
@@ -284,13 +351,17 @@ def process_image_pipeline(
284
  print(f"\nπŸ”· Step 3/3: Stamp Detection")
285
  print("-" * 70)
286
  try:
287
- if not Path(stamp_model_path).exists():
288
- raise FileNotFoundError(f"Stamp model not found: {stamp_model_path}")
 
 
 
289
 
290
  stamp_result = detect_stamps_no_save(
291
  str(image_path),
292
  model_path=stamp_model_path,
293
- conf=stamp_conf
 
294
  )
295
 
296
  if stamp_result and stamp_result.get("detections"):
 
31
  from signature.inference import detect_signatures
32
  from stamp_detector.detect import detect_stamps_no_save
33
 
34
+ # Import for model loading
35
+ from ultralytics import YOLO
36
+ import os
37
+
38
 
39
  def pdf_to_images(pdf_path: str, dpi: int = 200) -> List[np.ndarray]:
40
  """
 
72
  return images
73
 
74
 
75
+ def _load_signature_model(signature_model_path: Optional[str] = None):
76
+ """Load signature model once for reuse."""
77
+ from huggingface_hub import hf_hub_download
78
+
79
+ if signature_model_path and Path(signature_model_path).exists():
80
+ model_path = signature_model_path
81
+ else:
82
+ local_model_path = Path("yolov8s.pt")
83
+ if local_model_path.exists():
84
+ model_path = str(local_model_path)
85
+ else:
86
+ try:
87
+ hf_token = os.environ.get("HF_TOKEN") or os.environ.get("HUGGINGFACE_TOKEN")
88
+ model_path = hf_hub_download(
89
+ repo_id="tech4humans/yolov8s-signature-detector",
90
+ filename="yolov8s.pt",
91
+ token=hf_token
92
+ )
93
+ except Exception as e:
94
+ raise RuntimeError(f"Failed to load signature model: {e}")
95
+
96
+ print("πŸ“₯ Loading signature model...")
97
+ model = YOLO(model_path)
98
+ print("βœ“ Signature model loaded")
99
+ return model
100
+
101
+
102
+ def _load_stamp_model(stamp_model_path: str = "stamp_detector/stamp_model.pt"):
103
+ """Load stamp model once for reuse."""
104
+ if not Path(stamp_model_path).exists():
105
+ default_path = Path("stamp_detector/stamp_model.pt")
106
+ if default_path.exists():
107
+ stamp_model_path = str(default_path)
108
+ else:
109
+ raise FileNotFoundError(f"Stamp model not found: {stamp_model_path}")
110
+
111
+ print("πŸ“₯ Loading stamp model...")
112
+ model = YOLO(stamp_model_path)
113
+ print("βœ“ Stamp model loaded")
114
+ return model
115
+
116
+
117
  def process_pdf_pipeline(
118
  pdf_path: str,
119
  output_dir: str = "pipeline_outputs",
120
  stamp_model_path: str = "stamp_detector/stamp_model.pt",
121
  stamp_conf: float = 0.25,
122
  dpi: int = 200,
123
+ save_intermediate: bool = False,
124
+ signature_model_path: Optional[str] = None
125
  ) -> Dict[str, Any]:
126
  """
127
  Process a PDF file by converting each page to an image and running the pipeline.
 
133
  stamp_conf: Confidence threshold for stamp detection
134
  dpi: DPI for PDF to image conversion
135
  save_intermediate: Whether to save intermediate results
136
+ signature_model_path: Path to signature model (optional, will auto-download if not provided)
137
 
138
  Returns:
139
  Combined results dictionary for all pages
 
152
  print(f"Processing PDF: {pdf_path.name}")
153
  print(f"{'='*70}\n")
154
 
155
+ # Load models once before processing pages
156
+ print("πŸ”„ Loading models (this happens once for all pages)...")
157
+ try:
158
+ signature_model = _load_signature_model(signature_model_path)
159
+ stamp_model = _load_stamp_model(stamp_model_path)
160
+ except Exception as e:
161
+ print(f"βœ— Error loading models: {str(e)}")
162
+ raise
163
+
164
  # Convert PDF to images
165
+ print(f"\nπŸ“„ Converting PDF pages to images (DPI: {dpi})...")
166
  try:
167
  page_images = pdf_to_images(str(pdf_path), dpi=dpi)
168
  print(f"βœ“ Converted {len(page_images)} page(s) to images\n")
 
183
  temp_img_path = temp_dir / f"page_{page_num}.jpg"
184
  cv2.imwrite(str(temp_img_path), img)
185
 
186
+ # Process the page with pre-loaded models
187
  try:
188
  page_result = process_image_pipeline(
189
  str(temp_img_path),
190
  output_dir=output_dir,
191
+ signature_model=signature_model,
192
+ stamp_model=stamp_model,
193
  stamp_conf=stamp_conf,
194
  save_intermediate=save_intermediate
195
  )
 
247
  signature_model_path: Optional[str] = None,
248
  stamp_model_path: str = "stamp_detector/stamp_model.pt",
249
  stamp_conf: float = 0.25,
250
+ save_intermediate: bool = False,
251
+ signature_model: Optional[Any] = None,
252
+ stamp_model: Optional[Any] = None
253
  ) -> Dict[str, Any]:
254
  """
255
  Process a single image through all three detection models.
 
314
  print(f"\nπŸ”· Step 2/3: Signature Detection")
315
  print("-" * 70)
316
  try:
317
+ # Use pre-loaded model if provided, otherwise load on demand
318
+ if signature_model is None:
319
+ if signature_model_path:
320
+ signature_model = _load_signature_model(signature_model_path)
321
+ else:
322
+ signature_model = _load_signature_model()
323
+
324
  sig_result = detect_signatures(
325
  str(image_path),
326
+ model=signature_model, # Use pre-loaded model
327
  output_dir=None, # Don't save
328
  signatures_dir=None, # Don't save
329
  save_crops=False # Don't save crops
 
351
  print(f"\nπŸ”· Step 3/3: Stamp Detection")
352
  print("-" * 70)
353
  try:
354
+ # Use pre-loaded model if provided, otherwise load on demand
355
+ if stamp_model is None:
356
+ if not Path(stamp_model_path).exists():
357
+ raise FileNotFoundError(f"Stamp model not found: {stamp_model_path}")
358
+ stamp_model = _load_stamp_model(stamp_model_path)
359
 
360
  stamp_result = detect_stamps_no_save(
361
  str(image_path),
362
  model_path=stamp_model_path,
363
+ conf=stamp_conf,
364
+ model=stamp_model # Pass pre-loaded model
365
  )
366
 
367
  if stamp_result and stamp_result.get("detections"):
stamp_detector/detect.py CHANGED
@@ -9,7 +9,7 @@ import json
9
  from ultralytics import YOLO
10
 
11
 
12
- def detect_stamps_no_save(image_path, model_path="stamp_model.pt", conf=0.25):
13
  """
14
  Detect stamps without saving images.
15
 
@@ -17,27 +17,30 @@ def detect_stamps_no_save(image_path, model_path="stamp_model.pt", conf=0.25):
17
  image_path: Path to input image
18
  model_path: Path to model (or will download from HF Hub if not found)
19
  conf: Confidence threshold
 
20
 
21
  Returns:
22
  dict: Detection results with detections and image_size
23
  """
24
- # Load model - try to download from HF Hub if not found locally
25
- if not os.path.exists(model_path):
26
- # Try to download from Hugging Face Hub
27
- try:
28
- from huggingface_hub import hf_hub_download
29
- print(f"Model not found locally, attempting to download from HF Hub...")
30
- # You can upload your model to HF Hub and use it here
31
- # For now, try the default path in stamp_detector directory
32
- default_path = os.path.join("stamp_detector", "stamp_model.pt")
33
- if os.path.exists(default_path):
34
- model_path = default_path
35
- else:
36
- raise FileNotFoundError(f"Stamp model not found: {model_path}. Please upload stamp_model.pt to the Space.")
37
- except ImportError:
38
- raise FileNotFoundError(f"Stamp model not found: {model_path}")
39
-
40
- model = YOLO(model_path)
 
 
41
 
42
  # Load image
43
  if not os.path.exists(image_path):
 
9
  from ultralytics import YOLO
10
 
11
 
12
+ def detect_stamps_no_save(image_path, model_path="stamp_model.pt", conf=0.25, model=None):
13
  """
14
  Detect stamps without saving images.
15
 
 
17
  image_path: Path to input image
18
  model_path: Path to model (or will download from HF Hub if not found)
19
  conf: Confidence threshold
20
+ model: Pre-loaded YOLO model (optional, will load if not provided)
21
 
22
  Returns:
23
  dict: Detection results with detections and image_size
24
  """
25
+ # Use pre-loaded model if provided, otherwise load model
26
+ if model is None:
27
+ # Load model - try to download from HF Hub if not found locally
28
+ if not os.path.exists(model_path):
29
+ # Try to download from Hugging Face Hub
30
+ try:
31
+ from huggingface_hub import hf_hub_download
32
+ print(f"Model not found locally, attempting to download from HF Hub...")
33
+ # You can upload your model to HF Hub and use it here
34
+ # For now, try the default path in stamp_detector directory
35
+ default_path = os.path.join("stamp_detector", "stamp_model.pt")
36
+ if os.path.exists(default_path):
37
+ model_path = default_path
38
+ else:
39
+ raise FileNotFoundError(f"Stamp model not found: {model_path}. Please upload stamp_model.pt to the Space.")
40
+ except ImportError:
41
+ raise FileNotFoundError(f"Stamp model not found: {model_path}")
42
+
43
+ model = YOLO(model_path)
44
 
45
  # Load image
46
  if not os.path.exists(image_path):