Spaces:
Running
Running
muhammadhamza-stack
commited on
Commit
·
1ff1745
1
Parent(s):
78f8def
dockerize the app
Browse files- .gitattributes +1 -0
- .gitignore +4 -0
- Dockerfile +25 -0
- README.md +1 -1
- app.py +92 -52
- requirements.txt +9 -5
- sample_data/papertest1.jpg +3 -0
- sample_data/papertest2.jpg +3 -0
- sample_data/papertest3.JPG +3 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
*.jpg filter=lfs diff=lfs merge=lfs -text
|
.gitignore
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
venv
|
| 2 |
+
outputs
|
| 3 |
+
.cache
|
| 4 |
+
debug
|
Dockerfile
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FROM python:3.9-slim
|
| 2 |
+
|
| 3 |
+
ENV PYTHONDONTWRITEBYTECODE=1
|
| 4 |
+
ENV PYTHONUNBUFFERED=1
|
| 5 |
+
|
| 6 |
+
WORKDIR /app
|
| 7 |
+
|
| 8 |
+
# Required for OpenCV image display & ultralytics
|
| 9 |
+
RUN apt-get update && apt-get install -y \
|
| 10 |
+
libgl1 \
|
| 11 |
+
libglib2.0-0 \
|
| 12 |
+
git \
|
| 13 |
+
curl \
|
| 14 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 15 |
+
|
| 16 |
+
COPY requirements.txt .
|
| 17 |
+
|
| 18 |
+
RUN pip install --upgrade pip \
|
| 19 |
+
&& pip install --no-cache-dir -r requirements.txt
|
| 20 |
+
|
| 21 |
+
COPY . .
|
| 22 |
+
|
| 23 |
+
EXPOSE 7860
|
| 24 |
+
|
| 25 |
+
CMD ["python", "app.py"]
|
README.md
CHANGED
|
@@ -3,7 +3,7 @@ title: Contour Detection Paper
|
|
| 3 |
emoji: 👀
|
| 4 |
colorFrom: pink
|
| 5 |
colorTo: blue
|
| 6 |
-
sdk:
|
| 7 |
# sdk_version: 5.41.1
|
| 8 |
sdk_version: 5.42.0
|
| 9 |
python_version: 3.12.0
|
|
|
|
| 3 |
emoji: 👀
|
| 4 |
colorFrom: pink
|
| 5 |
colorTo: blue
|
| 6 |
+
sdk: docker
|
| 7 |
# sdk_version: 5.41.1
|
| 8 |
sdk_version: 5.42.0
|
| 9 |
python_version: 3.12.0
|
app.py
CHANGED
|
@@ -1032,43 +1032,83 @@ def predict_full_paper(image, paper_size, offset_value_mm = 0.02,offset_unit='mm
|
|
| 1032 |
scale_info # Always return scaling info
|
| 1033 |
)
|
| 1034 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1035 |
# Gradio Interface
|
| 1036 |
if __name__ == "__main__":
|
| 1037 |
os.makedirs("./outputs", exist_ok=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1038 |
|
| 1039 |
with gr.Blocks(title="Paper-Based DXF Generator", theme=gr.themes.Soft()) as demo:
|
| 1040 |
-
|
| 1041 |
-
gr.Markdown(""
|
| 1042 |
-
|
| 1043 |
-
|
| 1044 |
-
|
| 1045 |
-
|
| 1046 |
-
|
| 1047 |
-
|
| 1048 |
-
gr.Markdown(
|
| 1049 |
-
|
| 1050 |
-
|
| 1051 |
-
2. Select the correct paper size
|
| 1052 |
-
3. Configure options as needed
|
| 1053 |
-
4. Click Submit to generate DXF
|
| 1054 |
-
""")
|
| 1055 |
-
gr.Markdown("""
|
| 1056 |
-
### Tips for Best Results:
|
| 1057 |
-
- Ensure good lighting and clear paper edges
|
| 1058 |
-
- Place object completely at the center of the paper
|
| 1059 |
-
- Avoid shadows that might interfere with detection
|
| 1060 |
-
- Use high contrast between object and paper
|
| 1061 |
-
""")
|
| 1062 |
|
| 1063 |
|
| 1064 |
with gr.Row():
|
| 1065 |
with gr.Column():
|
|
|
|
| 1066 |
input_image = gr.Image(
|
| 1067 |
label="Input Image (Object on Paper)",
|
| 1068 |
type="numpy",
|
| 1069 |
height=400
|
| 1070 |
)
|
| 1071 |
-
|
|
|
|
| 1072 |
paper_size = gr.Radio(
|
| 1073 |
choices=["A4", "A3", "US Letter"],
|
| 1074 |
value="A4",
|
|
@@ -1076,42 +1116,23 @@ if __name__ == "__main__":
|
|
| 1076 |
info="Select the paper size used in your image"
|
| 1077 |
)
|
| 1078 |
|
| 1079 |
-
#
|
| 1080 |
-
# gr.Markdown("### Contour Offset")
|
| 1081 |
-
# with gr.Row():
|
| 1082 |
-
# offset_value_mm = gr.Number(
|
| 1083 |
-
# value=0.02,
|
| 1084 |
-
# label="Offset",
|
| 1085 |
-
# info="Expand contours outward by this amount",
|
| 1086 |
-
# precision=3,
|
| 1087 |
-
# minimum=0,
|
| 1088 |
-
# maximum=50
|
| 1089 |
-
# )
|
| 1090 |
-
# offset_unit = gr.Dropdown(
|
| 1091 |
-
# choices=["mm", "inches"],
|
| 1092 |
-
# value="mm",
|
| 1093 |
-
# label="Unit"
|
| 1094 |
-
# )
|
| 1095 |
-
|
| 1096 |
-
# with gr.Group():
|
| 1097 |
-
# gr.Markdown("### Finger Cuts")
|
| 1098 |
-
# enable_finger_cut = gr.Radio(
|
| 1099 |
-
# choices=["On", "Off"],
|
| 1100 |
-
# value="Off",
|
| 1101 |
-
# label="Enable Finger Cuts",
|
| 1102 |
-
# info="Add circular cuts for easier handling"
|
| 1103 |
-
# )
|
| 1104 |
|
| 1105 |
output_options = gr.CheckboxGroup(
|
| 1106 |
choices=["Annotated Image", "Outlines", "Mask"],
|
| 1107 |
-
value=[],
|
| 1108 |
label="Additional Outputs",
|
| 1109 |
info="DXF is always included"
|
| 1110 |
)
|
| 1111 |
|
|
|
|
|
|
|
|
|
|
| 1112 |
submit_btn = gr.Button("Generate DXF", variant="primary", size="lg")
|
| 1113 |
|
|
|
|
| 1114 |
with gr.Column():
|
|
|
|
| 1115 |
with gr.Group():
|
| 1116 |
gr.Markdown("### Generated Files")
|
| 1117 |
dxf_file = gr.File(label="DXF File", file_types=[".dxf"])
|
|
@@ -1119,8 +1140,8 @@ if __name__ == "__main__":
|
|
| 1119 |
|
| 1120 |
with gr.Group():
|
| 1121 |
gr.Markdown("### Preview Images")
|
| 1122 |
-
output_image = gr.Image(label="Annotated Image", visible=
|
| 1123 |
-
outlines_image = gr.Image(label="Outlines", visible=
|
| 1124 |
mask_image = gr.Image(label="Mask", visible=False)
|
| 1125 |
|
| 1126 |
def update_outputs_visibility(selected):
|
|
@@ -1150,6 +1171,25 @@ if __name__ == "__main__":
|
|
| 1150 |
outputs=[dxf_file, output_image, outlines_image, mask_image, scale_info]
|
| 1151 |
)
|
| 1152 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1153 |
|
| 1154 |
|
| 1155 |
-
demo.launch(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1032 |
scale_info # Always return scaling info
|
| 1033 |
)
|
| 1034 |
|
| 1035 |
+
# ---------------------
|
| 1036 |
+
# Documentation Strings for Gradio
|
| 1037 |
+
# ---------------------
|
| 1038 |
+
|
| 1039 |
+
QUICK_START_PAPER = """
|
| 1040 |
+
## 1. Quick Start Guide: From Photo to DXF Cut File
|
| 1041 |
+
This application converts a photograph of a single object placed on a sheet of standard paper (A4, A3, or US Letter) into a precise DXF contour file for CNC cutting. The paper acts as the scale reference.
|
| 1042 |
+
|
| 1043 |
+
1. **Preparation**: Place **only one object** (tool, part, etc.) flat on a sheet of A4, A3, or US Letter paper. Ensure the paper is fully visible and the object is fully within the boundaries of the paper. Use clear, overhead lighting.
|
| 1044 |
+
2. **Upload**: Upload the image in the **Input Image** box.
|
| 1045 |
+
3. **Configure**: Select the correct `Paper Size`. The default clearance is **0.02 mm** with **Finger Cuts Off**.
|
| 1046 |
+
4. **Run**: Click the **"Generate DXF"** button.
|
| 1047 |
+
5. **Download**: Review the previews, then download the final **DXF file** containing the object's profile, accurately scaled.
|
| 1048 |
+
"""
|
| 1049 |
+
|
| 1050 |
+
INPUT_EXPLANATION_PAPER = """
|
| 1051 |
+
## 2. Expected Inputs
|
| 1052 |
+
### Image Requirements
|
| 1053 |
+
* **Paper is Mandatory:** The system uses the known dimensions of the standard paper size (A4, A3, or US Letter) to calculate the real-world scale (mm/pixel).
|
| 1054 |
+
* **Single Object Only:** The system is designed to detect and contour only **one** significant object on the paper. Multiple objects or major fragments will cause an error.
|
| 1055 |
+
* **Placement & Lighting:** The image should be taken from directly above (minimal perspective distortion). Clear, shadow-free lighting is essential.
|
| 1056 |
+
### Processing Parameters (Hardcoded Default Values)
|
| 1057 |
+
| Parameter | Purpose | Default Value | Guidance for Non-Tech Clients |
|
| 1058 |
+
| :--- | :--- | :--- | :--- |
|
| 1059 |
+
| **Paper Size** | The exact size of the paper sheet used in the image. | A4 | Must match the paper you used for accurate scaling. |
|
| 1060 |
+
| **Offset Value** | The amount of space (clearance) added around the object profile. | **0.02 mm** | This minimal buffer ensures the cut is slightly larger than the object. (Cannot be changed in the UI) |
|
| 1061 |
+
| **Finger Cuts** | Adds a small circular cutout for easy object removal. | **Off** | Cannot be changed in the UI. |
|
| 1062 |
+
"""
|
| 1063 |
+
|
| 1064 |
+
OUTPUT_EXPLANATION_PAPER = """
|
| 1065 |
+
## 3. Expected Outputs
|
| 1066 |
+
| Output Field | Description | Purpose |
|
| 1067 |
+
| :--- | :--- | :--- |
|
| 1068 |
+
| **DXF file** | The final vector file containing the object's profile. All coordinates are in millimeters (MM). | Ready to upload to CNC machine software (AutoCAD DXF R2000 format). |
|
| 1069 |
+
| **Scaling Information**| The calculated real-world scale (mm per pixel) determined by the paper reference, plus the offset settings. | Confirmation of measurement accuracy. |
|
| 1070 |
+
| **Annotated Image** | The original image overlaid with the final generated outline (including offset and finger cuts). | Visual confirmation that the detection and sizing are correct relative to the original photo. |
|
| 1071 |
+
| **Outlines**| A clean, scaled, white-background image showing only the outlines (black lines). This visually represents the final geometry exported to the DXF. | Final quality check for shape before CNC cutting. |
|
| 1072 |
+
| **Mask (Technical)** | The binary image used internally to generate the contours after applying segmentation. | Technical output for debugging segmentation issues. |
|
| 1073 |
+
"""
|
| 1074 |
+
|
| 1075 |
# Gradio Interface
|
| 1076 |
if __name__ == "__main__":
|
| 1077 |
os.makedirs("./outputs", exist_ok=True)
|
| 1078 |
+
os.makedirs("./debug", exist_ok=True)
|
| 1079 |
+
|
| 1080 |
+
# Define HIDDEN inputs for the function signature, as requested.
|
| 1081 |
+
# These mimic the original inline hardcoded values.
|
| 1082 |
+
# NOTE: We must use named variables so gr.Examples can reference them.
|
| 1083 |
+
hidden_offset_value = gr.Number(value=0.02, visible=False, label="Hidden Offset Value")
|
| 1084 |
+
hidden_offset_unit = gr.Textbox(value='mm', visible=False, label="Hidden Offset Unit")
|
| 1085 |
+
hidden_enable_finger_cut = gr.Textbox(value='Off', visible=False, label="Hidden Finger Cut")
|
| 1086 |
+
|
| 1087 |
|
| 1088 |
with gr.Blocks(title="Paper-Based DXF Generator", theme=gr.themes.Soft()) as demo:
|
| 1089 |
+
|
| 1090 |
+
gr.Markdown("<h1 style='text-align: center;'> Paper-Based DXF Generator </h1>")
|
| 1091 |
+
gr.Markdown("Upload an image with a single object placed on standard paper (A4, A3, or US Letter). The paper serves as the scale reference.")
|
| 1092 |
+
|
| 1093 |
+
# 1. Guidelines & Instructions (Integrated Documentation)
|
| 1094 |
+
with gr.Accordion("Tips & User Guide", open=False):
|
| 1095 |
+
gr.Markdown(QUICK_START_PAPER)
|
| 1096 |
+
gr.Markdown("---")
|
| 1097 |
+
gr.Markdown(INPUT_EXPLANATION_PAPER)
|
| 1098 |
+
gr.Markdown("---")
|
| 1099 |
+
gr.Markdown(OUTPUT_EXPLANATION_PAPER)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1100 |
|
| 1101 |
|
| 1102 |
with gr.Row():
|
| 1103 |
with gr.Column():
|
| 1104 |
+
gr.Markdown("## Step 1: Upload Image ")
|
| 1105 |
input_image = gr.Image(
|
| 1106 |
label="Input Image (Object on Paper)",
|
| 1107 |
type="numpy",
|
| 1108 |
height=400
|
| 1109 |
)
|
| 1110 |
+
with gr.Column():
|
| 1111 |
+
gr.Markdown("## Step 2: Select Paper Size & Preview Outputs")
|
| 1112 |
paper_size = gr.Radio(
|
| 1113 |
choices=["A4", "A3", "US Letter"],
|
| 1114 |
value="A4",
|
|
|
|
| 1116 |
info="Select the paper size used in your image"
|
| 1117 |
)
|
| 1118 |
|
| 1119 |
+
# Hidden components are defined but not visible in the UI layout
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1120 |
|
| 1121 |
output_options = gr.CheckboxGroup(
|
| 1122 |
choices=["Annotated Image", "Outlines", "Mask"],
|
| 1123 |
+
value=["Annotated Image", "Outlines"],
|
| 1124 |
label="Additional Outputs",
|
| 1125 |
info="DXF is always included"
|
| 1126 |
)
|
| 1127 |
|
| 1128 |
+
with gr.Row():
|
| 1129 |
+
with gr.Column():
|
| 1130 |
+
gr.Markdown("## Step 3: Click Generate DXF ")
|
| 1131 |
submit_btn = gr.Button("Generate DXF", variant="primary", size="lg")
|
| 1132 |
|
| 1133 |
+
with gr.Row():
|
| 1134 |
with gr.Column():
|
| 1135 |
+
gr.Markdown("## Outputs ")
|
| 1136 |
with gr.Group():
|
| 1137 |
gr.Markdown("### Generated Files")
|
| 1138 |
dxf_file = gr.File(label="DXF File", file_types=[".dxf"])
|
|
|
|
| 1140 |
|
| 1141 |
with gr.Group():
|
| 1142 |
gr.Markdown("### Preview Images")
|
| 1143 |
+
output_image = gr.Image(label="Annotated Image", visible=True)
|
| 1144 |
+
outlines_image = gr.Image(label="Outlines", visible=True)
|
| 1145 |
mask_image = gr.Image(label="Mask", visible=False)
|
| 1146 |
|
| 1147 |
def update_outputs_visibility(selected):
|
|
|
|
| 1171 |
outputs=[dxf_file, output_image, outlines_image, mask_image, scale_info]
|
| 1172 |
)
|
| 1173 |
|
| 1174 |
+
# 4. Examples Section
|
| 1175 |
+
gr.Markdown("---")
|
| 1176 |
+
gr.Markdown("## Examples")
|
| 1177 |
+
gr.Examples(
|
| 1178 |
+
examples=[
|
| 1179 |
+
# [Input Image Path, Paper Size, Selected Outputs]
|
| 1180 |
+
# NOTE: The image paths below are placeholders. Ensure these files exist in ./examples/
|
| 1181 |
+
["./sample_data/papertest1.jpg", "A4", ["Annotated Image", "Outlines"]],
|
| 1182 |
+
["./sample_data/papertest2.jpg", "US Letter", ["Annotated Image", "Outlines", "Mask"]],
|
| 1183 |
+
["./sample_data/papertest3.jpg", "A3", ["Annotated Image", "Outlines"]],
|
| 1184 |
+
],
|
| 1185 |
+
inputs=[input_image, paper_size, output_options],
|
| 1186 |
+
label="Click an example to load the image and configuration. Then click 'Generate DXF'."
|
| 1187 |
+
)
|
| 1188 |
+
|
| 1189 |
|
| 1190 |
|
| 1191 |
+
demo.launch(
|
| 1192 |
+
server_name = "0.0.0.0",
|
| 1193 |
+
server_port=7860
|
| 1194 |
+
)
|
| 1195 |
+
|
requirements.txt
CHANGED
|
@@ -5,12 +5,16 @@ pydantic==2.10.6
|
|
| 5 |
opencv-python-headless>=4.8.0
|
| 6 |
opencv-contrib-python-headless>=4.8.0
|
| 7 |
ezdxf==1.3.5
|
| 8 |
-
gradio==5.15.0
|
| 9 |
kornia==0.8.0
|
| 10 |
timm==1.0.14
|
| 11 |
einops==0.8.1
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
|
|
|
| 15 |
shapely
|
| 16 |
-
git+https://github.com/ultralytics/CLIP.git
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
opencv-python-headless>=4.8.0
|
| 6 |
opencv-contrib-python-headless>=4.8.0
|
| 7 |
ezdxf==1.3.5
|
|
|
|
| 8 |
kornia==0.8.0
|
| 9 |
timm==1.0.14
|
| 10 |
einops==0.8.1
|
| 11 |
+
torch==2.2.2
|
| 12 |
+
torchaudio==2.2.2
|
| 13 |
+
torchmetrics==1.8.2
|
| 14 |
+
torchvision==0.17.2
|
| 15 |
shapely
|
| 16 |
+
git+https://github.com/ultralytics/CLIP.git
|
| 17 |
+
Pillow
|
| 18 |
+
numpy<2
|
| 19 |
+
gradio==3.50.2
|
| 20 |
+
gradio-client==0.6.1
|
sample_data/papertest1.jpg
ADDED
|
Git LFS Details
|
sample_data/papertest2.jpg
ADDED
|
Git LFS Details
|
sample_data/papertest3.JPG
ADDED
|
|
Git LFS Details
|