|
import streamlit as st |
|
from transformers import pipeline, AutoImageProcessor |
|
from PIL import Image, ImageDraw |
|
import torch |
|
|
|
st.set_page_config( |
|
page_title="Fraktur Detektion", |
|
layout="wide", |
|
initial_sidebar_state="collapsed" |
|
) |
|
|
|
st.markdown(""" |
|
<style> |
|
.stApp { |
|
background-color: transparent !important; |
|
padding: 0 !important; |
|
} |
|
|
|
[data-theme="light"] { |
|
--background-color: #ffffff; |
|
--text-color: #1f2937; |
|
--border-color: #e5e7eb; |
|
--button-color: #2563eb; |
|
--button-hover: #1d4ed8; |
|
} |
|
|
|
[data-theme="dark"] { |
|
--background-color: #1f2937; |
|
--text-color: #f3f4f6; |
|
--border-color: #4b5563; |
|
--button-color: #3b82f6; |
|
--button-hover: #2563eb; |
|
} |
|
|
|
.stButton > button { |
|
background-color: var(--button-color) !important; |
|
color: white !important; |
|
border: none !important; |
|
padding: 0.5rem 1rem !important; |
|
border-radius: 0.375rem !important; |
|
font-weight: 500 !important; |
|
transition: background-color 0.2s !important; |
|
} |
|
|
|
.stButton > button:hover { |
|
background-color: var(--button-hover) !important; |
|
} |
|
|
|
.block-container { |
|
padding: 0.5rem !important; |
|
max-width: 100% !important; |
|
} |
|
|
|
.stImage > img { |
|
max-height: 250px !important; |
|
width: auto !important; |
|
margin: 0 auto !important; |
|
} |
|
|
|
.result-box { |
|
padding: 0.375rem; |
|
border-radius: 0.375rem; |
|
margin: 0.25rem 0; |
|
background: var(--background-color); |
|
border: 1px solid var(--border-color); |
|
color: var(--text-color); |
|
} |
|
|
|
h2, h3, h4 { |
|
margin: 0.5rem 0 !important; |
|
color: var(--text-color) !important; |
|
font-size: 1rem !important; |
|
} |
|
|
|
#MainMenu, footer, header { |
|
display: none !important; |
|
} |
|
|
|
.uploadedFile { |
|
border: 1px dashed var(--border-color); |
|
border-radius: 0.375rem; |
|
padding: 0.25rem; |
|
} |
|
|
|
.row-widget.stButton { |
|
text-align: center; |
|
margin: 1rem 0; |
|
} |
|
|
|
div[data-testid="stFileUploader"] { |
|
width: 100%; |
|
} |
|
</style> |
|
""", unsafe_allow_html=True) |
|
|
|
@st.cache_resource |
|
def load_models(): |
|
return { |
|
"KnochenAuge": pipeline("object-detection", model="D3STRON/bone-fracture-detr"), |
|
"KnochenWächter": pipeline("image-classification", |
|
model="Heem2/bone-fracture-detection-using-xray", |
|
image_processor=AutoImageProcessor.from_pretrained("Heem2/bone-fracture-detection-using-xray")), |
|
"RöntgenMeister": pipeline("image-classification", |
|
model="nandodeomkar/autotrain-fracture-detection-using-google-vit-base-patch-16-54382127388", |
|
image_processor=AutoImageProcessor.from_pretrained("nandodeomkar/autotrain-fracture-detection-using-google-vit-base-patch-16-54382127388")) |
|
} |
|
|
|
def draw_boxes(image, predictions): |
|
draw = ImageDraw.Draw(image) |
|
for pred in predictions: |
|
if pred['label'].lower() == 'fracture' and pred['score'] > 0.6: |
|
box = pred['box'] |
|
label = f"Fraktur ({pred['score']:.2%})" |
|
color = "#2563eb" |
|
|
|
draw.rectangle( |
|
[(box['xmin'], box['ymin']), (box['xmax'], box['ymax'])], |
|
outline=color, |
|
width=2 |
|
) |
|
|
|
text_bbox = draw.textbbox((box['xmin'], box['ymin']-15), label) |
|
draw.rectangle(text_bbox, fill=color) |
|
draw.text((box['xmin'], box['ymin']-15), label, fill="white") |
|
return image |
|
|
|
def main(): |
|
models = load_models() |
|
|
|
st.markdown("### 📤 Röntgenbilder Upload") |
|
|
|
|
|
uploaded_files = st.file_uploader( |
|
"Wählen Sie Röntgenbilder aus", |
|
type=['png', 'jpg', 'jpeg'], |
|
accept_multiple_files=True, |
|
label_visibility="collapsed" |
|
) |
|
|
|
if uploaded_files: |
|
|
|
if st.button("Bilder analysieren", key="analyze_button"): |
|
col1, col2 = st.columns([1, 1]) |
|
|
|
for idx, uploaded_file in enumerate(uploaded_files): |
|
image = Image.open(uploaded_file) |
|
|
|
|
|
predictions = models["KnochenAuge"](image) |
|
fractures_found = any(p['label'].lower() == 'fracture' and p['score'] > 0.6 for p in predictions) |
|
|
|
|
|
if fractures_found: |
|
with col1 if idx % 2 == 0 else col2: |
|
result_image = image.copy() |
|
result_image = draw_boxes(result_image, predictions) |
|
st.image(result_image, caption=f"Bild {idx + 1}", use_column_width=True) |
|
|
|
|
|
pred_wachter = models["KnochenWächter"](image)[0] |
|
pred_meister = models["RöntgenMeister"](image)[0] |
|
|
|
if pred_wachter['score'] > 0.6 or pred_meister['score'] > 0.6: |
|
st.markdown(f""" |
|
<div class='result-box'> |
|
<span style='color: #2563eb'>KnochenWächter:</span> {pred_wachter['score']:.1%}<br> |
|
<span style='color: #2563eb'>RöntgenMeister:</span> {pred_meister['score']:.1%} |
|
</div> |
|
""", unsafe_allow_html=True) |
|
|
|
|
|
st.markdown(""" |
|
<script> |
|
// Fonction pour mettre à jour le thème |
|
function updateTheme(isDark) { |
|
document.documentElement.setAttribute('data-theme', isDark ? 'dark' : 'light'); |
|
|
|
// Mise à jour des styles en fonction du thème |
|
const root = document.documentElement; |
|
if (isDark) { |
|
root.style.setProperty('--background-color', '#1f2937'); |
|
root.style.setProperty('--text-color', '#f3f4f6'); |
|
root.style.setProperty('--border-color', '#4b5563'); |
|
} else { |
|
root.style.setProperty('--background-color', '#ffffff'); |
|
root.style.setProperty('--text-color', '#1f2937'); |
|
root.style.setProperty('--border-color', '#e5e7eb'); |
|
} |
|
} |
|
|
|
// Écouter les messages du parent |
|
window.addEventListener('message', function(e) { |
|
if (e.data.type === 'theme-change') { |
|
updateTheme(e.data.theme === 'dark'); |
|
} |
|
}); |
|
|
|
// Thème initial basé sur les préférences système |
|
updateTheme(window.matchMedia('(prefers-color-scheme: dark)').matches); |
|
</script> |
|
""", unsafe_allow_html=True) |
|
|
|
if __name__ == "__main__": |
|
main() |