| """Fish Species Classification โ CNN & Transfer Learning (combined Streamlit app).""" |
|
|
| import json |
| import sys |
| from pathlib import Path |
|
|
| import streamlit as st |
|
|
| if "/opt/anaconda3" in sys.executable: |
| st.set_page_config(page_title="Python ortam hatasi", page_icon="โ ๏ธ") |
| st.error( |
| "Bu uygulama Anaconda Python ile calismaz (segmentation fault).\n\n" |
| f"```bash\ncd \"{Path(__file__).resolve().parent}\"\n" |
| f"~/venvs/tensorflow/bin/streamlit run {Path(__file__).name}\n```" |
| ) |
| st.stop() |
|
|
| import numpy as np |
| import tensorflow as tf |
| from PIL import Image |
|
|
| ROOT = Path(__file__).resolve().parent |
|
|
| MODEL_CONFIG = { |
| "Convolutional Neural Networks": { |
| "stem": "fish_cnn", |
| "notebook": "FishClassificationNew.ipynb", |
| }, |
| "Transfer Learning": { |
| "stem": "fish_tl", |
| "notebook": "FishClassificationNew.ipynb", |
| }, |
| } |
|
|
|
|
| def get_preprocess(backbone: str): |
| if backbone == "VGG16": |
| from tensorflow.keras.applications.vgg16 import preprocess_input |
| return preprocess_input |
| if backbone == "ResNet50": |
| from tensorflow.keras.applications.resnet50 import preprocess_input |
| return preprocess_input |
| from tensorflow.keras.applications.xception import preprocess_input |
| return preprocess_input |
|
|
|
|
| @st.cache_resource |
| def load_artifacts(model_key: str): |
| stem = MODEL_CONFIG[model_key]["stem"] |
| models_dir = ROOT |
| for ext in (".h5", ".keras"): |
| path = models_dir / f"{stem}{ext}" |
| if path.is_file(): |
| model = tf.keras.models.load_model(path) |
| break |
| else: |
| raise FileNotFoundError( |
| f"Model not found for {model_key}. Run {MODEL_CONFIG[model_key]['notebook']} first." |
| ) |
| meta_path = models_dir / f"{stem}_meta.json" |
| meta = json.loads(meta_path.read_text(encoding="utf-8")) |
| return model, meta |
|
|
|
|
| def prepare_image(img: Image.Image, meta: dict, model_key: str) -> np.ndarray: |
| size = tuple(meta["img_size"]) |
| arr = np.array(img.convert("RGB").resize(size), dtype=np.float32) |
| arr = np.expand_dims(arr, axis=0) |
| if model_key == "Convolutional Neural Networks": |
| arr = arr / 255.0 |
| else: |
| arr = get_preprocess(meta.get("backbone", "Xception"))(arr) |
| return arr |
|
|
|
|
| st.set_page_config(page_title="Fish Species Classification", page_icon="๐") |
| st.title("Fish Species Classification") |
|
|
| model_type = st.radio( |
| "Model", |
| list(MODEL_CONFIG.keys()), |
| horizontal=True, |
| ) |
|
|
| try: |
| model, meta = load_artifacts(model_type) |
| except FileNotFoundError as e: |
| st.error(str(e)) |
| st.stop() |
|
|
| if model_type == "Transfer Learning": |
| st.caption(f"Backbone: {meta.get('backbone', 'Xception')}") |
| else: |
| st.caption("Custom CNN") |
|
|
| uploaded = st.file_uploader("Upload image (jpg/png)", type=["jpg", "jpeg", "png"]) |
| if uploaded: |
| img = Image.open(uploaded) |
| st.image(img, use_container_width=True) |
| batch = prepare_image(img, meta, model_type) |
| probs = model.predict(batch, verbose=0)[0] |
| idx = int(np.argmax(probs)) |
| label = meta["class_names"][idx] |
| st.success(f"Prediction: **{label}**") |
| st.write(f"Confidence: {probs[idx]:.2%}") |
|
|
|
|