JWST Image Analysis: Exploring the Wonders of Space with Python and Dash

Exploring the Universe: JWST Image Analysis with Python and Dash featured image JWST

In the field of astronomy, the James Webb Space Telescope (JWST) is a highly anticipated and powerful instrument that will revolutionize our understanding of the universe. To fully utilize the capabilities of the JWST, efficient image analysis techniques are essential. In this article, we will explore how to perform image analysis on JWST images using Python and Dash, a popular web framework for building interactive data visualizations.

The James Webb Space Telescope is the successor to the Hubble Space Telescope and is designed to observe the universe in the infrared spectrum. It will provide astronomers with unprecedented views of distant galaxies, star formation regions, and exoplanets. However, analyzing the data captured by the JWST requires specialized techniques due to the complexity and volume of the observations.

Exploring JWST Images with Python and Dash | Image Analysis Tool

Setting up the Dash Application and other required Libraries

To begin our image analysis journey, we need to set up a Dash application that will serve as the foundation for our interactive tool. Dash provides a user-friendly interface for creating web applications with Python. Let’s import the necessary libraries to perform image analysis and initialize the Dash app:

import dash
import dash_bootstrap_components as dbc
import dash_canvas
import dash_table
import plotly.graph_objects as go
import numpy as np
import matplotlib.pyplot as plt
import io
import base64
py.signal import find_peaks
from PIL import Image
from dash import dcc, html
from dash.dependencies import Input, Output
from scipy import ndimage
from skimage import filters, morphology, io
from skimage.measure import label
from matplotlib.patches import Circle
from sci


# Initialize the Dash app
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])

# Define the layout of the app

Uploading an Image and Defining App Layout

One of the essential functionalities of our tool is the ability to upload JWST images for analysis. We can achieve this using the dcc.Upload component provided by Dash. This component allows users to drag and drop or select an image file from their local system. Let’s add the image upload functionality to our app:

app.layout = dbc.Container(
    [
        dbc.Row(
            dbc.Col(html.H1("JWST Image Analysis"), className="text-center mt-5")
        ),
        dbc.Row(dbc.Col(dcc.Upload(
                id="upload-image",
                children=html.Div(
                    ["Drag and drop or click to select an image of JWST"]
                ),
                style={
                    "width": "100%",
                    "height": "60px",
                    "lineHeight": "60px",
                    "borderWidth": "1px",
                    "borderStyle": "dashed",
                    "borderRadius": "5px",
                    "textAlign": "center",
                    "margin": "10px",
                },
                multiple=False,
            ),
            width=12,
        )),
        dbc.Row(dbc.Col(
            dcc.Loading(
                dcc.Graph(id="spectrum-graph"),
                type="default",
                style={"height": "300px"},
            ),
            width=12,
        )),
        html.Div(
            [
                html.H3("Original Image"),
                html.Div(id="original-image-container"),  # Placeholder for the original uploaded image
                html.Div(id="filtered-images"),  # Placeholder for the filtered images
            ],
            className="filtered-images-container",
            style={"margin-top": "30px"},
        ),
        html.Div(id="stars-table")  # Placeholder for the detected stars table
    ],
    fluid=True,
)

Spectrum Analysis

After uploading an image, we can perform spectrum analysis to extract valuable information about the captured light. Spectrum analysis involves analyzing the intensity of light at different wavelengths. To visualize the spectrum, we can use the Plotly library.

def process_image(image):
    # Convert the image to grayscale
    grayscale_image = np.mean(image, axis=2)

    # Perform spectrum analysis
    spectrum = np.mean(grayscale_image, axis=0)

    # Find peaks in the spectrum
    peaks, _ = find_peaks(spectrum, distance=30, prominence=5)

    return spectrum, peaks

Image Filtering and Processing

To enhance the quality of JWST images and improve the accuracy of subsequent analysis, we can apply various image filtering techniques. In our tool, we will demonstrate the application of Gaussian, median, and maximum filters. The filtered images will be displayed alongside the original image. We use scipy, skimage and numpy libraries to process these images.

def apply_filters(image):
    # Apply Gaussian filter
    image_gaussian = filters.gaussian(image, sigma=1)

    # Apply median filter
    image_median = filters.median(image)

    # Apply maximum filter
    image_max = ndimage.maximum_filter(image, size=3)

    return image_gaussian, image_median, image_max

Detecting Stars

One of the exciting aspects of JWST images is the ability to detect stars and study their properties. To identify stars in an image, we can utilize techniques like local maxima detection. By identifying regions of the image with high intensity compared to their surroundings, we can locate potential stars.

Python Code: GitHub Repository Link

import dash
import dash_bootstrap_components as dbc
import dash_canvas
import dash_table
import plotly.graph_objects as go
import numpy as np
import matplotlib.pyplot as plt
import io
import base64
py.signal import find_peaks
from PIL import Image
from dash import dcc, html
from dash.dependencies import Input, Output
from scipy import ndimage
from skimage import filters, morphology, io
from skimage.measure import label
from matplotlib.patches import Circle
from sci


