
.. DO NOT EDIT.
.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY.
.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE:
.. "example_gallery/plot_coherence_factor.py"
.. LINE NUMBERS ARE GIVEN BELOW.

.. only:: html

    .. note::
        :class: sphx-glr-download-link-note

        :ref:`Go to the end <sphx_glr_download_example_gallery_plot_coherence_factor.py>`
        to download the full example code.

.. rst-class:: sphx-glr-example-title

.. _sphx_glr_example_gallery_plot_coherence_factor.py:


Coherence Factor for Ultrasound Beamforming
===========================================

This example demonstrates different coherence factor formulations and their
applications in ultrasound imaging. Coherence factors measure the degree to
which signals from different array elements are in phase, providing quality
metrics for adaptive beamforming and aberration correction.

We'll explore:

- Different coherence scenarios (perfect to severely aberrated)

- Multiple coherence factor types (Standard, Generalized, Sign, Phase)

- Parameter effects and practical considerations

This example demonstrates coherence factor calculations for beamforming quality
assessment [1]_, with applications to aberration correction [2]_. We compare
different formulations including the generalized coherence factor [3]_ and
phase coherence methods [4]_.

References
----------
.. [1] Rigby, K. W., et al. (1999). Improved in vivo abdominal image quality
       using real-time estimation and correction of wavefront aberration.
       Proceedings IEEE Ultrasonics Symposium, 2, 1351-1355.
.. [2] Vr˚alstad, A.E. et al. (2024). Coherence Based Sound Speed Aberration
       Correction — with clinical validation in fetal ultrasound. arXiv:2411.16551
.. [3] Li, P. C., & Li, M. L. (2003). Adaptive imaging using the generalized
       coherence factor. IEEE UFFC, 50(2), 128-141.
.. [4] Camacho, J., et al. (2009). Phase coherence imaging. IEEE UFFC, 56(5), 958-974.

Example
-------

.. GENERATED FROM PYTHON SOURCE LINES 38-41

.. code-block:: Python

    # Note: it would probably be interesting to use a PICMUS dataset with a beamformer
    # at some point.








.. GENERATED FROM PYTHON SOURCE LINES 42-44

1. Import required modules and functions
------------------------------------------------------------------------

.. GENERATED FROM PYTHON SOURCE LINES 44-59

.. code-block:: Python


    import matplotlib

    matplotlib.use("Agg")  # Use non-interactive backend
    import matplotlib.pyplot as plt
    import numpy as np
    from scipy import ndimage

    from ultrasound_metrics.metrics.coherence import (
        coherence_factor,
        generalized_coherence_factor,
        phase_coherence_factor,
        sign_coherence_factor,
    )








.. GENERATED FROM PYTHON SOURCE LINES 60-62

2. Setup: Simulate realistic ultrasound beamforming scenarios
------------------------------------------------------------------------

.. GENERATED FROM PYTHON SOURCE LINES 62-83

.. code-block:: Python



    # Define image dimensions and number of receive elements
    height, width = 128, 96
    n_elements = 32

    # Create a base complex-valued signal pattern with point targets and speckle
    np.random.seed(42)  # For reproducible results
    base_signal = np.random.randn(height, width) + 1j * np.random.randn(height, width)
    base_signal = base_signal.astype(np.complex64)

    # Add some structured features (simulating point targets and speckle)
    # Point target in upper region (high coherence expected)
    base_signal[30:35, 45:50] += 5.0 + 5.0j

    # Speckle pattern in middle region
    y_speckle, x_speckle = np.mgrid[50:80, 20:75]
    speckle_pattern = np.exp(1j * (x_speckle * 0.3 + y_speckle * 0.2))
    base_signal[50:80, 20:75] += 2.0 * speckle_pattern









.. GENERATED FROM PYTHON SOURCE LINES 84-86

3. Create scenarios with different coherence levels
------------------------------------------------------------------------

.. GENERATED FROM PYTHON SOURCE LINES 86-125

