Update app.py
Browse files
app.py
CHANGED
|
@@ -14,6 +14,10 @@ from scipy.spatial import distance as dist
|
|
| 14 |
# App Configuration & Model Loading
|
| 15 |
# ==============================================================================
|
| 16 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
# Set Streamlit page configuration
|
| 18 |
st.set_page_config(
|
| 19 |
page_title="Document Scanner & Table Recognizer",
|
|
@@ -34,9 +38,8 @@ def load_model():
|
|
| 34 |
processor, model = load_model()
|
| 35 |
|
| 36 |
# ==============================================================================
|
| 37 |
-
# Core Image Processing Functions
|
| 38 |
# ==============================================================================
|
| 39 |
-
# (These are the helper functions from the original script)
|
| 40 |
|
| 41 |
def order_points(pts):
|
| 42 |
xSorted = pts[np.argsort(pts[:, 0]), :]
|
|
@@ -77,8 +80,15 @@ def correct_orientation(image):
|
|
| 77 |
try:
|
| 78 |
osd = pytesseract.image_to_osd(image, output_type=pytesseract.Output.DICT)
|
| 79 |
rotation = osd['rotate']
|
| 80 |
-
if rotation
|
| 81 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 82 |
return rotated_image
|
| 83 |
except Exception as e:
|
| 84 |
st.warning(f"OSD check failed: {e}. Returning original image.")
|
|
@@ -88,7 +98,7 @@ def extract_and_draw_table_structure(image_bgr):
|
|
| 88 |
"""Takes a BGR image, finds table structure, and returns an image with boxes."""
|
| 89 |
image_pil = Image.fromarray(cv2.cvtColor(image_bgr, cv2.COLOR_BGR2RGB))
|
| 90 |
inputs = processor(images=image_pil, return_tensors="pt")
|
| 91 |
-
|
| 92 |
with torch.no_grad():
|
| 93 |
outputs = model(**inputs)
|
| 94 |
|
|
@@ -96,7 +106,6 @@ def extract_and_draw_table_structure(image_bgr):
|
|
| 96 |
target_sizes = torch.tensor([image_pil.size[::-1]])
|
| 97 |
results = processor.post_process_object_detection(outputs, threshold=0.7, target_sizes=target_sizes)[0]
|
| 98 |
|
| 99 |
-
# Use Matplotlib to draw on the image
|
| 100 |
fig, ax = plt.subplots(1, figsize=(width / 100, height / 100), dpi=100)
|
| 101 |
ax.imshow(image_pil)
|
| 102 |
ax.axis('off')
|
|
@@ -110,7 +119,8 @@ def extract_and_draw_table_structure(image_bgr):
|
|
| 110 |
ax.add_patch(rect)
|
| 111 |
|
| 112 |
fig.canvas.draw()
|
| 113 |
-
|
|
|
|
| 114 |
img_with_boxes = img_with_boxes.reshape(fig.canvas.get_width_height()[::-1] + (3,))
|
| 115 |
plt.close(fig)
|
| 116 |
return img_with_boxes
|
|
@@ -125,32 +135,29 @@ st.write("Upload a document photo. The app will automatically straighten it, fix
|
|
| 125 |
uploaded_file = st.file_uploader("Choose a document image...", type=["jpg", "jpeg", "png"])
|
| 126 |
|
| 127 |
if uploaded_file is not None:
|
| 128 |
-
# Convert the uploaded file to an OpenCV image
|
| 129 |
file_bytes = np.asarray(bytearray(uploaded_file.read()), dtype=np.uint8)
|
| 130 |
-
input_image = cv2.imdecode(file_bytes, 1)
|
| 131 |
input_image_rgb = cv2.cvtColor(input_image, cv2.COLOR_BGR2RGB)
|
| 132 |
|
| 133 |
st.subheader("1. Original Image")
|
| 134 |
-
|
|
|
|
| 135 |
|
| 136 |
with st.spinner("Processing your document... This may take a moment."):
|
| 137 |
-
# Step 1: Straighten and orient the document
|
| 138 |
straightened_image = find_and_straighten_document(input_image)
|
| 139 |
-
image_to_process = straightened_image if straightened_image is not None else input_image
|
| 140 |
final_image = correct_orientation(image_to_process)
|
| 141 |
final_image_rgb = cv2.cvtColor(final_image, cv2.COLOR_BGR2RGB)
|
| 142 |
|
| 143 |
-
# Step 2: Extract table structure
|
| 144 |
image_with_structure = extract_and_draw_table_structure(final_image)
|
| 145 |
|
| 146 |
st.subheader("2. Corrected Document & Detected Structure")
|
| 147 |
col1, col2 = st.columns(2)
|
| 148 |
|
| 149 |
with col1:
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
# Convert to bytes for the download button
|
| 154 |
_, buf = cv2.imencode(".jpg", final_image)
|
| 155 |
st.download_button(
|
| 156 |
label="Download Clean Image",
|
|
@@ -160,4 +167,5 @@ if uploaded_file is not None:
|
|
| 160 |
)
|
| 161 |
|
| 162 |
with col2:
|
| 163 |
-
|
|
|
|
|
|
| 14 |
# App Configuration & Model Loading
|
| 15 |
# ==============================================================================
|
| 16 |
|
| 17 |
+
# For Hugging Face Spaces deployment, you also need these two files:
|
| 18 |
+
# 1. requirements.txt (listing all Python libraries)
|
| 19 |
+
# 2. packages.txt (containing the line "tesseract-ocr")
|
| 20 |
+
|
| 21 |
# Set Streamlit page configuration
|
| 22 |
st.set_page_config(
|
| 23 |
page_title="Document Scanner & Table Recognizer",
|
|
|
|
| 38 |
processor, model = load_model()
|
| 39 |
|
| 40 |
# ==============================================================================
|
| 41 |
+
# Core Image Processing Functions
|
| 42 |
# ==============================================================================
|
|
|
|
| 43 |
|
| 44 |
def order_points(pts):
|
| 45 |
xSorted = pts[np.argsort(pts[:, 0]), :]
|
|
|
|
| 80 |
try:
|
| 81 |
osd = pytesseract.image_to_osd(image, output_type=pytesseract.Output.DICT)
|
| 82 |
rotation = osd['rotate']
|
| 83 |
+
if rotation in [90, 180, 270]:
|
| 84 |
+
# The rotation values from Tesseract are counter-clockwise.
|
| 85 |
+
# OpenCV's rotation constants are clockwise. We need to map them correctly.
|
| 86 |
+
if rotation == 90:
|
| 87 |
+
rotated_image = cv2.rotate(image, cv2.ROTATE_90_COUNTERCLOCKWISE)
|
| 88 |
+
elif rotation == 180:
|
| 89 |
+
rotated_image = cv2.rotate(image, cv2.ROTATE_180)
|
| 90 |
+
else: # 270
|
| 91 |
+
rotated_image = cv2.rotate(image, cv2.ROTATE_90_CLOCKWISE)
|
| 92 |
return rotated_image
|
| 93 |
except Exception as e:
|
| 94 |
st.warning(f"OSD check failed: {e}. Returning original image.")
|
|
|
|
| 98 |
"""Takes a BGR image, finds table structure, and returns an image with boxes."""
|
| 99 |
image_pil = Image.fromarray(cv2.cvtColor(image_bgr, cv2.COLOR_BGR2RGB))
|
| 100 |
inputs = processor(images=image_pil, return_tensors="pt")
|
| 101 |
+
|
| 102 |
with torch.no_grad():
|
| 103 |
outputs = model(**inputs)
|
| 104 |
|
|
|
|
| 106 |
target_sizes = torch.tensor([image_pil.size[::-1]])
|
| 107 |
results = processor.post_process_object_detection(outputs, threshold=0.7, target_sizes=target_sizes)[0]
|
| 108 |
|
|
|
|
| 109 |
fig, ax = plt.subplots(1, figsize=(width / 100, height / 100), dpi=100)
|
| 110 |
ax.imshow(image_pil)
|
| 111 |
ax.axis('off')
|
|
|
|
| 119 |
ax.add_patch(rect)
|
| 120 |
|
| 121 |
fig.canvas.draw()
|
| 122 |
+
# FIX: Replaced deprecated 'tostring_rgb' with 'tobytes_rgb'
|
| 123 |
+
img_with_boxes = np.frombuffer(fig.canvas.tobytes_rgb(), dtype=np.uint8)
|
| 124 |
img_with_boxes = img_with_boxes.reshape(fig.canvas.get_width_height()[::-1] + (3,))
|
| 125 |
plt.close(fig)
|
| 126 |
return img_with_boxes
|
|
|
|
| 135 |
uploaded_file = st.file_uploader("Choose a document image...", type=["jpg", "jpeg", "png"])
|
| 136 |
|
| 137 |
if uploaded_file is not None:
|
|
|
|
| 138 |
file_bytes = np.asarray(bytearray(uploaded_file.read()), dtype=np.uint8)
|
| 139 |
+
input_image = cv2.imdecode(file_bytes, 1)
|
| 140 |
input_image_rgb = cv2.cvtColor(input_image, cv2.COLOR_BGR2RGB)
|
| 141 |
|
| 142 |
st.subheader("1. Original Image")
|
| 143 |
+
# FIX: Replaced deprecated 'use_column_width' with 'use_container_width'
|
| 144 |
+
st.image(input_image_rgb, caption="Your Uploaded Image", use_container_width=True)
|
| 145 |
|
| 146 |
with st.spinner("Processing your document... This may take a moment."):
|
|
|
|
| 147 |
straightened_image = find_and_straighten_document(input_image)
|
| 148 |
+
image_to_process = straightened_image if straightened_image is not None and straightened_image.size > 0 else input_image
|
| 149 |
final_image = correct_orientation(image_to_process)
|
| 150 |
final_image_rgb = cv2.cvtColor(final_image, cv2.COLOR_BGR2RGB)
|
| 151 |
|
|
|
|
| 152 |
image_with_structure = extract_and_draw_table_structure(final_image)
|
| 153 |
|
| 154 |
st.subheader("2. Corrected Document & Detected Structure")
|
| 155 |
col1, col2 = st.columns(2)
|
| 156 |
|
| 157 |
with col1:
|
| 158 |
+
# FIX: Replaced deprecated 'use_column_width' with 'use_container_width'
|
| 159 |
+
st.image(final_image_rgb, caption="Auto-Corrected & Oriented", use_container_width=True)
|
| 160 |
+
|
|
|
|
| 161 |
_, buf = cv2.imencode(".jpg", final_image)
|
| 162 |
st.download_button(
|
| 163 |
label="Download Clean Image",
|
|
|
|
| 167 |
)
|
| 168 |
|
| 169 |
with col2:
|
| 170 |
+
# FIX: Replaced deprecated 'use_column_width' with 'use_container_width'
|
| 171 |
+
st.image(image_with_structure, caption="Detected Table Structure (Rows: Green, Columns: Red)", use_container_width=True)
|