AMontiB commited on
Commit
0b2abd8
·
1 Parent(s): ac2a7d8

deal with large images

Browse files
Files changed (4) hide show
  1. __pycache__/app.cpython-310.pyc +0 -0
  2. app.py +54 -2
  3. test_cleanup.py +56 -0
  4. test_crop.py +44 -0
__pycache__/app.cpython-310.pyc CHANGED
Binary files a/__pycache__/app.cpython-310.pyc and b/__pycache__/app.cpython-310.pyc differ
 
app.py CHANGED
@@ -5,6 +5,7 @@ import sys
5
  import json
6
  import argparse
7
  from types import SimpleNamespace
 
8
 
9
  # Try to import detector - if this fails, we'll show an error in the UI
10
  try:
@@ -30,6 +31,42 @@ if os.environ.get("SPACE_ID"):
30
  # Available detectors based on launcher.py
31
  DETECTORS = ['R50_TF', 'R50_nodown', 'CLIP-D', 'P2G', 'NPR']
32
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  def predict(image_path, detector_name):
34
  # Check if detector is available
35
  if not DETECTOR_AVAILABLE:
@@ -42,12 +79,20 @@ def predict(image_path, detector_name):
42
  if not image_path:
43
  return json.dumps({"error": "Please upload an image."}, indent=2)
44
 
 
 
 
 
 
 
 
 
45
  # Create a temporary output file path
46
  output_path = "temp_result.json"
47
 
48
  # Mock args object
49
  args = SimpleNamespace(
50
- image=image_path,
51
  detector=detector_name,
52
  config_dir='configs',
53
  output=output_path,
@@ -99,6 +144,13 @@ def predict(image_path, detector_name):
99
  # Cleanup
100
  if os.path.exists(output_path):
101
  os.remove(output_path)
 
 
 
 
 
 
 
102
 
103
  # Create Gradio Interface
104
  # Use theme only if gradio version supports it
@@ -119,7 +171,7 @@ with demo:
119
  * **Elapsed Time**: The time the model needed to make the prediction (excluding preprocessing or model building).
120
 
121
  ### Note
122
- ⚠️ Due to file size limitations, model weights need to be downloaded automatically on first use. This may take a few moments.
123
  ⚠️ To provide a free service, all models run on CPU.The detection process may take a few seconds, depending on the image size and the selected detector.
124
  """)
125
 
 
5
  import json
6
  import argparse
7
  from types import SimpleNamespace
8
+ from PIL import Image
9
 
10
  # Try to import detector - if this fails, we'll show an error in the UI
11
  try:
 
31
  # Available detectors based on launcher.py
32
  DETECTORS = ['R50_TF', 'R50_nodown', 'CLIP-D', 'P2G', 'NPR']
33
 
34
+ def process_image(image_path):
35
+ """
36
+ Check if image is larger than 1024x1024 and central crop it if necessary.
37
+ Returns the path to the processed image (or original if no change).
38
+ """
39
+ try:
40
+ with Image.open(image_path) as img:
41
+ width, height = img.size
42
+
43
+ # Check if both dimensions are larger than 1024
44
+ if width > 1024 and height > 1024:
45
+ print(f"Image size {width}x{height} exceeds 1024x1024. Performing central crop.")
46
+
47
+ # Calculate crop box
48
+ left = (width - 1024) / 2
49
+ top = (height - 1024) / 2
50
+ right = (width + 1024) / 2
51
+ bottom = (height + 1024) / 2
52
+
53
+ # Crop
54
+ img_cropped = img.crop((left, top, right, bottom))
55
+
56
+ # Save to new path
57
+ directory, filename = os.path.split(image_path)
58
+ name, ext = os.path.splitext(filename)
59
+ new_filename = f"{name}_cropped{ext}"
60
+ new_path = os.path.join(directory, new_filename)
61
+
62
+ img_cropped.save(new_path)
63
+ return new_path
64
+
65
+ return image_path
66
+ except Exception as e:
67
+ print(f"Error processing image: {e}")
68
+ return image_path
69
+
70
  def predict(image_path, detector_name):
71
  # Check if detector is available
72
  if not DETECTOR_AVAILABLE:
 
79
  if not image_path:
80
  return json.dumps({"error": "Please upload an image."}, indent=2)
81
 
82
+ # Process image (central crop if too large)
83
+ processed_path = image_path
84
+ try:
85
+ processed_path = process_image(image_path)
86
+ except Exception as e:
87
+ print(f"Warning: Image processing failed: {e}")
88
+ # Continue with original image if processing fails
89
+
90
  # Create a temporary output file path
91
  output_path = "temp_result.json"
92
 
93
  # Mock args object
94
  args = SimpleNamespace(
95
+ image=processed_path,
96
  detector=detector_name,
97
  config_dir='configs',
98
  output=output_path,
 
144
  # Cleanup
145
  if os.path.exists(output_path):
146
  os.remove(output_path)
147
+
148
+ # Cleanup cropped image if it's different from original
149
+ if processed_path != image_path and os.path.exists(processed_path):
150
+ try:
151
+ os.remove(processed_path)
152
+ except Exception as e:
153
+ print(f"Warning: Could not remove temporary file {processed_path}: {e}")
154
 
155
  # Create Gradio Interface
156
  # Use theme only if gradio version supports it
 
171
  * **Elapsed Time**: The time the model needed to make the prediction (excluding preprocessing or model building).
172
 
173
  ### Note
174
+ ⚠️ Due to file size limitations, model weights need to be downloaded automatically on first use. This may take a few moments. \
175
  ⚠️ To provide a free service, all models run on CPU.The detection process may take a few seconds, depending on the image size and the selected detector.
176
  """)