# Initialize the Dash app
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])

# Define the layout of the app
app.layout = dbc.Container(
    [
        dbc.Row(
            dbc.Col(html.H1("JWST Image Analysis"), className="text-center mt-5")
        ),
        dbc.Row(dbc.Col(dcc.Upload(
                id="upload-image",
                children=html.Div(
                    ["Drag and drop or click to select an image of JWST"]
                ),
                style={
                    "width": "100%",
                    "height": "60px",
                    "lineHeight": "60px",
                    "borderWidth": "1px",
                    "borderStyle": "dashed",
                    "borderRadius": "5px",
                    "textAlign": "center",
                    "margin": "10px",
                },
                multiple=False,
            ),
            width=12,
        )),
        dbc.Row(dbc.Col(
            dcc.Loading(
                dcc.Graph(id="spectrum-graph"),
                type="default",
                style={"height": "300px"},
            ),
            width=12,
        )),
        html.Div(
            [
                html.H3("Original Image"),
                html.Div(id="original-image-container"),  # Placeholder for the original uploaded image
                html.Div(id="filtered-images"),  # Placeholder for the filtered images
            ],
            className="filtered-images-container",
            style={"margin-top": "30px"},
        ),
        html.Div(id="stars-table")  # Placeholder for the detected stars table
    ],
    fluid=True,
)


def process_image(image):
    # Convert the image to grayscale
    grayscale_image = np.mean(image, axis=2)

    # Perform spectrum analysis
    spectrum = np.mean(grayscale_image, axis=0)

    # Find peaks in the spectrum
    peaks, _ = find_peaks(spectrum, distance=30, prominence=5)

    return spectrum, peaks


def apply_filters(image):
    # Apply Gaussian filter
    image_gaussian = filters.gaussian(image, sigma=1)

    # Apply median filter
    image_median = filters.median(image)

    # Apply maximum filter
    image_max = ndimage.maximum_filter(image, size=3)

    return image_gaussian, image_median, image_max