.. code-block:: Python


    # These scenarios simulate different imaging conditions from ideal focusing
    # to severe aberrations, showing how coherence factors respond to signal quality.

    # Scenario 1: Perfect coherence (all elements receive identical signal)
    beamsum_perfect = np.tile(base_signal[None, :, :], (n_elements, 1, 1))
    coherence_perfect = coherence_factor(beamsum_perfect)

    # Scenario 2: High coherence with small phase variations (good focusing)
    beamsum_high = np.zeros((n_elements, height, width), dtype=np.complex64)
    for i in range(n_elements):
        # Small random phase shifts (simulating good focusing)
        phase_noise = np.random.normal(0, 0.1, (height, width))  # Small phase variations
        beamsum_high[i] = base_signal * np.exp(1j * phase_noise)

    coherence_high = coherence_factor(beamsum_high)

    # Scenario 3: Medium coherence with moderate aberrations
    beamsum_medium = np.zeros((n_elements, height, width), dtype=np.complex64)
    for i in range(n_elements):
        # Moderate phase aberrations
        phase_aberration = np.random.normal(0, 0.5, (height, width))
        amplitude_variation = 1.0 + np.random.normal(0, 0.2, (height, width))
        beamsum_medium[i] = base_signal * amplitude_variation * np.exp(1j * phase_aberration)

    coherence_medium = coherence_factor(beamsum_medium)

    # Scenario 4: Low coherence (strong aberrations/noise)
    beamsum_low = np.zeros((n_elements, height, width), dtype=np.complex64)
    for i in range(n_elements):
        # Strong phase aberrations and amplitude variations
        phase_aberration = np.random.uniform(-np.pi, np.pi, (height, width))
        amplitude_variation = np.random.uniform(0.2, 1.8, (height, width))
        noise = 0.5 * (np.random.randn(height, width) + 1j * np.random.randn(height, width))
        beamsum_low[i] = base_signal * amplitude_variation * np.exp(1j * phase_aberration) + noise

    coherence_low = coherence_factor(beamsum_low)









.. GENERATED FROM PYTHON SOURCE LINES 126-128

4. Visualize the coherence maps
------------------------------------------------------------------------

.. GENERATED FROM PYTHON SOURCE LINES 128-166

.. code-block:: Python


    fig, axes = plt.subplots(2, 4, figsize=(16, 8))

    # Define extent for proper axis scaling (simulate realistic ultrasound coordinates)
    lateral_extent = [-width / 2 * 0.1, width / 2 * 0.1]  # mm
    axial_extent = [0, height * 0.1]  # mm
    extent = [lateral_extent[0], lateral_extent[1], axial_extent[1], axial_extent[0]]

    scenarios = [
        (beamsum_perfect, coherence_perfect, "Perfect Coherence"),
        (beamsum_high, coherence_high, "High Coherence\n(Good Focusing)"),
        (beamsum_medium, coherence_medium, "Medium Coherence\n(Moderate Aberrations)"),
        (beamsum_low, coherence_low, "Low Coherence\n(Strong Aberrations)"),
    ]

    for idx, (beamsum, coherence, title) in enumerate(scenarios):
        # Top row: Magnitude of summed beamforming result
        summed_magnitude = np.abs(np.sum(beamsum, axis=0))

        im1 = axes[0, idx].imshow(summed_magnitude, cmap="gray", extent=extent)
        axes[0, idx].set_title(f"{title}\nMagnitude Image")
        axes[0, idx].set_xlabel("Lateral (mm)")
        if idx == 0:
            axes[0, idx].set_ylabel("Axial (mm)")
        plt.colorbar(im1, ax=axes[0, idx], shrink=0.8)

        # Bottom row: Coherence factor
        im2 = axes[1, idx].imshow(coherence, cmap="viridis", vmin=0, vmax=1, extent=extent)
        axes[1, idx].set_title(f"Coherence Factor\nMean: {coherence.mean():.3f}")
        axes[1, idx].set_xlabel("Lateral (mm)")
        if idx == 0:
            axes[1, idx].set_ylabel("Axial (mm)")
        plt.colorbar(im2, ax=axes[1, idx], shrink=0.8, label="Coherence")

    plt.tight_layout()
    plt.show()





.. image-sg:: /example_gallery/images/sphx_glr_plot_coherence_factor_001.png
   :alt: Perfect Coherence Magnitude Image, High Coherence (Good Focusing) Magnitude Image, Medium Coherence (Moderate Aberrations) Magnitude Image, Low Coherence (Strong Aberrations) Magnitude Image, Coherence Factor Mean: 1.000, Coherence Factor Mean: 0.990, Coherence Factor Mean: 0.756, Coherence Factor Mean: 0.032
   :srcset: /example_gallery/images/sphx_glr_plot_coherence_factor_001.png
   :class: sphx-glr-single-img





