diff --git a/deblur/deblur_2d.py b/deblur/deblur_2d.py index f42b47d..a7844df 100644 --- a/deblur/deblur_2d.py +++ b/deblur/deblur_2d.py @@ -215,7 +215,6 @@ def kernel_detection(blurred, mask, edge_threshold=30, profile_length=21): - def kernel_detection_box(blurred, mask, edge_threshold=30, profile_length=21): def box_function(x, amp, center, width): """Simple box profile: flat region with sharp transitions.""" @@ -295,6 +294,117 @@ def deconvolution(image_file, edge_threshold=30, profile_length=21): plt.show() +def sharpness_heatmap(image, block_size=32, threshold=30): + """ + Compute a sharpness heatmap using color-aware Laplacian variance over blocks, + generate a binary mask highlighting blurred areas, and smooth the edges of the mask. + + Args: + image: BGR or RGB image (NumPy array). + block_size: Size of the square block to compute sharpness. + sigma: Standard deviation for Gaussian smoothing of the heatmap. + threshold: Sharpness threshold to define blurred regions (between 0 and 1). + smoothing_sigma: Standard deviation for Gaussian smoothing of the binary mask edges. + + Returns: + blurred_mask: Binary mask highlighting blurred areas (0 = sharp, 255 = blurred). + """ + if image.ndim != 3 or image.shape[2] != 3: + raise ValueError("Input must be a color image (3 channels)") + + h, w, _ = image.shape + heatmap = np.zeros((h // block_size, w // block_size)) + + # Calculate sharpness for each block + for y in range(0, h - block_size + 1, block_size): + for x in range(0, w - block_size + 1, block_size): + block = image[y:y + block_size, x:x + block_size, :] + sharpness_vals = [] + + for c in range(3): # For R, G, B channels + channel = block[..., c] + lap_var = cv2.Laplacian(channel, cv2.CV_64F).var() + sharpness_vals.append(lap_var) + + # Use average sharpness across color channels + heatmap[y // block_size, x // block_size] = np.mean(sharpness_vals) + + print(heatmap) + + # Threshold the heatmap to create a binary mask (blurred regions) + mask = heatmap < threshold + mask = (mask * 255).astype(np.uint8) # Convert to binary mask (0, 255) + + # Display Heatmap + plt.subplot(1, 2, 1) + plt.imshow(heatmap, cmap='hot', interpolation='nearest') + plt.title("Sharpness Heatmap") + plt.colorbar(label='Sharpness') + + # Display Smoothed Mask + plt.subplot(1, 2, 2) + plt.imshow(mask, cmap='gray', interpolation='nearest') + plt.title("Smoothed Mask for Blurred Areas") + plt.colorbar(label='Blurred Mask') + + plt.tight_layout() + plt.show() + + return smoothed_mask + + +def graininess_heatmap(image, block_size=32, threshold=100): + """ + Compute a graininess heatmap using local variance (texture/noise) over blocks. + No smoothing or blurring is applied. + + Args: + image: BGR or RGB image (NumPy array). + block_size: Size of the square block to compute variance (graininess). + + Returns: + graininess_map: Heatmap highlighting the graininess (texture/noise) in the image. + """ + if image.ndim != 3 or image.shape[2] != 3: + raise ValueError("Input must be a color image (3 channels)") + + h, w, _ = image.shape + graininess_map = np.zeros((h // block_size, w // block_size)) + + # Calculate variance for each block + for y in range(0, h - block_size + 1, block_size): + for x in range(0, w - block_size + 1, block_size): + block = image[y:y + block_size, x:x + block_size, :] + variance_vals = [] + + for c in range(3): # For R, G, B channels + channel = block[..., c] + variance = np.var(channel) + variance_vals.append(variance) + + # Use average variance across color channels for graininess + graininess_map[y // block_size, x // block_size] = np.mean(variance_vals) + + + mask = graininess_map < threshold + mask = (mask * 255).astype(np.uint8) # Convert to binary mask (0, 255) + + # Display graininess_map + plt.subplot(1, 2, 1) + plt.imshow(graininess_map, cmap='hot', interpolation='nearest') + plt.title("Graininess Heatmap") + plt.colorbar(label='Graininess') + + # Display Smoothed Mask + plt.subplot(1, 2, 2) + plt.imshow(mask, cmap='gray', interpolation='nearest') + plt.title("Mask for Blurred Areas") + plt.colorbar(label='Blurred Mask') + + plt.tight_layout() + plt.show() + + return graininess_map @@ -302,4 +412,8 @@ if __name__ == "__main__": img_file = "assets/real_test.jpg" #demo("assets/omas.png") - deconvolution(img_file, edge_threshold=5) + # deconvolution(img_file, edge_threshold=5) + + image = cv2.imread(img_file) + test = graininess_heatmap(image) + heatmap = sharpness_heatmap(image)