177
 
test_cleanup.py ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import json
3
+ from PIL import Image
4
+ from app import predict, process_image
5
+
6
+ # Mock DETECTOR_AVAILABLE to avoid import errors during test
7
+ import app
8
+ app.DETECTOR_AVAILABLE = True
9
+ app.run_detect = lambda args: None # Mock run_detect
10
+
11
+ def test_cleanup():
12
+ # Create a large dummy image
13
+ large_img_path = "test_large_cleanup.png"
14
+ Image.new('RGB', (2000, 2000), color='green').save(large_img_path)
15
+
16
+ # Create a dummy output file because predict expects it
17
+ output_path = "temp_result.json"
18
+ with open(output_path, 'w') as f:
19
+ json.dump({"prediction": "real", "confidence": 0.9, "elapsed_time": 0.1}, f)
20
+
21
+ # We need to monkeypatch process_image to track the file it creates
22
+ original_process_image = app.process_image
23
+ created_files = []
24
+
25
+ def tracked_process_image(path):
26
+ new_path = original_process_image(path)
27
+ if new_path != path:
28
+ created_files.append(new_path)
29
+ return new_path
30
+
31
+ app.process_image = tracked_process_image
32
+
33
+ # Run predict
34
+ try:
35
+ print("Running predict...")
36
+ app.predict(large_img_path, "R50_TF")
37
+ except Exception as e:
38
+ print(f"Predict failed: {e}")
39
+
40
+ # Check if cropped file was created
41
+ assert len(created_files) > 0, "Should have created a cropped file"
42
+ cropped_path = created_files[0]
43
+ print(f"Cropped path was: {cropped_path}")
44
+
45
+ # Check if cropped file was deleted
46
+ assert not os.path.exists(cropped_path), f"Cropped file {cropped_path} should have been deleted"
47
+ print("Cleanup test passed!")
48
+
49
+ # Cleanup original
50
+ if os.path.exists(large_img_path):
51
+ os.remove(large_img_path)
52
+ if os.path.exists(output_path):
53
+ os.remove(output_path)
54
+
55
+ if __name__ == "__main__":
56
+ test_cleanup()
test_crop.py ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from PIL import Image
3
+ from app import process_image
4
+
5
+ def test_process_image():
6
+ # Create a large dummy image
7
+ large_img_path = "test_large.png"
8
+ Image.new('RGB', (2000, 2000), color='red').save(large_img_path)
9
+
10
+ # Process it
11
+ processed_path = process_image(large_img_path)
12
+
13
+ # Check if a new file was created
14
+ assert processed_path != large_img_path, "Should have returned a new path"
15
+ assert "cropped" in processed_path, "New path should contain 'cropped'"
16
+
17
+ # Check dimensions
18
+ with Image.open(processed_path) as img:
19
+ assert img.size == (1024, 1024), f"Expected 1024x1024, got {img.size}"
20
+
21
+ print("Large image test passed!")
22
+
23
+ # Create a small dummy image
24
+ small_img_path = "test_small.png"
25
+ Image.new('RGB', (800, 800), color='blue').save(small_img_path)
26
+
27
+ # Process it
28
+ processed_path_small = process_image(small_img_path)
29
+
30
+ # Check if it returned the same path
31
+ assert processed_path_small == small_img_path, "Should have returned original path"
32
+
33
+ print("Small image test passed!")
34
+
35
+ # Cleanup
36
+ if os.path.exists(large_img_path):
37
+ os.remove(large_img_path)
38
+ if os.path.exists(processed_path):
39
+ os.remove(processed_path)
40
+ if os.path.exists(small_img_path):
41
+ os.remove(small_img_path)
42
+
43
+ if __name__ == "__main__":
44
+ test_process_image()