.. GENERATED FROM PYTHON SOURCE LINES 167-169

5. Analyze coherence distribution across scenarios
------------------------------------------------------------------------

.. GENERATED FROM PYTHON SOURCE LINES 169-207

.. code-block:: Python


    fig, axes = plt.subplots(1, 2, figsize=(12, 5))

    # Histogram of coherence values
    coherence_data = [
        (coherence_perfect.flatten(), "Perfect", "red"),
        (coherence_high.flatten(), "High", "orange"),
        (coherence_medium.flatten(), "Medium", "green"),
        (coherence_low.flatten(), "Low", "blue"),
    ]

    for coherence_vals, label, color in coherence_data:
        # Use consistent binning across all datasets for fair comparison
        axes[0].hist(coherence_vals, bins=50, alpha=0.7, label=label, color=color, range=(0, 1), density=False)

    axes[0].set_xlabel("Coherence Factor")
    axes[0].set_ylabel("Count")
    axes[0].set_title("Distribution of Coherence Values")
    axes[0].legend()
    axes[0].grid(True, alpha=0.3)

    # Box plot comparison
    coherence_values = [
        coherence_perfect.flatten(),
        coherence_high.flatten(),
        coherence_medium.flatten(),
        coherence_low.flatten(),
    ]
    labels = ["Perfect", "High", "Medium", "Low"]

    axes[1].boxplot(coherence_values, tick_labels=labels)
    axes[1].set_ylabel("Coherence Factor")
    axes[1].set_title("Coherence Factor Distribution by Scenario")
    axes[1].grid(True, alpha=0.3)

    plt.tight_layout()
    plt.show()




.. image-sg:: /example_gallery/images/sphx_glr_plot_coherence_factor_002.png
   :alt: Distribution of Coherence Values, Coherence Factor Distribution by Scenario
   :srcset: /example_gallery/images/sphx_glr_plot_coherence_factor_002.png
   :class: sphx-glr-single-img





.. GENERATED FROM PYTHON SOURCE LINES 208-214

6. Compare magnitude-based vs power-based coherence formulations
------------------------------------------------------------------------
Two mathematical formulations exist in the literature:

• Magnitude-based: CF = \\|Σ s_i\\| / Σ \\|s_i\\| (original formulation)
• Power-based: CF = \\|Σ s_i\\|² / (M * Σ \\|s_i\\|²) (vbeam library)

.. GENERATED FROM PYTHON SOURCE LINES 214-256

.. code-block:: Python


    # Test with perfect coherence scenario
    coherence_perfect_mag = coherence_factor(beamsum_perfect, power_based=False)
    coherence_perfect_pow = coherence_factor(beamsum_perfect, power_based=True)

    # Test with low coherence scenario
    coherence_low_mag = coherence_factor(beamsum_low, power_based=False)
    coherence_low_pow = coherence_factor(beamsum_low, power_based=True)

    # Create comparison visualization
    fig, axes = plt.subplots(2, 2, figsize=(12, 10))

    # Perfect coherence comparison
    im00 = axes[0, 0].imshow(coherence_perfect_mag, cmap="viridis", vmin=0, vmax=1, extent=extent)
    axes[0, 0].set_title(f"Perfect Coherence (Magnitude)\nMean: {coherence_perfect_mag.mean():.6f}")
    axes[0, 0].set_xlabel("Lateral (mm)")
    axes[0, 0].set_ylabel("Axial (mm)")
    plt.colorbar(im00, ax=axes[0, 0], label="coherence")

    im01 = axes[0, 1].imshow(coherence_perfect_pow, cmap="viridis", vmin=0, vmax=1, extent=extent)
    axes[0, 1].set_title(f"Perfect Coherence (Power)\nMean: {coherence_perfect_pow.mean():.6f}")
    axes[0, 1].set_xlabel("Lateral (mm)")
    axes[0, 1].set_ylabel("Axial (mm)")
    plt.colorbar(im01, ax=axes[0, 1], label="coherence")

    # Low coherence comparison
    im10 = axes[1, 0].imshow(coherence_low_mag, cmap="viridis", vmin=0, vmax=1, extent=extent)
    axes[1, 0].set_title(f"Low Coherence (Magnitude)\nMean: {coherence_low_mag.mean():.6f}")
    axes[1, 0].set_xlabel("Lateral (mm)")
    axes[1, 0].set_ylabel("Axial (mm)")
    plt.colorbar(im10, ax=axes[1, 0], label="coherence")

    im11 = axes[1, 1].imshow(coherence_low_pow, cmap="viridis", vmin=0, vmax=1, extent=extent)
    axes[1, 1].set_title(f"Low Coherence (Power)\nMean: {coherence_low_pow.mean():.6f}")
    axes[1, 1].set_xlabel("Lateral (mm)")
    axes[1, 1].set_ylabel("Axial (mm)")
    plt.colorbar(im11, ax=axes[1, 1], label="coherence")

    plt.tight_layout()
    plt.show()