@app.callback(
    Output("spectrum-graph", "figure"),
    Output("original-image-container", "children"),  # Added output for displaying the original uploaded image
    Output("filtered-images", "children"),
    Output("stars-table", "children"),
    Input("upload-image", "contents"),
    prevent_initial_call=True,
)
def update_spectrum(contents):
    if contents is None:
        # Handle case when no file is uploaded
        return go.Figure(), html.Div(), html.Div(), html.Div()

    # Get the uploaded image
    _, content_string = contents.split(",")
    image = Image.open(io.BytesIO(base64.b64decode(content_string)))

    # Convert the image to numpy array
    image_array = np.array(image)
    image_array2 = np.array(image)

    # Process the image
    spectrum, peaks = process_image(image_array)

    threshold_value = np.mean(image_array) + 2 * np.std(image_array)  # set the threshold value
    image_max = np.copy(image_array)
    image_max[image_max < threshold_value] = 0  # zero out all values below the threshold
    labeled = label(image_max)  # label the connected components in the image

    # Update the is_local_maximum function with local_maxima function
    lm = morphology.local_maxima(image_array)
    coords = np.where(np.logical_and(lm, image_array > threshold_value))
    x1, y1 = coords[0], coords[1]
    v = image_array[(x1, y1)]
    lim = 0.7
    indices = np.where(v > lim)[0]

    # Handle the case when no local maxima are found
    if len(indices) == 0:
        print("No local maxima found.")
        detected_stars = []
    else:
        x2, y2 = x1[indices], y1[indices]
        detected_stars = list(zip(x2, y2))
        # print("Stars detected at positions:", detected_stars)

        # Add red circles to the image_array
        for star in detected_stars:
            x, y = star
            image_array[x, y] = [255, 0, 0]  # Red color

    # Create the spectrum plot
    fig = go.Figure()
    fig.add_trace(go.Scatter(x=np.arange(len(spectrum)), y=spectrum, name="Spectrum"))
    fig.add_trace(
        go.Scatter(
            x=peaks,
            y=spectrum[peaks],
            mode="markers",
            name="Peaks",
            marker=dict(color="red", size=8),
        )
    )
    fig.update_layout(
        title="Spectrum Analysis",
        xaxis_title="Pixel",
        yaxis_title="Intensity",
        template="plotly_white",
    )

    # Apply filters to the image
    image_gaussian, image_median, image_max = apply_filters(image_array)
    canvas_width = 500
    canvas_height = 250

    # Display the original uploaded image
    original_image = html.Div(
        [
            html.H4("Original Uploaded Image"),
            html.Img(
                src=image_to_data_url(image_array2),
                style={"max-width": "100%", "max-height": "80%"},
            ),
        ],
        className="img-zoom-container",
        style={
            "height": "650px",
            "width": "100%",
            "border": "1px solid gray",
            "padding": "10px",
            "text-align": "center",
        },
    )

    # Display the filtered images with zoom functionality
    filtered_images = html.Div(
        [
            html.H3("Filtered Images"),
            dbc.Row(
                [
                    dbc.Col(
                        html.Div(
                            [
                                html.H4("Image with Gaussian Filter"),
                                dash_canvas.DashCanvas(
                                    id="canvas-gaussian",
                                    width=canvas_width,
                                    height=canvas_height,
                                    image_content=image_to_data_url(image_gaussian),
                                ),
                            ],
                            className="img-zoom-container",
                            style={
                                "height": "650px",
                                "width": "650px",
                                "border": "1px solid gray",
                                "padding": "10px",
                            },
                        ),
                        width=6,
                        style={"margin-bottom": "80px", "padding-right": "5px"},
                    ),
                    dbc.Col(
                        html.Div(
                            [
                                html.H4("Image withMedian Filter"),
                                dash_canvas.DashCanvas(
                                    id="canvas-median",
                                    width=canvas_width,
                                    height=canvas_height,
                                    image_content=image_to_data_url(image_median),
                                ),
                            ],
                            className="img-zoom-container",
                            style={
                                "height": "650px",
                                "width": "650px",
                                "border": "1px solid gray",
                                "padding": "10px",
                            },
                        ),
                        width=6,
                        style={"margin-bottom": "80px", "padding-left": "5px"},
                    ),
                    dbc.Col(
                        html.Div(
                            [
                                html.H4("Image with Maximum Filter"),
                                dash_canvas.DashCanvas(
                                    id="canvas-max",
                                    width=canvas_width,
                                    height=canvas_height,
                                    image_content=image_to_data_url(image_max),
                                ),
                            ],
                            className="img-zoom-container",
                            style={
                                "height": "650px",
                                "width": "650px",
                                "border": "1px solid gray",
                                "padding": "10px",
                            },
                        ),
                        width=6,
                        style={"margin-bottom": "80px", "padding-right": "5px"},
                    ),
                    dbc.Col(
                        html.Div(
                            [
                                html.H4("Image with detected stars"),
                                dash_canvas.DashCanvas(
                                    id="canvas-detected-stars",
                                    width=canvas_width,
                                    height=canvas_height,
                                    image_content=image_to_data_url(image_array),
                                ),
                            ],
                            className="img-zoom-container",
                            style={
                                "height": "650px",
                                "width": "650px",
                                "border": "1px solid gray",
                                "padding": "10px",
                            },
                        ),
                        width=6,
                        style={"margin-bottom": "80px", "padding-left": "5px"},
                    ),
                ],
                style={"margin-left": "-5px", "margin-right": "-5px"},
            ),
        ],
    )

    # Create a data table for the detected stars
    stars_table = html.Div(
        [
            html.H3("Detected Stars"),
            dash_table.DataTable(
                id="stars-data-table",
                columns=[{"name": "Star ID", "id": "id"}, {"name": "Position", "id": "position"}],
                data=[{"id": i+1, "position": f"{star[0]}, {star[1]}"} for i, star in enumerate(detected_stars)],
                style_cell={'textAlign': 'center'},
                style_header={'fontWeight': 'bold'},
            ),
        ],
        className="stars-table-container",
    )

    return fig, original_image, filtered_images, stars_table


def image_to_data_url(image):
    img = Image.fromarray(image.astype(np.uint8))  # Convert to uint8 data type
    img = img.convert("RGB")  # Convert to RGB mode
    buffer = io.BytesIO()
    img.save(buffer, format="PNG")
    data_url = base64.b64encode(buffer.getvalue()).decode("utf-8")
    return f"data:image/png;base64,{data_url}"


if __name__ == "__main__":
    app.run_server(debug=True)

In this article, we have explored how to perform image analysis on JWST images using Python and Dash. We have covered the setup of a Dash application, image upload functionality, spectrum analysis, image filtering, and star detection. With these techniques at our disposal, we can delve into the wonders of space captured by the JWST and gain valuable insights into the universe.

FAQs

Q1: How can I access the JWST Image Analysis tool?

A: You can access the JWST Image Analysis tool by visiting https://github.com/kantherabhishek/JWST-Image-Analysis-Dash

Q2: Can I analyze images captured by telescopes other than JWST?

A: While this tool is specifically designed for analyzing JWST images, you can modify and adapt the code to analyze images captured by other telescopes as well.

Q3: Is the tool capable of handling large datasets of JWST images?

A: Yes, the tool is designed to handle large datasets of JWST images. However, you may need to optimize the code further for extremely large datasets.

Q4: Can I export the analyzed data for further analysis?

A: Yes, you can export the analyzed data in various formats supported by Python, such as CSV or Excel, for further analysis using other tools or libraries.

Q5: Are there any specific system requirements for running the JWST Image Analysis tool?

A: The tool requires a system with Python and the necessary libraries installed. Please refer to the documentation for the specific requirements and dependencies.

In conclusion, the JWST Image Analysis tool empowers astronomers and researchers to delve into the mysteries of the universe by analyzing JWST images using Python and Dash. With its intuitive interface and powerful capabilities, the tool opens new doors for understanding celestial objects and phenomena.

%d bloggers like this: