If seems the first decider us not being included by installer-. I would ask
the astropy folks where/how the decoders are discovered.

In the meantime, maybe try setting astropy.io or even astropy.io.fits as a
hidden import.

Though if you aren’t getting an import error, then the (python) module is
there — but it seems to rely on a data file, or library or something that
isn’t being included.

-CHB

Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R            (206) 526-6959   voice
7600 Sand Point Way NE   (206) 526-6329   fax
Seattle, WA  98115       (206) 526-6317   main reception

[email protected]


On Tue, Mar 18, 2025 at 6:32 AM skyjudith JAI <[email protected]> wrote:

> Here is the second fits file.
>
> On Mon, Mar 17, 2025 at 5:05 PM 'Chris Barker' via PyInstaller <
> [email protected]> wrote:
>
>> Just a suggestion- to make it even easier to diagnose, try a simple
>> script only processes a fits file, without  QT.
>>
>> That will be a far simpler build, and it may be more obvious what’s
>> missing.
>>
>> -CHB
>>
>>
>> Christopher Barker, Ph.D.
>> Oceanographer
>>
>> Emergency Response Division
>> NOAA/NOS/OR&R            (206) 526-6959   voice
>> 7600 Sand Point Way NE
>> <https://www.google.com/maps/search/7600+Sand+Point+Way+NE?entry=gmail&source=g>
>>   (206) 526-6329   fax
>> Seattle, WA  98115       (206) 526-6317   main reception
>>
>> [email protected]
>>
>>
>> On Sun, Mar 16, 2025 at 3:56 PM skyjudith JAI <[email protected]>
>> wrote:
>>
>>> 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
>>> <https://groups.google.com/d/msgid/pyinstaller/4da01cd9-0d2f-47ef-96f3-05b87ee1989bn%40googlegroups.com?utm_medium=email&utm_source=footer>
>>> .
>>>
>> --
>> 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/CALGmxE%2Bs7_q-cwRTU7abB3HYR3V2YjArywUQj_NyK2yZztSSag%40mail.gmail.com
>> <https://groups.google.com/d/msgid/pyinstaller/CALGmxE%2Bs7_q-cwRTU7abB3HYR3V2YjArywUQj_NyK2yZztSSag%40mail.gmail.com?utm_medium=email&utm_source=footer>
>> .
>>
> --
> 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/CABuiZshvX0h0O2M6yJBQx8o-Oh4fBVoiVWcvyY0M2iXaLHQDdg%40mail.gmail.com
> <https://groups.google.com/d/msgid/pyinstaller/CABuiZshvX0h0O2M6yJBQx8o-Oh4fBVoiVWcvyY0M2iXaLHQDdg%40mail.gmail.com?utm_medium=email&utm_source=footer>
> .
>

-- 
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/CALGmxEJBi03C4Ck6VSfDgndG%3DWN-NtQR_xViDXUH0yqik5i%2BPQ%40mail.gmail.com.

Reply via email to