.. image-sg:: /example_gallery/images/sphx_glr_plot_coherence_factor_003.png
   :alt: Perfect Coherence (Magnitude) Mean: 1.000000, Perfect Coherence (Power) Mean: 1.000000, Low Coherence (Magnitude) Mean: 0.175807, Low Coherence (Power) Mean: 0.031737
   :srcset: /example_gallery/images/sphx_glr_plot_coherence_factor_003.png
   :class: sphx-glr-single-img





.. GENERATED FROM PYTHON SOURCE LINES 257-261

7. Individual Channel Visualization (Before Beamforming)
------------------------------------------------------------------------
Individual channel visualization shows magnitude, phase, and real components
before beamforming to understand signal relationships

.. GENERATED FROM PYTHON SOURCE LINES 261-306

.. code-block:: Python


    # Select a few channels to visualize (channels 5, 15, 25)
    channels_to_show = [5, 15, 25]
    channel_labels = [f"Channel {ch}" for ch in channels_to_show]

    # Use medium coherence data for demonstration
    selected_beamsum = beamsum_medium

    fig, axes = plt.subplots(3, len(channels_to_show), figsize=(15, 12))

    for i, ch in enumerate(channels_to_show):
        channel_data = selected_beamsum[ch]  # Shape: (height, width)

        # Top row: Magnitude images
        magnitude = np.abs(channel_data)
        im1 = axes[0, i].imshow(magnitude, cmap="gray", extent=extent)
        axes[0, i].set_title(f"{channel_labels[i]}\nMagnitude")
        axes[0, i].set_xlabel("Lateral (mm)")
        if i == 0:
            axes[0, i].set_ylabel("Axial (mm)")
        plt.colorbar(im1, ax=axes[0, i], shrink=0.8)

        # Middle row: Phase images (using circular colormap)
        phase = np.angle(channel_data)
        im2 = axes[1, i].imshow(phase, cmap="hsv", vmin=-np.pi, vmax=np.pi, extent=extent)
        axes[1, i].set_title("Phase (radians)")
        axes[1, i].set_xlabel("Lateral (mm)")
        if i == 0:
            axes[1, i].set_ylabel("Axial (mm)")
        plt.colorbar(im2, ax=axes[1, i], shrink=0.8)

        # Bottom row: Real part
        real_part = np.real(channel_data)
        im3 = axes[2, i].imshow(real_part, cmap="RdBu_r", extent=extent)
        axes[2, i].set_title("Real Part")
        axes[2, i].set_xlabel("Lateral (mm)")
        if i == 0:
            axes[2, i].set_ylabel("Axial (mm)")
        plt.colorbar(im3, ax=axes[2, i], shrink=0.8)

    plt.suptitle("Individual Channel Data (Before Beamforming)", fontsize=16)
    plt.tight_layout()
    plt.show()





.. image-sg:: /example_gallery/images/sphx_glr_plot_coherence_factor_004.png
   :alt: Individual Channel Data (Before Beamforming), Channel 5 Magnitude, Channel 15 Magnitude, Channel 25 Magnitude, Phase (radians), Phase (radians), Phase (radians), Real Part, Real Part, Real Part
   :srcset: /example_gallery/images/sphx_glr_plot_coherence_factor_004.png
   :class: sphx-glr-single-img





.. GENERATED FROM PYTHON SOURCE LINES 307-310

