CoolFace
Apppublic

benedictpepper/Brain-Tumor-Segmentation

sourceHugging Faceupdated 6mo agoView on Hugging Face
0likes
app.py235 linesDownload Raw Back to root
1import os2import numpy as np3import cv24import skfuzzy as fuzz5from sklearn.metrics import silhouette_score, davies_bouldin_score6import streamlit as st7from PIL import Image8import io9 10 11st.set_page_config(12    page_title="Brain Tumor Segmentation",13    page_icon="๐Ÿง ",14    layout="wide"15)16 17 18class FCMSegmenter:19    """Fuzzy C-Means based MRI tumor segmentation with optional texture features."""20    21    def __init__(self, n_clusters=4, fuzziness=2.0, max_iter=1000, error=0.005, use_texture=False):22        self.n_clusters = n_clusters23        self.fuzziness = fuzziness24        self.max_iter = max_iter25        self.error = error26        self.use_texture = use_texture27        self.cntr = None28        self.u = None29        self.fpc = None30        self.iterations = None31        self.objective_value = None32        33    def load_image_array(self, img_rgb):34        """Preprocess numpy RGB image array for segmentation."""35        img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2GRAY) if len(img_rgb.shape) > 2 else img_rgb36        original_shape = img_gray.shape37        38     39        pixel_intensity = img_gray.flatten().astype(np.float32)40        41        if self.use_texture:42       43            local_mean = cv2.blur(img_gray, (5, 5)).flatten().astype(np.float32)44            sq_img = img_gray.astype(np.float32) ** 245            local_sq_mean = cv2.blur(sq_img, (5, 5)).flatten()46            local_std = np.sqrt(np.maximum(local_sq_mean - local_mean**2, 0))47            48           49            pixel_data = np.vstack((pixel_intensity, local_mean, local_std))50        else:51           52            pixel_data = pixel_intensity.reshape((1, -1))53            54        return img_rgb, img_gray, pixel_data, original_shape55    56    def segment(self, pixel_data):57        """Apply Fuzzy C-Means clustering to pixel data."""58        cntr, u, _, _, jm, p, fpc = fuzz.cluster.cmeans(59            data=pixel_data,60            c=self.n_clusters,61            m=self.fuzziness,62            error=self.error,63            maxiter=self.max_iter,64            init=None65        )66        67        self.cntr = cntr68        self.u = u69        self.fpc = fpc70        self.iterations = p71        self.objective_value = jm[-1]72        73        return np.argmax(u, axis=0)74    75    def create_segmented_image(self, cluster_labels, original_shape):76        """Convert cluster labels to color-coded segmented RGB image."""77        segmented_labels = cluster_labels.reshape(original_shape)78        segmented_color = np.zeros((original_shape[0], original_shape[1], 3), dtype=np.uint8)79        80    81        intensity_centers = self.cntr[:, 0]82        sorted_centers = np.argsort(intensity_centers)83        84      85        color_map = {86            sorted_centers[0]: [0, 0, 0],       # Background (Black)87            sorted_centers[1]: [85, 85, 85],    # Healthy tissue (Gray)88            sorted_centers[2]: [0, 255, 0],     # Fluid/Edema (Green)89            sorted_centers[3] if self.n_clusters > 3 else -1: [255, 0, 0] # Tumor (Red)90        }91        92        for i in range(self.n_clusters):93            mask = segmented_labels == i94            color = color_map.get(i, [255, 255, 255])95            segmented_color[mask] = color96        97        return segmented_labels, segmented_color98    99    def evaluate(self, pixel_data, cluster_labels):100        """Compute clustering quality metrics safely without freezing."""101        labels_flat = cluster_labels.flatten()102        data_t = pixel_data.T 103        104        metrics = {105            'fpc': self.fpc,106            'iterations': self.iterations,107            'objective_value': self.objective_value108        }109        110        if len(np.unique(labels_flat)) > 1:111            try:112               113                sample_size = min(10000, len(labels_flat))114                indices = np.random.choice(len(labels_flat), sample_size, replace=False)115                116                metrics['silhouette'] = silhouette_score(data_t[indices], labels_flat[indices])117                metrics['davies_bouldin'] = davies_bouldin_score(data_t[indices], labels_flat[indices])118            except Exception as e:119                st.warning(f"Detailed metric calculation skipped: {e}")120        121        return metrics122    123    def process(self, img_rgb):124        """Full segmentation pipeline."""125        img_rgb, img_gray, pixel_data, original_shape = self.load_image_array(img_rgb)126        cluster_labels = self.segment(pixel_data)127        segmented_labels, segmented_color = self.create_segmented_image(cluster_labels, original_shape)128        metrics = self.evaluate(pixel_data, cluster_labels)129        130        return {131            'original': img_rgb,132            'gray': img_gray,133            'segmented_labels': segmented_labels,134            'segmented_color': segmented_color,135            'metrics': metrics136        }137 138 139def main():140    st.title("๐Ÿง  Brain Tumor Segmentation using FCM")141    st.markdown("Upload an MRI scan to automatically segment and highlight potential tumor regions using the **Fuzzy C-Means** algorithm.")142 143    st.sidebar.header("โš™๏ธ Advanced Configuration")144    n_clusters = st.sidebar.slider("Number of Clusters (Tissue Types)", min_value=2, max_value=8, value=4, step=1)145    fuzziness = st.sidebar.slider("Fuzziness Parameter (m)", min_value=1.1, max_value=5.0, value=2.0, step=0.1)146    use_texture = st.sidebar.checkbox("Use Texture Features (Local Mean & Variance)", value=False)147    148    st.sidebar.markdown("---")149 150    with st.sidebar.expander("โ„น๏ธ About this Program", expanded=False):151        st.markdown("""152        **Developer:** Benedict Pepper153        154        **About this Program:**155        This is an automated medical image analysis tool that applies the Fuzzy C-Means (FCM) soft clustering algorithm to segment brain MRI scans. By clustering pixel data into distinct tissue groups, this tool helps isolate potential tumor regions from healthy tissue, fluids, and background.156        157        **What is Fuzzy C-Means (FCM)?**158        Unlike traditional K-Means clustering where each pixel belongs strictly to ONE group, FCM allows a pixel to have a "degree of belonging" (membership) to multiple groups at the same time. This is particularly useful in medical imaging because tissue boundaries are often blurred and overlap (the partial volume effect).159        160        **The Objective Function (Formula):**161        The algorithm minimizes:162        $J_m = \sum_{i=1}^{N} \sum_{j=1}^{C} (u_{ij}^m) \cdot ||x_i - c_j||^2$163        164        Where:165        * $N$: total number of pixels.166        * $C$: total number of clusters.167        * $u_{ij}$: degree of membership of pixel $x_i$ in cluster $j$.168        * $m$: Fuzziness parameter.169        * $c_j$: center of the cluster.170        """)171 172    # Main area execution - User Input173    st.markdown("### 1. Upload MRI Scan")174    uploaded_file = st.file_uploader("Choose an MRI image file", type=["jpg", "jpeg", "png", "bmp", "tif"])175 176    if uploaded_file is not None:177     178        file_bytes = np.asarray(bytearray(uploaded_file.read()), dtype=np.uint8)179        img_bgr = cv2.imdecode(file_bytes, 1)180        img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)181        182        st.markdown("### 2. Run Segmentation")183        run_btn = st.button("๐Ÿš€ Run Segmentation", type="primary", use_container_width=True)184 185      186        col1, col2 = st.columns(2)187        with col1:188            st.image(img_rgb, caption="Original MRI Image", use_container_width=True)189            190        with col2:191            if not run_btn:192                st.info("๐Ÿ‘ˆ Click **Run Segmentation** above to process this image. (You can adjust advanced settings in the sidebar first if desired)")193            else:194                with st.spinner("Processing... Applying Fuzzy C-Means (This might take a few seconds)"):195                    segmenter = FCMSegmenter(196                        n_clusters=n_clusters, 197                        fuzziness=fuzziness, 198                        use_texture=use_texture199                    )200                    results = segmenter.process(img_rgb)201                    202                st.image(results['segmented_color'], caption="Segmented Output", use_container_width=True)203                204      205        if run_btn:206            st.markdown("---")207            st.markdown("### ๐Ÿ“Š Evaluation Metrics")208            m = results['metrics']209            210            metric_cols = st.columns(4)211            metric_cols[0].metric("FPC Score", f"{m.get('fpc', 0):.4f}", help="Fuzzy Partition Coefficient (closer to 1.0 is better)")212            metric_cols[1].metric("Iterations", f"{m.get('iterations', 0)}", help="Cycles taken to converge")213            metric_cols[2].metric("Objective Val", f"{m.get('objective_value', 0):.2e}")214            if 'silhouette' in m:215                metric_cols[3].metric("Silhouette Score", f"{m['silhouette']:.4f}", help="Cluster separation quality (closer to 1.0 is better)")216 217            st.markdown("### ๐Ÿ’พ Export Results")218            219     220            seg_img_pil = Image.fromarray(results['segmented_color'])221            buf = io.BytesIO()222            seg_img_pil.save(buf, format="PNG")223            byte_im = buf.getvalue()224            225            st.download_button(226                label="Download Segmented Image",227                data=byte_im,228                file_name="segmented_tumor.png",229                mime="image/png"230            )231    else:232        st.info("๐Ÿ‘† Please upload an MRI scan to get started.")233 234if __name__ == '__main__':235    main()