File size: 9,445 Bytes
717c92d |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 |
import streamlit as st
from pathlib import Path
from io import BytesIO
from PIL import Image, UnidentifiedImageError
import matplotlib.pyplot as plt
from imgshape.shape import get_shape
from imgshape.analyze import analyze_type
from imgshape.recommender import recommend_preprocessing
from imgshape.augmentations import AugmentationRecommender
from imgshape.report import generate_markdown_report, generate_html_report
from imgshape.viz import plot_shape_distribution
from imgshape.torchloader import to_torch_transform
# Page config
st.set_page_config(page_title="imgshape v2.1.3", layout="wide")
st.title("πΌοΈ imgshape β Smart Dataset Assistant (v2.1.3)")
st.markdown(
"Upload an image or provide a dataset folder to analyze, "
"recommend preprocessing, generate reports, and even get PyTorch transforms."
)
# Sidebar for inputs
st.sidebar.header("π Input")
uploaded_file = st.sidebar.file_uploader(
"Upload an image", type=["jpg", "jpeg", "png", "bmp", "tiff"]
)
dataset_path = st.sidebar.text_input("Dataset folder path", "assets/sample_images")
tabs = st.tabs(["π Shape", "π Analyze", "π§ Recommend", "π Report", "π TorchLoader"])
# ------------------------- helpers -------------------------
def cache_uploaded_bytes():
"""
Read uploaded_file once and cache raw bytes in session_state['uploaded_bytes'].
Returns bytes or None.
"""
if uploaded_file is None:
return None
if "uploaded_bytes" not in st.session_state:
try:
st.session_state["uploaded_bytes"] = uploaded_file.read()
except Exception as e:
st.session_state["uploaded_bytes"] = None
st.error(f"Error reading upload: {e}")
return None
return st.session_state["uploaded_bytes"]
def load_uploaded_image_from_bytes(bytes_data):
"""
Build fresh BytesIO and PIL.Image from raw bytes.
Returns (PIL.Image, BytesIO) or (None, None) on error.
"""
if not bytes_data:
return None, None
try:
buf = BytesIO(bytes_data)
pil_img = Image.open(BytesIO(bytes_data)).convert("RGB")
return pil_img, buf
except UnidentifiedImageError:
return None, None
except Exception as e:
st.error(f"Unexpected error opening image: {e}")
return None, None
# ------------------------- SHAPE TAB -------------------------
with tabs[0]:
st.subheader("π Shape Detection")
bytes_data = cache_uploaded_bytes()
if bytes_data:
pil_img, buf = load_uploaded_image_from_bytes(bytes_data)
if pil_img is None:
st.error("Uploaded file is not a valid image. Please upload a PNG/JPEG/etc.")
else:
st.image(pil_img, caption="Uploaded Image", use_column_width=True)
try:
# get_shape accepts a PIL.Image or path depending on implementation
shape = get_shape(pil_img)
st.json({"shape": shape})
except Exception as e:
st.error(f"Error in shape detection: {e}")
else:
st.info("Upload an image to see its shape.")
# ------------------------- ANALYZE TAB -------------------------
with tabs[1]:
st.subheader("π Image Analysis")
bytes_data = cache_uploaded_bytes()
if bytes_data:
pil_img, buf = load_uploaded_image_from_bytes(bytes_data)
if pil_img is None:
st.error("Uploaded file is not a valid image. Please upload a PNG/JPEG/etc.")
else:
buf.seek(0)
try:
analysis = analyze_type(buf)
st.json(analysis)
except Exception as e:
st.error(f"Error in analysis: {e}")
else:
st.info("Upload an image to analyze.")
st.subheader("π Dataset Visualization")
if st.button("Plot Shape Distribution"):
try:
fig = plt.figure()
plot_shape_distribution(dataset_path, save=False)
st.pyplot(fig)
except Exception as e:
st.error(f"Error plotting dataset: {e}")
# ------------------------- RECOMMEND TAB -------------------------
with tabs[2]:
st.subheader("π§ Preprocessing + Augmentation Recommendations")
bytes_data = cache_uploaded_bytes()
if bytes_data:
pil_img, buf = load_uploaded_image_from_bytes(bytes_data)
if pil_img is None:
st.error("Uploaded file is not a valid image. Please upload a PNG/JPEG/etc.")
else:
try:
rec = recommend_preprocessing(pil_img) # β
pass PIL.Image
st.json({"preprocessing": rec})
except Exception as e:
st.error(f"Error in preprocessing recommendation: {e}")
# Augmentation plan
try:
ar = AugmentationRecommender(seed=42)
buf.seek(0)
analysis = analyze_type(buf) # still safe with BytesIO
plan = ar.recommend_for_dataset(
{"entropy_mean": analysis.get("entropy", 5.0), "image_count": 1}
)
st.json({
"augmentation_plan": {
"order": plan.recommended_order,
"augmentations": [a.__dict__ for a in plan.augmentations]
}
})
except Exception as e:
st.error(f"Error in augmentation plan: {e}")
else:
st.info("Upload an image to get recommendations.")
# ------------------------- REPORT TAB -------------------------
with tabs[3]:
st.subheader("π Dataset Report")
if st.button("Generate Markdown + HTML Report"):
try:
stats = {"image_count": 1, "source_dir": dataset_path}
rec = {}
bytes_data = cache_uploaded_bytes()
if bytes_data:
# use bytes for preprocessing recommendation
_, buf = load_uploaded_image_from_bytes(bytes_data)
if buf is not None:
buf.seek(0)
rec = recommend_preprocessing(buf)
ar = AugmentationRecommender(seed=42)
plan = ar.recommend_for_dataset({"entropy_mean": 5.0, "image_count": 10})
md_path = Path("report.md")
html_path = Path("report.html")
generate_markdown_report(
md_path, stats, {}, rec,
{"augmentations": [a.__dict__ for a in plan.augmentations]}
)
generate_html_report(md_path, html_path)
st.success("Reports generated!")
st.download_button("β¬οΈ Download Markdown", md_path.read_text(), file_name="report.md")
st.download_button("β¬οΈ Download HTML", html_path.read_text(), file_name="report.html")
except Exception as e:
st.error(f"Error generating report: {e}")
# ------------------------- TORCHLOADER TAB -------------------------
with tabs[4]:
st.subheader("π TorchLoader Export")
bytes_data = cache_uploaded_bytes()
if bytes_data:
pil_img, buf = load_uploaded_image_from_bytes(bytes_data)
if pil_img is None:
st.error("Uploaded file is not a valid image. Please upload a PNG/JPEG/etc.")
else:
try:
rec = recommend_preprocessing(pil_img) # β
use PIL.Image
snippet_or_transform = to_torch_transform({}, rec)
if isinstance(snippet_or_transform, str):
st.code(snippet_or_transform, language="python")
else:
st.success("β
torchvision.transforms.Compose object created")
st.write(snippet_or_transform)
except Exception as e:
st.error(f"Error building Torch transform: {e}")
else:
st.info("Upload an image to export Torch transforms.")
# ------------------------- FOOTER -------------------------
st.markdown("---")
st.markdown(
"""
<div style="text-align: center;">
<p><b>Connect with me</b></p>
<a href="https://instagram.com/stifler.xd" target="_blank" style="margin: 0 10px; text-decoration: none;">
<img src="https://cdn-icons-png.flaticon.com/512/2111/2111463.png" width="30"/> Instagram
</a>
<a href="https://github.com/STiFLeR7" target="_blank" style="margin: 0 10px; text-decoration: none;">
<img src="https://cdn-icons-png.flaticon.com/512/733/733553.png" width="30"/> GitHub
</a>
<a href="https://huggingface.co/STiFLeR7" target="_blank" style="margin: 0 10px; text-decoration: none;">
<img src="https://huggingface.co/front/assets/huggingface_logo-noborder.svg" width="30"/> HuggingFace
</a>
<a href="https://medium.com/@stiflerxd" target="_blank" style="margin: 0 10px; text-decoration: none;">
<img src="https://cdn-icons-png.flaticon.com/512/5968/5968906.png" width="30"/> Medium
</a>
<a href="https://www.kaggle.com/stiflerxd" target="_blank" style="margin: 0 10px; text-decoration: none;">
<img src="https://cdn-icons-png.flaticon.com/512/2111/2111290.png" width="30"/> Kaggle
</a>
<br><br>
π§ <a href="mailto:hillaniljppatel@gmail.com">hillaniljppatel@gmail.com</a> |
π <a href="https://hillpatel.tech" target="_blank">hillpatel.tech</a>
</div>
""",
unsafe_allow_html=True
) |