8. Delay-and-Sum Beamforming vs Coherence Factors
------------------------------------------------------------------------
Compare DAS beamformed image with coherence quality map

.. GENERATED FROM PYTHON SOURCE LINES 310-338

.. code-block:: Python


    # Compute delay-and-sum (DAS) beamformed image
    das_image = np.sum(selected_beamsum, axis=0)
    das_magnitude = np.abs(das_image)

    # Compute standard coherence factor
    cf_standard = coherence_factor(selected_beamsum, power_based=False)

    fig, axes = plt.subplots(1, 2, figsize=(12, 6))

    # DAS magnitude image
    im1 = axes[0].imshow(das_magnitude, cmap="gray", extent=extent)
    axes[0].set_title("Delay-and-Sum Beamformed Image\n(Sum of all channels)")
    axes[0].set_xlabel("Lateral (mm)")
    axes[0].set_ylabel("Axial (mm)")
    plt.colorbar(im1, ax=axes[0], shrink=0.8)

    # Coherence factor
    im2 = axes[1].imshow(cf_standard, cmap="viridis", vmin=0, vmax=1, extent=extent)
    axes[1].set_title("Standard Coherence Factor\n(Quality Map)")
    axes[1].set_xlabel("Lateral (mm)")
    axes[1].set_ylabel("Axial (mm)")
    plt.colorbar(im2, ax=axes[1], shrink=0.8, label="Coherence")

    plt.tight_layout()
    plt.show()





.. image-sg:: /example_gallery/images/sphx_glr_plot_coherence_factor_005.png
   :alt: Delay-and-Sum Beamformed Image (Sum of all channels), Standard Coherence Factor (Quality Map)
   :srcset: /example_gallery/images/sphx_glr_plot_coherence_factor_005.png
   :class: sphx-glr-single-img





.. GENERATED FROM PYTHON SOURCE LINES 339-342

9. Comparison of Different Coherence Factor Types
------------------------------------------------------------------------
Compare all coherence factor types: Standard, Generalized, Sign, and Phase

.. GENERATED FROM PYTHON SOURCE LINES 342-377

.. code-block:: Python


    # Compute all coherence factor types
    cf_magnitude = coherence_factor(selected_beamsum, power_based=False)
    cf_power = coherence_factor(selected_beamsum, power_based=True)
    gcf = generalized_coherence_factor(selected_beamsum)  # Optimal for diffuse scatterers
    scf = sign_coherence_factor(selected_beamsum, power=1.0)
    pcf = phase_coherence_factor(selected_beamsum, power=1.0)

    # Create comparison visualization
    coherence_types = [
        (cf_magnitude, "Standard CF\n(Magnitude-based)", "Standard coherence factor using magnitude ratios"),
        (cf_power, "Standard CF\n(Power-based)", "Power-based coherence factor (vbeam-compatible)"),
        (gcf, "Generalized CF\n(GCF)", "Uses spatial DFT for robustness in speckle regions"),
        (scf, "Sign CF\n(SCF)", "Uses only signal polarity - hardware efficient"),
        (pcf, "Phase CF\n(PCF)", "Based on phase coherence - amplitude independent"),
    ]

    fig, axes = plt.subplots(2, 3, figsize=(18, 12))
    axes = axes.flatten()

    for i, (cf_data, title, _description) in enumerate(coherence_types):
        im = axes[i].imshow(cf_data, cmap="viridis", vmin=0, vmax=1, extent=extent)
        axes[i].set_title(f"{title}\nMean: {cf_data.mean():.3f}")
        axes[i].set_xlabel("Lateral (mm)")
        axes[i].set_ylabel("Axial (mm)")
        plt.colorbar(im, ax=axes[i], shrink=0.8, label="Coherence")

    # Remove the last subplot (we only have 5 coherence types)
    axes[5].remove()

    plt.suptitle("Comparison of Different Coherence Factor Types", fontsize=16)
    plt.tight_layout()
    plt.show()





.. image-sg:: /example_gallery/images/sphx_glr_plot_coherence_factor_006.png
   :alt: Comparison of Different Coherence Factor Types, Standard CF (Magnitude-based) Mean: 0.886, Standard CF (Power-based) Mean: 0.756, Generalized CF (GCF) Mean: 0.772, Sign CF (SCF) Mean: 0.543, Phase CF (PCF) Mean: 0.886
   :srcset: /example_gallery/images/sphx_glr_plot_coherence_factor_006.png
   :class: sphx-glr-single-img





