Team Ai
Apppublic

silversurfer343/ComputerVisionProject

sourceHugging Faceupdated 1y agoView on Hugging Face
0likes
app2.py894 linesDownload Raw Back to root
1import streamlit as st
2import cv2
3import numpy as np
4from skimage.segmentation import slic, mark_boundaries, find_boundaries
5from skimage.util import img_as_float
6from skimage import measure
7from PIL import Image
8import io
9import torch
10import torchvision
11from torchvision.models.segmentation import deeplabv3_resnet50
12import matplotlib.pyplot as plt
13import os
14from pathlib import Path
15from scipy import stats
16from scipy.ndimage import binary_fill_holes
17from skimage.morphology import remove_small_objects, remove_small_holes
18from skimage.measure import label, regionprops
19from sklearn.mixture import GaussianMixture
20from sklearn.preprocessing import StandardScaler
21from huggingface_hub import hf_hub_download
22
23def main():
24    st.set_page_config(page_title="Wall Crack Detection", layout="wide")
25    st.title("🧱 Wall Detection & Segmentation")
26
27    # Create tabs for different methods
28    tab1, tab2 = st.tabs(["Traditional CV Approach", "Deep Learning Approach"])
29
30    @st.cache_data
31    def load_image(image_file):
32        # Convert uploaded file to a cv2 image
33        file_bytes = np.asarray(bytearray(image_file.read()), dtype=np.uint8)
34        img = cv2.imdecode(file_bytes, 1)
35        return img
36
37    def process_image_traditional(img):
38        # Make copies for later overlays
39        img_orig = img.copy()
40        
41        # Convert to grayscale
42        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
43
44        # -------------------------------
45        # Harris Corner Detection
46        # -------------------------------
47        harris = cv2.cornerHarris(np.float32(gray), blockSize=2, ksize=3, k=0.04)
48        harris = cv2.dilate(harris, None)
49        harris_img = img.copy()
50        harris_img[harris > 0.01 * harris.max()] = [255, 0, 0]  # Mark corners in red
51        
52        # Create binary mask for harris corners for comparison
53        harris_mask = np.zeros_like(gray, dtype=np.uint8)
54        harris_mask[harris > 0.01 * harris.max()] = 255
55
56        # -------------------------------
57        # Canny + Morphological Closing
58        # -------------------------------
59        edges = cv2.Canny(gray, 50, 120)
60        kernel = np.ones((3, 3), np.uint8)
61        closed_edges = cv2.morphologyEx(edges, cv2.MORPH_CLOSE, kernel)
62
63        # -------------------------------
64        # HoughLinesP Detection
65        # -------------------------------
66        hough_img = img.copy()
67        hough_mask = np.zeros_like(gray, dtype=np.uint8)
68        lines = cv2.HoughLinesP(closed_edges, rho=1, theta=np.pi/180, 
69                                threshold=50, minLineLength=28, maxLineGap=15)
70        if lines is not None:
71            for line in lines:
72                x1, y1, x2, y2 = line[0]
73                cv2.line(hough_img, (x1, y1), (x2, y2), (0, 255, 0), 2)
74                cv2.line(hough_mask, (x1, y1), (x2, y2), 255, 2)
75
76        # -------------------------------
77        # Region-based Segmentation (Contours)
78        # -------------------------------
79        contours, _ = cv2.findContours(closed_edges.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
80        region_seg_img = img.copy()
81        region_mask = np.zeros_like(gray, dtype=np.uint8)
82        for cnt in contours:
83            area = cv2.contourArea(cnt)
84            if area > 50:  # adjust the area threshold as needed
85                x, y, w, h = cv2.boundingRect(cnt)
86                cv2.rectangle(region_seg_img, (x, y), (x + w, y + h), (255, 0, 0), 2)
87                cv2.rectangle(region_mask, (x, y), (x + w, y + h), 255, 2)
88
89        # -------------------------------
90        # Crack Detection Logic (Hough + Region)
91        # -------------------------------
92        hough_detected = lines is not None and len(lines) > 0
93        region_detected = False
94        for cnt in contours:
95            if cv2.contourArea(cnt) > 100:  # more stringent area threshold for detection
96                region_detected = True
97                break
98        traditional_prediction = 1 if (hough_detected or region_detected) else 0
99
100        return harris_img, closed_edges, hough_img, region_seg_img, harris_mask, hough_mask, region_mask, traditional_prediction
101
102    def process_image_slic(img):
103        # Make a copy of the original image
104        img_orig = img.copy()
105        
106        # First, perform the same basic processing for Hough detection:
107        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
108        edges = cv2.Canny(gray, 50, 120)
109        kernel = np.ones((3, 3), np.uint8)
110        closed_edges = cv2.morphologyEx(edges, cv2.MORPH_CLOSE, kernel)
111        lines1 = cv2.HoughLinesP(closed_edges, rho=1, theta=np.pi/180,
112                                 threshold=50, minLineLength=28, maxLineGap=15)
113        hough_detected = lines1 is not None and len(lines1) > 0
114
115        # Now, perform SLIC segmentation on the original image.
116        # Convert image to RGB float (as required by skimage)
117        img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
118        img_float = img_as_float(img_rgb)
119        
120        # Run SLIC with chosen parameters; adjust n_segments for granularity
121        segments = slic(img_float, n_segments=200, compactness=10, sigma=1, start_label=1)
122        
123        # Mark boundaries for visualization
124        slic_img = mark_boundaries(img_float, segments)
125        
126        # Extract boundaries from the SLIC segmentation
127        boundaries = find_boundaries(segments, mode='outer').astype(np.uint8) * 255
128        
129        # Run Hough Transform on the boundary mask
130        hough_lines_img = img.copy()
131        slic_mask = np.zeros_like(gray, dtype=np.uint8)
132        lines2 = cv2.HoughLinesP(boundaries, rho=1, theta=np.pi/180,
133                                 threshold=50, minLineLength=28, maxLineGap=15)
134        
135        if lines2 is not None:
136            for line in lines2:
137                x1, y1, x2, y2 = line[0]
138                cv2.line(hough_lines_img, (x1, y1), (x2, y2), (0, 0, 255), 2)
139                cv2.line(slic_mask, (x1, y1), (x2, y2), 255, 2)
140        
141        slic_detected = lines2 is not None and len(lines2) > 0
142
143        # Union logic: if either Hough on closed_edges or on SLIC boundaries detects a crack, return 1.
144        prediction = 1 if (hough_detected or slic_detected) else 0
145        
146        return slic_img, hough_lines_img, slic_mask, prediction
147
148    # GMM segmentation function
149    def apply_gmm_binary_mask(image, k=2):
150        image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
151        gray = cv2.cvtColor(image_rgb, cv2.COLOR_RGB2GRAY)
152
153        pixels = gray.reshape(-1, 1)
154        scaler = StandardScaler()
155        pixels_scaled = scaler.fit_transform(pixels)
156
157        gmm = GaussianMixture(n_components=k, random_state=42)
158        labels = gmm.fit_predict(pixels_scaled)
159        labels_image = labels.reshape(gray.shape)
160
161        class_means = [pixels[labels == i].mean() for i in range(k)]
162        crack_class = np.argmin(class_means)
163
164        binary_mask = (labels_image == crack_class).astype(np.uint8) * 255
165        return image_rgb, binary_mask
166
167    # Function to get DeepLabV3 model
168    @st.cache_resource
169    def load_dl_model():
170        # Initialize the DeepLabV3 model
171        model = torchvision.models.segmentation.deeplabv3_resnet50(pretrained=False)
172        # Modify the classifier to output 1 class (binary segmentation)
173        model.classifier[4] = torch.nn.Conv2d(256, 1, kernel_size=(1, 1), stride=(1, 1))
174        
175        # Load pretrained weights
176        device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
177        model_path = os.path.join(os.path.dirname(__file__), "deepnetv3.pth")
178        
179        try:
180            # First try loading from local file
181            if os.path.exists(model_path):
182                model.load_state_dict(torch.load(model_path, map_location=device), strict=False)
183            else:
184                # If local file doesn't exist, try downloading from Hugging Face
185                model_path = hf_hub_download(
186                    repo_id="silversurfer343/deepnet",  # Replace with your actual username
187                    filename="deepnetv3.pth"
188                )
189                model.load_state_dict(torch.load(model_path, map_location=device), strict=False)
190            
191            model.to(device)
192            model.eval()
193            return model, device, True
194        except Exception as e:
195            st.error(f"Error loading model: {e}")
196            return model, device, False
197
198    # Function to preprocess image for deep learning
199    def preprocess_image_dl(img):
200        # Resize image to 512x512 (or the size expected by your model)
201        img_resized = cv2.resize(img, (512, 512))
202        # Convert BGR to RGB
203        img_rgb = cv2.cvtColor(img_resized, cv2.COLOR_BGR2RGB)
204        # Convert to tensor and normalize
205        img_tensor = torch.from_numpy(img_rgb).float().permute(2, 0, 1) / 255.0
206        # Add batch dimension
207        img_batch = img_tensor.unsqueeze(0)
208        return img_batch, img_rgb
209
210    # Function to predict mask using the pretrained model
211    def predict_mask(model, img_tensor, device, threshold=0.5):
212        img_tensor = img_tensor.to(device)
213        with torch.no_grad():
214            output = model(img_tensor)['out']
215            pred = torch.sigmoid(output)
216            pred_bin = (pred > threshold).float()
217        return pred_bin
218
219    # ------------------- Refinement Methods -------------------
220
221    # 1. SLIC-based Refinement
222    def generate_superpixels(image, n_segments=300, compactness=10):
223        # image must be in HWC format and float
224        if image.dtype != np.float32:
225            image = image.astype(np.float32) / 255.0
226
227        superpixels = slic(image, n_segments=n_segments, compactness=compactness, start_label=0)
228        return superpixels
229
230    def refine_with_superpixels(pred_mask, superpixels):
231        refined_mask = np.zeros_like(pred_mask)
232
233        for label in np.unique(superpixels):
234            region_mask = (superpixels == label)
235            majority_vote = stats.mode(pred_mask[region_mask].flatten(), keepdims=False).mode
236            refined_mask[region_mask] = majority_vote
237
238        return refined_mask
239
240    # 2. Region-based Split and Merge Refinement
241    def region_based_split_and_merge(image, pred_mask, split_variance_thresh=0.01, merge_similarity_thresh=0.1, min_region_size=50):
242        image_gray = cv2.cvtColor((image * 255).astype(np.uint8), cv2.COLOR_RGB2GRAY)
243        labeled_mask = label(pred_mask)
244
245        region_map = np.zeros_like(pred_mask)
246
247        # Region Splitting
248        label_counter = 1
249        for region in regionprops(labeled_mask):
250            coords = region.coords
251            region_intensity = image_gray[tuple(zip(*coords))]
252            region_variance = np.var(region_intensity)
253
254            if region_variance > split_variance_thresh and len(coords) > 10:
255                # split into 2 by k-means clustering
256                pixels = np.array([image[coord[0], coord[1]] for coord in coords])
257                pixels = np.float32(pixels)
258                
259                if len(pixels) > 1:  # Ensure there are enough pixels for clustering
260                    try:
261                        criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
262                        _, labels, _ = cv2.kmeans(pixels, 2, None, criteria, 3, cv2.KMEANS_RANDOM_CENTERS)
263                        labels = labels.flatten()
264                        for i, coord in enumerate(coords):
265                            region_map[coord[0], coord[1]] = label_counter + labels[i]
266                        label_counter += 2
267                    except:
268                        # Fallback if kmeans fails
269                        for coord in coords:
270                            region_map[coord[0], coord[1]] = label_counter
271                        label_counter += 1
272                else:
273                    for coord in coords:
274                        region_map[coord[0], coord[1]] = label_counter
275                    label_counter += 1
276            else:
277                for coord in coords:
278                    region_map[coord[0], coord[1]] = label_counter
279                label_counter += 1
280
281        # Region Merging
282        final_map = region_map.copy()
283        merged = set()
284        for label1 in np.unique(region_map):
285            if label1 == 0 or label1 in merged:
286                continue
287
288            mask1 = (region_map == label1)
289            if np.sum(mask1) == 0:  # Skip empty regions
290                continue
291            
292            mean1 = np.mean(image[mask1], axis=0)
293
294            for label2 in np.unique(region_map):
295                if label2 == 0 or label2 == label1 or label2 in merged:
296                    continue
297
298                mask2 = (region_map == label2)
299                if np.sum(mask2) == 0:  # Skip empty regions
300                    continue
301                
302                mean2 = np.mean(image[mask2], axis=0)
303
304                # Merge if similar color mean
305                if np.linalg.norm(mean1 - mean2) < merge_similarity_thresh:
306                    final_map[mask2] = label1
307                    merged.add(label2)
308
309        # Morphological Cleaning
310        binary_mask = final_map > 0
311        binary_mask = binary_fill_holes(binary_mask)
312        binary_mask = remove_small_objects(binary_mask, min_size=min_region_size)
313        binary_mask = remove_small_holes(binary_mask, area_threshold=min_region_size)
314
315        return binary_mask.astype(np.uint8)
316
317    # 3. Mean Shift Refinement
318    def generate_mean_shift_segments(image, spatial_radius=21, color_radius=51, quantization_level=16):
319        # Convert image to uint8 [0,255] and then to BGR
320        image_uint8 = (image * 255).astype(np.uint8)
321        image_bgr = cv2.cvtColor(image_uint8, cv2.COLOR_RGB2BGR)
322        
323        # Apply mean shift filtering
324        filtered_bgr = cv2.pyrMeanShiftFiltering(image_bgr, spatial_radius, color_radius)
325        filtered_rgb = cv2.cvtColor(filtered_bgr, cv2.COLOR_BGR2RGB)
326        
327        # Quantize colors
328        quantized = (filtered_rgb // quantization_level) * quantization_level
329        
330        # Flatten to combine channels; cast to uint32 to avoid overflow
331        flat = quantized.reshape(-1, 3).astype(np.uint32)
332        flat_int = flat[:, 0] * 256 * 256 + flat[:, 1] * 256 + flat[:, 2]
333        quantized_int = flat_int.reshape(quantized.shape[0], quantized.shape[1])
334        
335        # Label connected components
336        segments = label(quantized_int, connectivity=1)
337        return segments
338
339    def refine_with_mean_shift(pred_mask, segments):
340        refined_mask = np.zeros_like(pred_mask)
341        unique_segments = np.unique(segments)
342        
343        for seg_val in unique_segments:
344            region = (segments == seg_val)
345            majority_label = np.mean(pred_mask[region]) > 0.5
346            refined_mask[region] = majority_label
347        
348        return refined_mask
349
350    # Function to visualize the prediction with refinements
351    def visualize_prediction_with_refinements(image_tensor, pred_bin, slic_refined, region_refined, mean_shift_refined, alpha=0.6):
352        # Convert tensors to numpy arrays
353        image_np = image_tensor.squeeze().permute(1, 2, 0).numpy()
354        pred_np = pred_bin.squeeze().cpu().numpy()
355        
356        # Create overlays
357        overlay_original = create_overlay(image_np, pred_np, alpha)
358        overlay_slic = create_overlay(image_np, slic_refined, alpha)
359        overlay_region = create_overlay(image_np, region_refined, alpha)
360        overlay_mean_shift = create_overlay(image_np, mean_shift_refined, alpha)
361        
362        # Create figure for visualization
363        fig, axs = plt.subplots(2, 4, figsize=(18, 9))
364        
365        # Original Image and Predicted Mask
366        axs[0, 0].imshow(image_np)
367        axs[0, 0].set_title('Original Image')
368        axs[0, 1].imshow(pred_np, cmap='gray')
369        axs[0, 1].set_title('Predicted Mask')
370        
371        # Refined Masks
372        axs[0, 2].imshow(slic_refined, cmap='gray')
373        axs[0, 2].set_title('SLIC Refined')
374        axs[0, 3].imshow(region_refined, cmap='gray')
375        axs[0, 3].set_title('Region-based Refined')
376        
377        # Mean Shift Refined and Overlays
378        axs[1, 0].imshow(mean_shift_refined, cmap='gray')
379        axs[1, 0].set_title('Mean Shift Refined')
380        axs[1, 1].imshow(overlay_original)
381        axs[1, 1].set_title('Original Overlay')
382        axs[1, 2].imshow(overlay_slic)
383        axs[1, 2].set_title('SLIC Overlay')
384        axs[1, 3].imshow(overlay_mean_shift)
385        axs[1, 3].set_title('Mean Shift Overlay')
386        
387        for ax in axs.flat:
388            ax.axis('off')
389        
390        plt.tight_layout()
391        
392        # Convert plot to image
393        buf = io.BytesIO()
394        plt.savefig(buf, format='png', dpi=150)
395        buf.seek(0)
396        plt.close(fig)
397        
398        return buf
399
400    def create_overlay(image, mask, alpha=0.6):
401        # Create green mask overlay
402        overlay = image.copy()
403        green_mask = np.zeros_like(image)
404        green_mask[..., 1] = 1  # Green channel
405        overlay_mask = np.where(mask[..., None] > 0, green_mask, 0)
406        overlay = (1 - alpha) * image + alpha * overlay_mask
407        overlay = np.clip(overlay, 0, 1)
408        return overlay
409
410    # Function to visualize traditional CV methods comparison
411    def visualize_traditional_cv_comparison(img_rgb, harris_mask, hough_mask, region_mask, slic_mask, gmm_mask, alpha=0.6):
412        # Create figure for visualization
413        fig, axs = plt.subplots(2, 3, figsize=(18, 12))
414        
415        # Original Image
416        axs[0, 0].imshow(img_rgb)
417        axs[0, 0].set_title('Original Image')
418        
419        # Harris Corners Mask
420        axs[0, 1].imshow(harris_mask, cmap='gray')
421        axs[0, 1].set_title('Harris Corners Mask')
422        
423        # Hough Lines Mask
424        axs[0, 2].imshow(hough_mask, cmap='gray')
425        axs[0, 2].set_title('Hough Lines Mask')
426        
427        # Region Mask
428        axs[1, 0].imshow(region_mask, cmap='gray')
429        axs[1, 0].set_title('Region-based Mask')
430        
431        # SLIC Mask
432        axs[1, 1].imshow(slic_mask, cmap='gray')
433        axs[1, 1].set_title('SLIC Mask')
434        
435        # GMM Mask
436        axs[1, 2].imshow(gmm_mask, cmap='gray')
437        axs[1, 2].set_title('GMM Mask')
438        
439        for ax in axs.flat:
440            ax.axis('off')
441        
442        plt.tight_layout()
443        
444        # Convert plot to image
445        buf = io.BytesIO()
446        plt.savefig(buf, format='png', dpi=150)
447        buf.seek(0)
448        plt.close(fig)
449        
450        return buf
451
452    def visualize_traditional_overlays(img_rgb, harris_mask, hough_mask, region_mask, slic_mask, gmm_mask, alpha=0.6):
453        # Create overlays for each mask
454        harris_overlay = create_overlay(img_rgb, harris_mask/255, alpha)
455        hough_overlay = create_overlay(img_rgb, hough_mask/255, alpha)
456        region_overlay = create_overlay(img_rgb, region_mask/255, alpha)
457        slic_overlay = create_overlay(img_rgb, slic_mask/255, alpha)
458        gmm_overlay = create_overlay(img_rgb, gmm_mask/255, alpha)
459        
460        # Create figure for visualization
461        fig, axs = plt.subplots(2, 3, figsize=(18, 12))
462        
463        # Original Image
464        axs[0, 0].imshow(img_rgb)
465        axs[0, 0].set_title('Original Image')
466        
467        # Harris Corners Overlay
468        axs[0, 1].imshow(harris_overlay)
469        axs[0, 1].set_title('Harris Corners Overlay')
470        
471        # Hough Lines Overlay
472        axs[0, 2].imshow(hough_overlay)
473        axs[0, 2].set_title('Hough Lines Overlay')
474        
475        # Region Overlay
476        axs[1, 0].imshow(region_overlay)
477        axs[1, 0].set_title('Region-based Overlay')
478        
479        # SLIC Overlay
480        axs[1, 1].imshow(slic_overlay)
481        axs[1, 1].set_title('SLIC Overlay')
482        
483        # GMM Overlay
484        axs[1, 2].imshow(gmm_overlay)
485        axs[1, 2].set_title('GMM Overlay')
486        
487        for ax in axs.flat:
488            ax.axis('off')
489        
490        plt.tight_layout()
491        
492        # Convert plot to image
493        buf = io.BytesIO()
494        plt.savefig(buf, format='png', dpi=150)
495        buf.seek(0)
496        plt.close(fig)
497        
498        return buf
499
500    # ------------- Streamlit UI -------------
501    with tab1:
502        st.header("Traditional Computer Vision Approach")
503        
504        uploaded_file = st.file_uploader("Upload a wall image (JPG/PNG/JPEG):", type=["jpg","png","jpeg"], key="cv_uploader")
505        
506        if uploaded_file is not None:
507            img = load_image(uploaded_file)
508            
509            # Process the image through our traditional pipeline
510            harris_img, closed_edges, hough_img, region_seg_img, harris_mask, hough_mask, region_mask, traditional_prediction = process_image_traditional(img)
511            
512            # Process the image using SLIC
513            slic_img, slic_hough_img, slic_mask, slic_prediction = process_image_slic(img)
514            
515            # Process the image using GMM
516            image_rgb, gmm_mask = apply_gmm_binary_mask(img, 2)
517            
518            # GMM Crack Detection Logic
519            crack_pixel_ratio = np.sum(gmm_mask == 255) / gmm_mask.size
520            gmm_prediction = 1 if crack_pixel_ratio > 0.01 else 0  # 1% threshold
521            
522            st.subheader("Uploaded Image")
523            st.image(cv2.cvtColor(img, cv2.COLOR_BGR2RGB), channels="RGB", use_column_width=True)
524            
525            # Display traditional CV outputs
526            st.subheader("Traditional Computer Vision Results")
527            col1, col2, col3 = st.columns(3)
528            
529            with col1:
530                st.image(cv2.cvtColor(harris_img, cv2.COLOR_BGR2RGB), caption="Harris Corner Detection", use_column_width=True)
531                st.image(closed_edges, caption="Canny + Morphological Closing", use_column_width=True, channels="GRAY")
532            
533            with col2:
534                st.image(cv2.cvtColor(hough_img, cv2.COLOR_BGR2RGB), caption="Crack Lines via HoughLinesP", use_column_width=True)
535                st.image(cv2.cvtColor(region_seg_img, cv2.COLOR_BGR2RGB), caption="Region-based Segmentation", use_column_width=True)
536            
537            with col3:
538                # Final Crack Classification
539                if traditional_prediction == 1:
540                    st.error("⚠️ Crack Detected! (Traditional)")
541                else:
542                    st.success("✅ No Crack Detected (Traditional)")
543            
544            # Display SLIC outputs
545            st.subheader("SLIC-based Segmentation Results")
546            col1, col2 = st.columns(2)
547            
548            with col1:
549                st.image(slic_img, caption="SLIC Segmentation", use_column_width=True)
550            
551            with col2:
552                # SLIC Crack Classification
553                if slic_prediction == 1:
554                    st.error("⚠️ Crack Detected! (SLIC + Hough)")
555                else:
556                    st.success("✅ No Crack Detected (SLIC + Hough)")
557
558            # GMM Results
559            st.subheader("GMM-Based Segmentation")
560            col1, col2 = st.columns(2)
561
562            with col1:
563                st.image(image_rgb, caption="Original (RGB)", use_column_width=True)
564            with col2:
565                st.image(gmm_mask, caption="GMM Crack Mask", use_column_width=True, channels="GRAY")
566            
567            # Display GMM result in Streamlit
568            if gmm_prediction == 1:
569                st.error("⚠️ Crack Detected! (GMM Segmentation)")
570            else:
571                st.success("✅ No Crack Detected (GMM Segmentation)")
572
573            # New: Detailed Refinement Results and Performance Comparison
574            st.subheader("Detailed Method Comparison")
575            
576            # Visualization of all masks
577            img_rgb_viz = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
578            mask_comparison = visualize_traditional_cv_comparison(
579                img_rgb_viz, 
580                harris_mask, 
581                hough_mask, 
582                region_mask, 
583                slic_mask, 
584                gmm_mask
585            )
586            st.image(mask_comparison, caption="Comparison of Detection Masks", use_column_width=True)
587            
588            
589            # Performance Comparison
590            st.subheader("Performance Comparison")
591            
592            # Calculate pixel coverage for each method
593            harris_coverage = np.sum(harris_mask > 0) / harris_mask.size * 100
594            hough_coverage = np.sum(hough_mask > 0) / hough_mask.size * 100
595            region_coverage = np.sum(region_mask > 0) / region_mask.size * 100
596            slic_coverage = np.sum(slic_mask > 0) / slic_mask.size * 100
597            gmm_coverage = np.sum(gmm_mask > 0) / gmm_mask.size * 100
598            
599            data = {
600                'Method': ['Harris Corners', 'Hough Lines', 'Region-based', 'SLIC', 'GMM'],
601                'Crack Coverage (%)': [
602                    harris_coverage,
603                    hough_coverage,
604                    region_coverage,
605                    slic_coverage,
606                    gmm_coverage
607                ]
608            }
609            
610            st.write("Crack Coverage Percentage by Method:")
611            st.bar_chart(data, x='Method', y='Crack Coverage (%)')
612            
613            # Method Analysis
614            st.subheader("Method Analysis")
615            
616            col1, col2 = st.columns(2)
617            
618            with col1:
619                st.markdown("**Strongest Detection Methods**")
620                methods = ['Harris Corners', 'Hough Lines', 'Region-based', 'SLIC', 'GMM']
621                coverages = [harris_coverage, hough_coverage, region_coverage, slic_coverage, gmm_coverage]
622                max_idx = coverages.index(max(coverages))
623                
624                st.info(f"**{methods[max_idx]}** shows the highest crack coverage at **{coverages[max_idx]:.2f}%**")
625                
626                if max(coverages) > 1.0:
627                    st.warning("Significant crack pattern detected in the image")
628                else:
629                    st.success("Minimal crack patterns detected in the image")
630            
631            with col2:
632                st.markdown("**Detection Confidence**")
633                
634                # Count positive detections
635                detection_count = sum([
636                    1 if harris_coverage > 0.5 else 0,
637                    1 if hough_coverage > 0.5 else 0,
638                    1 if region_coverage > 0.5 else 0,
639                    1 if slic_coverage > 0.5 else 0,
640                    1 if gmm_coverage > 0.5 else 0
641                ])
642                confidence = (detection_count / 5) * 100
643                
644                st.progress(confidence / 100)
645                st.write(f"Detection Confidence: {confidence:.1f}%")
646
647                if confidence > 60:
648                    st.error("High confidence crack detection - further inspection recommended")
649                elif confidence > 20:
650                    st.warning("Medium confidence crack detection - monitoring recommended")
651                else:
652                    st.success("Low confidence crack detection - likely safe condition")
653
654                # Final Analysis Summary
655                st.subheader("Analysis Summary")
656                st.markdown(f"""
657                * **Traditional CV Methods**: {'Detected cracks' if traditional_prediction == 1 else 'No cracks detected'}
658                * **SLIC-Based Methods**: {'Detected cracks' if slic_prediction == 1 else 'No cracks detected'}
659                * **GMM-Based Methods**: {'Detected cracks' if gmm_prediction == 1 else 'No cracks detected'}
660                * **Overall Detection Confidence**: {confidence:.1f}%
661                """)
662
663                # Add recommendations based on detection results
664                if confidence > 40:
665                    st.error("""
666                    **Recommendations**: 
667                    - Consider professional inspection of the wall
668                    - Monitor crack development over time
669                    - Check for water damage or structural issues nearby
670                    """)
671                elif confidence > 10:
672                    st.warning("""
673                    **Recommendations**:
674                    - Monitor the area periodically
675                    - Take reference photos for comparison over time
676                    - Check again after extreme weather conditions
677                    """)
678                else:
679                    st.success("""
680                    **Recommendations**:
681                    - No immediate action required
682                    - Include in regular building maintenance checks
683                    """)
684
685    with tab2:
686        st.header("Deep Learning Approach with Refinement Methods")
687        
688        uploaded_file_dl = st.file_uploader("Upload a wall image (JPG/PNG/JPEG):", type=["jpg","png","jpeg"], key="dl_uploader")
689        
690        # Load the pretrained model
691        model, device, model_loaded = load_dl_model()
692        
693        if not model_loaded:
694            st.warning("Pretrained model could not be loaded. Deep learning analysis may not be accurate.")
695        
696        if uploaded_file_dl is not None:
697            with st.spinner("Processing image with DeepLabV3 model and applying refinements..."):
698                img_dl = load_image(uploaded_file_dl)
699                
700                # Preprocess image
701                img_tensor, img_rgb = preprocess_image_dl(img_dl)
702                
703                # Predict mask
704                pred_bin = predict_mask(model, img_tensor, device)
705                pred_np = pred_bin.squeeze().cpu().numpy()
706                
707                # Apply SLIC-based refinement
708                superpixels = generate_superpixels(img_rgb, n_segments=300, compactness=10)
709                slic_refined = refine_with_superpixels(pred_np, superpixels)
710                
711                # Apply Region-based Split and Merge refinement
712                region_refined = region_based_split_and_merge(img_rgb, pred_np)
713                
714                # Apply Mean Shift refinement
715                mean_shift_segments = generate_mean_shift_segments(img_rgb)
716                mean_shift_refined = refine_with_mean_shift(pred_np, mean_shift_segments)
717                
718                # Visualize all results
719                vis_buf = visualize_prediction_with_refinements(
720                    img_tensor.cpu(), 
721                    pred_bin.cpu(), 
722                    slic_refined, 
723                    region_refined, 
724                    mean_shift_refined
725                )
726                
727                # Display results
728                st.image(vis_buf, caption="DeepLabV3 Segmentation Results with Refinement Methods", use_column_width=True)
729                
730                # Show individual refinement results
731                st.subheader("Detailed Refinement Results")
732                
733                col1, col2, col3 = st.columns(3)
734                
735                with col1:
736                    st.markdown("**SLIC-based Refinement**")
737                    st.info("Combines segmentation with majority voting inside superpixels")
738                    crack_ratio_slic = np.sum(slic_refined) / slic_refined.size
739                    if crack_ratio_slic > 0.01:
740                        st.error("⚠️ Crack Detected! (SLIC Refinement)")
741                    else:
742                        st.success("✅ No Crack Detected (SLIC Refinement)")
743                
744                with col2:
745                    st.markdown("**Region-based Refinement**")
746                    st.info("Uses split & merge based on color & texture variance")
747                    crack_ratio_region = np.sum(region_refined) / region_refined.size
748                    if crack_ratio_region > 0.01:
749                        st.error("⚠️ Crack Detected! (Region Refinement)")
750                    else:
751                        st.success("✅ No Crack Detected (Region Refinement)")
752                
753                with col3:
754                    st.markdown("**Mean Shift Refinement**")
755                    st.info("Uses adaptive bandwidth clustering for natural segmentation")
756                    crack_ratio_ms = np.sum(mean_shift_refined) / mean_shift_refined.size
757                    if crack_ratio_ms > 0.01:
758                        st.error("⚠️ Crack Detected! (Mean Shift Refinement)")
759                    else:
760                        st.success("✅ No Crack Detected (Mean Shift Refinement)")
761                
762                # Display comparison of methods
763                st.subheader("Performance Comparison")
764                
765                # Calculate crack ratios for each method
766                crack_ratio_original = np.sum(pred_np) / pred_np.size
767                
768                data = {
769                    'Method': ['Original DL', 'SLIC', 'Region-based', 'Mean Shift'],
770                    'Crack Coverage (%)': [
771                        crack_ratio_original * 100,
772                        crack_ratio_slic * 100, 
773                        crack_ratio_region * 100,
774                        crack_ratio_ms * 100
775                    ]
776                }
777                
778                st.write("Crack Coverage Percentage by Method:")
779                st.bar_chart(data, x='Method', y='Crack Coverage (%)')
780                
781                # Add new detailed analysis and recommendations section
782                st.subheader("Deep Learning Model Analysis")
783                
784                # Calculate weighted ensemble prediction
785                weights = {
786                    'Original': 0.25,
787                    'SLIC': 0.25,
788                    'Region': 0.25,
789                    'MeanShift': 0.25
790                }
791                
792                ensemble_score = (
793                    weights['Original'] * crack_ratio_original +
794                    weights['SLIC'] * crack_ratio_slic +
795                    weights['Region'] * crack_ratio_region +
796                    weights['MeanShift'] * crack_ratio_ms
797                ) * 100
798                
799                st.write(f"Weighted Ensemble Score: {ensemble_score:.2f}%")
800                
801                # Display confidence gauge
802                st.progress(min(ensemble_score/10, 1.0))  # Cap at 100%
803                
804                if ensemble_score > 5:
805                    st.error("⚠️ High confidence crack detection (Deep Learning)")
806                    st.markdown("""
807                    **Model Analysis**:
808                    - The deep learning model has detected significant crack patterns with high confidence
809                    - Multiple refinement methods confirm the detection
810                    - Detailed inspection is recommended
811                    """)
812                elif ensemble_score > 1:
813                    st.warning("⚠️ Medium confidence crack detection (Deep Learning)")
814                    st.markdown("""
815                    **Model Analysis**:
816                    - The model has detected potential crack patterns with moderate confidence
817                    - Some refinement methods confirm the detection
818                    - Further monitoring is recommended
819                    """)
820                else:
821                    st.success("✅ Low/No crack detection (Deep Learning)")
822                    st.markdown("""
823                    **Model Analysis**:
824                    - The model found minimal or no crack patterns
825                    - Refinement methods confirm the absence of significant cracks
826                    - The wall appears to be in good condition
827                    """)
828                
829                # Method comparison and analysis
830                st.subheader("Method Effectiveness Analysis")
831                
832                # Determine the most sensitive method
833                methods = ['Original DL', 'SLIC', 'Region-based', 'Mean Shift']
834                ratios = [crack_ratio_original, crack_ratio_slic, crack_ratio_region, crack_ratio_ms]
835                most_sensitive_idx = np.argmax(ratios)
836                
837                st.info(f"Most sensitive method: **{methods[most_sensitive_idx]}** with {ratios[most_sensitive_idx]*100:.2f}% coverage")
838                
839                # Calculate agreement between methods
840                agreement_count = sum([1 for r in ratios if r > 0.01])
841                agreement_percentage = (agreement_count / len(ratios)) * 100
842                
843                st.write(f"Method agreement: {agreement_percentage:.1f}% ({agreement_count}/{len(ratios)} methods agree)")
844                
845                # Model confidence explanation
846                st.subheader("Confidence Explanation")
847                
848                col1, col2 = st.columns(2)
849                with col1:
850                    st.markdown("""
851                    **How confidence is calculated:**
852                    - Original model prediction (25%)
853                    - SLIC refinement results (25%)
854                    - Region-based refinement (25%) 
855                    - Mean Shift refinement (25%)
856                    """)
857                
858                with col2:
859                    st.markdown("""
860                    **Interpreting the results:**
861                    - >5%: Significant crack detected
862                    - 1-5%: Potential crack detected
863                    - <1%: No significant crack detected
864                    """)
865                
866                # Final recommendation section
867                st.subheader("Final Recommendations")
868                
869                if ensemble_score > 5:
870                    st.error("""
871                    **Professional Assessment Recommended:**
872                    - Schedule a structural inspection
873                    - Document the crack pattern and location
874                    - Monitor for changes in size or pattern
875                    - Check for water infiltration or other damage
876                    """)
877                elif ensemble_score > 1:
878                    st.warning("""
879                    **Monitoring Recommended:**
880                    - Take reference photos for future comparison
881                    - Check the area after extreme weather conditions
882                    - Monitor for growth or pattern changes
883                    - Consider applying crack sealant if stable
884                    """)
885                else:
886                    st.success("""
887                    **No Immediate Action Required:**
888                    - Include in regular building maintenance inspections
889                    - Re-analyze if visible changes occur
890                    - Consider this area low priority for repairs
891                    """)
892
893if __name__ == "__main__":
894    main()