My complete code is very long but I've made a 'minimumtest.py' which shows 
the same behaviour, i.e. works in python but fails after pyinstaller.  The 
minimum code is below (sorry I don't see where I can include it as an 
attachment).  I was aligning 9 fits images but each is 7.4 Mb.  Is there 
somewhere I can put the fits files?
Judith

import sys
import os
import numpy as np
from astropy.io import fits
import astroalign as aa
from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QWidget, QVBoxLayout, QPushButton, 
QFileDialog, QLabel
)
from PyQt5.QtCore import QTimer
import pyqtgraph as pg
import warnings
warnings.simplefilter("ignore", DeprecationWarning)

class FITSAlignmentApp(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("FITS Alignment Test")
        self.setGeometry(100, 100, 800, 600)

        # Main widget
        central_widget = QWidget(self)
        self.setCentralWidget(central_widget)

        # Layout
        layout = QVBoxLayout(central_widget)

        # Load button
        self.load_button = QPushButton("Load FITS Files", self)
        self.load_button.clicked.connect(self.load_fits_files)
        layout.addWidget(self.load_button)

        # Status label
        self.status_label = QLabel("Select FITS files to align", self)
        layout.addWidget(self.status_label)

        # PyQtGraph ImageView
        self.image_view = pg.ImageView()
        layout.addWidget(self.image_view)

        # Timer for sequential loading
        self.timer = QTimer()
        self.timer.timeout.connect(self.show_next_image)
        self.image_index = 0
        self.images = []
        self.aligned_images = []
        self.transforms = []

    def load_fits_files(self):
        """ Open file dialog and load multiple FITS files with delay """
        files, _ = QFileDialog.getOpenFileNames(
            self, "Select FITS Files", os.getcwd(),  # Start in the current 
working directory
            "FITS Files (*.fits *.fit *.fts *.FITS *.FIT *.FTS);;All Files 
(*)"
        )

        if not files:
            self.status_label.setText("No files selected.")
            return

        # Load images
        self.images = []
        for file in files:
            try:
                with fits.open(file) as hdul:
                    data = hdul[0].data
                    if data is not None:
                        self.images.append(data.astype(np.float64))
            except Exception as e:
                self.status_label.setText(f"Error loading {file}: {e}")
                return

        if len(self.images) < 2:
            self.status_label.setText("Need at least 2 images to align.")
            return

        self.status_label.setText(f"Loaded {len(self.images)} images. 
Aligning...")

        # Use the first image as the reference
        self.reference_image = self.images[0]
        self.aligned_images = [self.reference_image]  # First image is 
already "aligned"

        # Align each image to the reference
        self.transforms = []
        for i, img in enumerate(self.images[1:], start=1):
            try:
                # Compute the transformation parameters
                transform, footprint = aa.find_transform(img, 
self.reference_image)

                dx, dy = transform.translation  # Extract x, y shifts
                rotation_rad = transform.rotation  # Extract rotation in 
radians
                rotation_deg = np.degrees(rotation_rad)  # Convert to 
degrees

                # Apply the transformation to align the image
                print(f"Original Image {i} Shape: {img.shape}")
                aligned_img, footprint = aa.apply_transform(transform, img, 
self.reference_image)
                # Ensure aligned_img is a NumPy array
                aligned_img = np.array(aligned_img, dtype=np.float64)
                print(f"Transformed Image {i} Shape: {aligned_img.shape}")
                aligned_img = np.array(aligned_img, dtype=np.float64)
                
                print(f"Image {i}: Δx = {dx:.2f}, Δy = {dy:.2f}, Δrot = 
{rotation_deg:.2f}°")

                # Ensure aligned image has the same shape as the reference 
image
                aligned_img = np.array(aligned_img, dtype=np.float64)

                if aligned_img.shape != self.reference_image.shape:
                    print(f"Warning: Shape mismatch in Image {i}. 
Resizing...")
                    min_shape = (
                        min(aligned_img.shape[0], 
self.reference_image.shape[0]),
                        min(aligned_img.shape[1], 
self.reference_image.shape[1]),
                    )
                    aligned_img = aligned_img[:min_shape[0], :min_shape[1]]
                    self.reference_image = 
self.reference_image[:min_shape[0], :min_shape[1]]

                self.aligned_images.append(aligned_img)
                self.transforms.append(transform)


            except Exception as e:
                print(f"Error aligning image {i}: {e}")
                self.aligned_images.append(img)  # If alignment fails, keep 
original

        self.status_label.setText("Alignment complete. Displaying 
images...")
        self.image_index = 0
        self.timer.start(1000)  # 1-second delay between images

    def extract_transform(self, transform):
        """ Extract translation and rotation from transformation matrix. """
        dx = transform[0, 2]  # Translation in x
        dy = transform[1, 2]  # Translation in y
        rotation_radians = np.arctan2(transform[1, 0], transform[0, 0])
        rotation_degrees = np.degrees(rotation_radians)  # Convert to 
degrees
        return dx, dy, rotation_degrees

    def show_next_image(self):
        """ Show aligned images one by one before displaying the median """
        if self.image_index < len(self.aligned_images):
            current_image = self.aligned_images[self.image_index]
            focus_min, focus_max = self.compute_focus_range(current_image)
            self.image_view.setImage(current_image, levels=(focus_min, 
focus_max))
            self.status_label.setText(f"Showing aligned image 
{self.image_index + 1}/{len(self.aligned_images)}")
            self.image_index += 1
        else:
            # Stop the timer and compute the median
            self.timer.stop()
            self.display_median_image()

    def display_median_image(self):
        """ Compute and display the median-combined image """
        self.status_label.setText("Computing median image...")
        median_image = np.nanmedian(np.stack(self.aligned_images), axis=0)
        focus_min, focus_max = self.compute_focus_range(median_image)
        self.image_view.setImage(median_image, levels=(focus_min, 
focus_max))
        self.status_label.setText("Showing median image.")

    def compute_focus_range(self, data):
        """ Compute focus_min and focus_max dynamically """
        valid_data = data[data != 0]  # Exclude exact zero values
        if valid_data.size > 0:
            median = np.nanmedian(valid_data)
            std = np.nanstd(valid_data)
            min_val = np.nanmin(valid_data)
            max_val = np.nanmax(valid_data)
        else:
            # Fallback if all values are zero
            median = np.nanmedian(data)
            std = np.nanstd(data)
            min_val = np.nanmin(data)
            max_val = np.nanmax(data)

        # Expand range slightly for better visualization
        focus_min = max(median - std, min_val)
        focus_max = min(median + std, max_val)

        return focus_min, focus_max

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = FITSAlignmentApp()
    window.show()
    sys.exit(app.exec_())






On Sunday, March 16, 2025 at 2:52:33 PM UTC-4 bwoodsend wrote:

Presumably whatever submodule/package/data file is responsible for 
supporting these FITS files is not being collected. I can't help beyond 
that without either a minimal example + FITS file to play with or a some 
clue as to what package/file is issuing that error message which will tell 
us where to look for what exactly is missing.

-- 
You received this message because you are subscribed to the Google Groups 
"PyInstaller" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion visit 
https://groups.google.com/d/msgid/pyinstaller/4da01cd9-0d2f-47ef-96f3-05b87ee1989bn%40googlegroups.com.

Reply via email to