.. GENERATED FROM PYTHON SOURCE LINES 378-381

10. Quantitative Comparison of Coherence Factors
------------------------------------------------------------------------
Quantitative comparison of coherence factor statistics

.. GENERATED FROM PYTHON SOURCE LINES 381-417

.. code-block:: Python


    # Compute statistics for each coherence factor type
    cf_stats = []
    for cf_data, name, _ in coherence_types:
        stats = {
            "name": name,
            "mean": float(cf_data.mean()),
            "std": float(cf_data.std()),
            "min": float(cf_data.min()),
            "max": float(cf_data.max()),
            "median": float(np.median(cf_data)),
        }
        cf_stats.append(stats)


    # Create histograms of coherence values
    fig, axes = plt.subplots(2, 3, figsize=(15, 10))
    axes = axes.flatten()

    colors = ["red", "orange", "green", "blue", "purple"]
    for i, ((cf_data, name, _), color) in enumerate(zip(coherence_types, colors)):
        axes[i].hist(cf_data.flatten(), bins=50, alpha=0.7, color=color, density=True)
        axes[i].set_xlabel("Coherence Value")
        axes[i].set_ylabel("Density")
        axes[i].set_title(name)
        axes[i].grid(True, alpha=0.3)
        axes[i].set_xlim(0, 1)

    # Remove the last subplot
    axes[5].remove()

    plt.suptitle("Distribution of Coherence Values by Type", fontsize=16)
    plt.tight_layout()
    plt.show()





.. image-sg:: /example_gallery/images/sphx_glr_plot_coherence_factor_007.png
   :alt: Distribution of Coherence Values by Type, Standard CF (Magnitude-based), Standard CF (Power-based), Generalized CF (GCF), Sign CF (SCF), Phase CF (PCF)
   :srcset: /example_gallery/images/sphx_glr_plot_coherence_factor_007.png
   :class: sphx-glr-single-img





.. GENERATED FROM PYTHON SOURCE LINES 418-422

11. GCF Parameter M0 Analysis
------------------------------------------------------------------------
Demonstrate the effect of the M0 parameter in Generalized Coherence Factor
This is the spatial-frequency (i.e. field-of-view) cutoff for the GCF.

.. GENERATED FROM PYTHON SOURCE LINES 422-464

.. code-block:: Python


    # Demonstrate the effect of different M0 values as discussed in Li & Li (2003)
    # M0 controls the width of the low-frequency region used for GCF calculation
    # Reduce to 3 values for cleaner 1x3 layout
    m0_values = [0, 1, 2]
    gcf_m0_results = []

    for m0 in m0_values:
        try:
            gcf_m0 = generalized_coherence_factor(selected_beamsum, m0=m0)
            gcf_m0_results.append((gcf_m0, m0))
            mean_val = gcf_m0.mean()
            std_val = gcf_m0.std()
            print(f"   M0={m0}: Mean={mean_val:.3f}, Std={std_val:.3f}")
        except ValueError as e:
            print(f"   M0={m0}: {e}")
            gcf_m0_results.append((None, m0))

    # Visualize different M0 values
    fig, axes = plt.subplots(1, 3, figsize=(15, 5))

    for i, (gcf_data, m0) in enumerate(gcf_m0_results):
        if gcf_data is not None:
            im = axes[i].imshow(gcf_data, cmap="viridis", vmin=0, vmax=1, extent=extent)
            axes[i].set_title(f"GCF with M0={m0}\nMean: {gcf_data.mean():.3f} ± {gcf_data.std():.3f}")
            axes[i].set_xlabel("Azimuth (mm)")
            axes[i].set_ylabel("Range (mm)")
            plt.colorbar(im, ax=axes[i], fraction=0.046, pad=0.04)
        else:
            axes[i].text(0.5, 0.5, f"M0={m0}\nInvalid", ha="center", va="center", transform=axes[i].transAxes, fontsize=14)
            axes[i].set_title(f"GCF with M0={m0} (Invalid)")
            axes[i].axis("off")

    plt.suptitle(
        "Effect of GCF Cutoff Frequency M0\n"
        + "M0=0: Point targets only | M0=1: Optimal for diffuse scatterers | M0=2: More stable",
        fontsize=14,
    )
    plt.tight_layout()
    plt.show()





.. image-sg:: /example_gallery/images/sphx_glr_plot_coherence_factor_008.png
   :alt: Effect of GCF Cutoff Frequency M0 M0=0: Point targets only | M0=1: Optimal for diffuse scatterers | M0=2: More stable, GCF with M0=0 Mean: 0.756 ± 0.048, GCF with M0=1 Mean: 0.772 ± 0.046, GCF with M0=2 Mean: 0.788 ± 0.045
   :srcset: /example_gallery/images/sphx_glr_plot_coherence_factor_008.png
   :class: sphx-glr-single-img


.. rst-class:: sphx-glr-script-out

 .. code-block:: none

       M0=0: Mean=0.756, Std=0.048
       M0=1: Mean=0.772, Std=0.046
       M0=2: Mean=0.788, Std=0.045




.. GENERATED FROM PYTHON SOURCE LINES 465-469

12. Spatial Smoothing Effect
------------------------------------------------------------------------
Many methods, such as [2]_, smooth the coherence map to reduce noise
before using it for aberration correction.

.. GENERATED FROM PYTHON SOURCE LINES 469-504

.. code-block:: Python


    # Effect of spatial smoothing on coherence maps

    # Apply different levels of spatial smoothing to standard coherence factor
    cf_original = coherence_factor(selected_beamsum, power_based=False)

    # Different smoothing kernel sizes - reduced to 3 for cleaner layout
    smoothing_kernels = [1, 3, 5]  # in pixels
    smoothed_cfs = []

    for kernel_size in smoothing_kernels:
        if kernel_size == 1:
            # No smoothing
            smoothed_cf = cf_original
        else:
            # Gaussian smoothing
            smoothed_cf = ndimage.gaussian_filter(cf_original, sigma=kernel_size / 2)
        smoothed_cfs.append(smoothed_cf)

    fig, axes = plt.subplots(1, 3, figsize=(15, 5))

    for i, (smoothed_cf, kernel_size) in enumerate(zip(smoothed_cfs, smoothing_kernels)):
        im = axes[i].imshow(smoothed_cf, cmap="viridis", vmin=0, vmax=1, extent=extent)
        if kernel_size == 1:
            title = f"Original (No Smoothing)\nMean: {smoothed_cf.mean():.3f}"
        else:
            title = f"Gaussian sigma={kernel_size / 2:.1f}\nMean: {smoothed_cf.mean():.3f}"
        axes[i].set_title(title)
        axes[i].set_xlabel("Lateral (mm)")
        axes[i].set_ylabel("Axial (mm)")
        plt.colorbar(im, ax=axes[i], shrink=0.8)

    plt.suptitle("Effect of Spatial Smoothing on Coherence Factor", fontsize=16)
    plt.tight_layout()
    plt.show()



.. image-sg:: /example_gallery/images/sphx_glr_plot_coherence_factor_009.png
   :alt: Effect of Spatial Smoothing on Coherence Factor, Original (No Smoothing) Mean: 0.886, Gaussian sigma=1.5 Mean: 0.886, Gaussian sigma=2.5 Mean: 0.886
   :srcset: /example_gallery/images/sphx_glr_plot_coherence_factor_009.png
   :class: sphx-glr-single-img






.. rst-class:: sphx-glr-timing

   **Total running time of the script:** (0 minutes 4.344 seconds)


.. _sphx_glr_download_example_gallery_plot_coherence_factor.py:

.. only:: html

  .. container:: sphx-glr-footer sphx-glr-footer-example

    .. container:: sphx-glr-download sphx-glr-download-jupyter

      :download:`Download Jupyter notebook: plot_coherence_factor.ipynb <plot_coherence_factor.ipynb>`

    .. container:: sphx-glr-download sphx-glr-download-python

      :download:`Download Python source code: plot_coherence_factor.py <plot_coherence_factor.py>`

    .. container:: sphx-glr-download sphx-glr-download-zip

      :download:`Download zipped: plot_coherence_factor.zip <plot_coherence_factor.zip>`


.. only:: html

 .. rst-class:: sphx-glr-signature

    `Gallery generated by Sphinx-Gallery <https://sphinx-gallery.github.io>`_
