Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
126813e
Add GitHub workflow to generate SunscanOS image
melix Dec 16, 2024
f8f1ea8
Add hotspot configuration
melix Dec 22, 2024
ff9f55c
Bump JSol'Ex version
melix Dec 22, 2024
81f7860
Animations feature + Staking feature + New Pan/Zoom component + Impro…
guillbertrand Dec 31, 2024
a41b9e9
update .gitignore
guillbertrand Dec 31, 2024
9d8459b
Add watermark on stacked images
guillbertrand Dec 31, 2024
e1283f0
Merge pull request #9 from melix/cc/build-sunscan-os
guillbertrand Jan 1, 2025
53a7d59
Add tag/line description to watermark
guillbertrand Jan 1, 2025
5e1923e
Fixed sign bug under INTI in detect edge, allows to better process lo…
guillbertrand Jan 1, 2025
9212386
update gh workflow
guillbertrand Jan 1, 2025
75abc0c
Add pip modules
guillbertrand Jan 2, 2025
21cbc5b
update gh workflow
guillbertrand Jan 2, 2025
10bbf61
clean code
guillbertrand Jan 2, 2025
883a3f6
feat: refactoring capture with new image class + new camera class + …
guillbertrand Jan 2, 2025
a7669d8
bug fix + remove flooding logs
guillbertrand Jan 2, 2025
5526d3e
fix: inversion between red and blue channel, use all green signal
splanquart Jan 4, 2025
9ddd164
Merge pull request #13 from splanquart/v1.3.0
guillbertrand Jan 4, 2025
c6f9689
fix: camera + image rpi4
guillbertrand Jan 4, 2025
4e39ec8
bug fix and clean code
guillbertrand Jan 4, 2025
c494c47
updated backend version
guillbertrand Jan 5, 2025
3265120
feat: improve support or pisugar with netcat in image
splanquart Jan 15, 2025
c48f546
Try with ubuntu ARM64
melix Jan 18, 2025
12476fd
Attempt to avoid git clone command
melix Jan 18, 2025
451ed90
feat: install pisugar server in image
splanquart Jan 15, 2025
635ff56
Merge branch 'cc/ubuntu-arm' into pisugar
splanquart Jan 18, 2025
3c475d6
Update pi-gen-sunscan/04-system/04-run-chroot.sh
splanquart Jan 18, 2025
0aed352
Added automatic helium process + fwhm calculation on intensity profile
guillbertrand Jan 19, 2025
22ba6d3
updated helium process
guillbertrand Jan 19, 2025
f57f2a5
improve helium processing
guillbertrand Jan 19, 2025
c52ef74
updated Colorise_Image method
guillbertrand Jan 19, 2025
5d4378e
clean code
guillbertrand Jan 20, 2025
5bb0297
improve color managment
guillbertrand Jan 20, 2025
ae412ec
clean code
guillbertrand Jan 20, 2025
466f4ae
Merge branch 'v1.3.0' into cc/ubuntu-arm
guillbertrand Jan 20, 2025
633c45f
Merge pull request #17 from melix/cc/ubuntu-arm
guillbertrand Jan 20, 2025
0c0b46f
Merge branch 'v1.3.0' of github.com:staros-projects/sunscan-backend i…
guillbertrand Jan 20, 2025
64853e1
Merge pull request #16 from splanquart/pisugar
guillbertrand Jan 20, 2025
fabc33f
updated watermark
guillbertrand Jan 20, 2025
b78c5fb
jsolex stack test
guillbertrand Jan 28, 2025
626b273
Improve protus images (antialisasing) + add doppler eclipse
guillbertrand Jan 28, 2025
e5e60c4
add eclipse on stacked images
guillbertrand Jan 28, 2025
7b9d5c5
add doppler eclipse
guillbertrand Jan 28, 2025
b1b3c29
fix doppler eclipse + updated CI
guillbertrand Jan 28, 2025
33210d0
add color doppler
guillbertrand Feb 18, 2025
4f7dd48
tmp update : added pull_request trigger on ci
guillbertrand Feb 18, 2025
c8ba831
Add Stacking and Animations in webapp
matthieulel Feb 18, 2025
3eef33d
Merge branch 'v1.3.0' into dev
guillbertrand Feb 18, 2025
759c5f6
Revert "V1.3.0"
guillbertrand Feb 18, 2025
2ac886b
Merge pull request #20 from staros-projects/revert-12-v1.3.0
guillbertrand Feb 18, 2025
44e7906
Revert "Revert "V1.3.0""
guillbertrand Feb 18, 2025
22ddd39
Merge pull request #21 from staros-projects/revert-20-revert-12-v1.3.0
guillbertrand Feb 18, 2025
aae769d
updated webapp
guillbertrand Feb 18, 2025
e246ff6
fix footer Layout
guillbertrand Feb 18, 2025
6c09fca
fix cleanup zip files at each new download
matthieulel Feb 18, 2025
1b28bf7
Merge remote-tracking branch 'origin/dev' into dev
matthieulel Feb 18, 2025
fbcc5ab
updated webapp
guillbertrand Feb 18, 2025
2aab7df
fix footer Layout
guillbertrand Feb 18, 2025
01d6d71
Merge branch 'v1.3.0' of https://github.com/staros-projects/sunscan-b…
guillbertrand Feb 22, 2025
a855de9
Generate timestamp and date strings for file naming in UTC
guillbertrand Feb 22, 2025
e027a52
Generate timestamp and date strings for file naming in UTC
guillbertrand Feb 22, 2025
b7f5907
update firmware zip source with v1.3.0
guillbertrand Feb 22, 2025
980a306
Handles CORS preflight requests.
guillbertrand Feb 22, 2025
a74f919
updated souce + updated delete scan method
guillbertrand Feb 22, 2025
21a6914
update webapp logo
guillbertrand Feb 22, 2025
9ce0cbf
Merge branch 'v1.3.0' of https://github.com/staros-projects/sunscan-b…
guillbertrand Feb 22, 2025
1337ce3
updated firmwware backend source ((zip file)
guillbertrand Feb 22, 2025
6bd8aef
Improve Colorise_Image
guillbertrand Feb 22, 2025
649b264
Merge branch 'v1.3.0' of https://github.com/staros-projects/sunscan-b…
guillbertrand Feb 22, 2025
d7596bd
update backend source v1.3.0
guillbertrand Feb 22, 2025
f893149
shudown and reboot endpoint bugfix + new source zip
guillbertrand Feb 23, 2025
b6629d8
disable stacked protu
guillbertrand Feb 28, 2025
71f5a91
Add UT mention in watermark datetime
guillbertrand Mar 1, 2025
cb0eeed
Added 3 configurable options for stacking
guillbertrand Mar 1, 2025
a57c9b2
fix watermark bug
guillbertrand Mar 1, 2025
60e59b5
Add stacked img thumbnail in desktop webapp
guillbertrand Mar 1, 2025
4243de9
update rpi timezone
guillbertrand Mar 1, 2025
64b52b7
Merge branch 'v1.3.0' of github.com:staros-projects/sunscan-backend i…
guillbertrand Mar 1, 2025
588b378
Add log for timezone and datetime sync
guillbertrand Mar 1, 2025
89553ba
fCI firmware libcamera lib update
guillbertrand Mar 1, 2025
e6f21fb
Add animation preview in webapp + fix bug with webapp zip filename + …
guillbertrand Mar 1, 2025
ce15581
webapp source
guillbertrand Mar 1, 2025
027a908
fix webapp zip download + update firmware source
guillbertrand Mar 1, 2025
8ac4ce3
fix package_backend
guillbertrand Mar 2, 2025
8463454
updated source
guillbertrand Mar 2, 2025
8553761
fix: color mode stability
guillbertrand Mar 2, 2025
1003895
update source
guillbertrand Mar 2, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
147 changes: 147 additions & 0 deletions .github/workflows/build-image.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
name: Builds the Sunscan OS image

on:
pull_request:
push:
tags:
- '*.*.*'
branches:
- main
workflow_dispatch:

jobs:
build-image:
runs-on: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v4
- name: Determine version
id: vars
run: |
# Get the tag, if any
TAG=$(git describe --tags --exact-match 2>/dev/null || echo "")

if [ -n "$TAG" ]; then
echo "APP_VERSION=$TAG" >> $GITHUB_ENV
echo "IMGFILENAME=sunscan_os_$TAG" >> $GITHUB_ENV
else
BRANCH=$(git rev-parse --abbrev-ref HEAD)
COMMIT=$(git rev-parse --short HEAD)
echo "APP_VERSION=${BRANCH}_${COMMIT}" >> $GITHUB_ENV
echo "IMGFILENAME=sunscan_os_${BRANCH}_${COMMIT}" >> $GITHUB_ENV
fi
- run: |
{
mkdir -p pi-gen-sunscan/01-prepare-repo
cat > pi-gen-sunscan/01-prepare-repo/00-run.sh <<-EOF
#!/bin/bash
git clone ${{ github.server_url }}/${{ github.event.pull_request.head.repo.full_name || github.repository }}.git --branch ${{ github.head_ref || github.ref_name }} --depth 1 ${WORK_DIR}/tmp/repo
ls -alh ${WORK_DIR}/tmp/repo
EOF
} &&
chmod +x pi-gen-sunscan/01-prepare-repo/00-run.sh

- uses: usimd/pi-gen-action@v1
id: build
with:
compression: xz

# Compression level to be used. From 0 to 9 (refer to the tool man page for more
# information on this. Usually 0 is no compression but very fast, up to 9 with the
# best compression but very slow).
compression-level: 9

# Enable SSH access to Pi.
enable-ssh: 1

export-last-stage-only: true

# Comma or whitespace separated list of additional packages to install on host
# before running pi-gen. Use this list to add any packages your custom stages may
# require. Note that this is not affecting the final image. In order to add
# additional packages, you need to add a respective 'XX-packages' file in your
# custom stage.
extra-host-dependencies: ''

# Comma or whitespace separated list of additional modules to load on host before
# running pi-gen. If your custom stage requires additional software or kernel
# modules to be loaded, add them here. Note that this is not meant to configure
# modules to be loaded in the target image.
extra-host-modules: ''

# Token to use for checking out pi-gen repo.
github-token: ${{ github.token }}

# Host name of the image.
hostname: sunscan

# Final image name.
image-name: ${{ env.IMGFILENAME }}

# Enabling this option will remove plenty of components from the GitHub Actions
# runner that are not mandatory pre-requisites for a (vanilla) pi-gen build. This
# shall increase the available disk space so that also large images can be
# compiled on a free GHA runner (benchmark is the full image including a desktop
# environment). If any packages are missing during the build consider adding them
# to the `extra-host-dependencies` list.
increase-runner-disk-size: false

# Default keyboard keymap.
keyboard-keymap: us

# Default keyboard layout.
keyboard-layout: English (US)

# Default locale of the system image.
locale: en_US.UTF-8

# Password of the intial user account, locked if empty.
password: 'password'

# Path where selected pi-gen ref will be checked out to. If the path does not yet
# exist, it will be created (including its parents).
pi-gen-dir: pi-gen

# The release name to use in `/etc/issue.txt`. The default should only be used for
# official Raspberry Pi builds.
pi-gen-release: Raspberry Pi reference

# GitHub repository to fetch pi-gen from, must be a fork from RPi-Distro/pi-gen.
pi-gen-repository: RPi-Distro/pi-gen

# Release version of pi-gen to use. This can both be a branch or tag name known in
# the pi-gen repository.
pi-gen-version: arm64

# Setting to `1` will disable password authentication for SSH and enable public
# key authentication. Note that if SSH is not enabled this will take effect when
# SSH becomes enabled.
pubkey-only-ssh: 0

# The release version to build images against. Valid values are jessie, stretch,
# buster, bullseye, bookworm, and testing.
release: bookworm

# List of stage name to execute in given order. Relative and absolute paths to
# custom stage directories are allowed here. Note that by default pi-gen exports
# images in stage2 (lite), stage4 and stage5. You probably want to hook in custom
# stages before one of the exported stages. Otherwise, the action will make sure
# any custom stage will include an image export directive.
stage-list: stage0 stage1 stage2 ./pi-gen-sunscan

# System timezone.
timezone: Europe/Paris

# Name of the initial user account.
username: admin

# Print all output from pi-gen.
verbose-output: true
- uses: actions/upload-artifact@v4
with:
name: ${{ env.IMGFILENAME }}
path: ${{ steps.build.outputs.image-path }}
# - name: Release
# uses: softprops/action-gh-release@v2
# if: startsWith(github.ref, 'refs/tags/')
# with:
# files: ${{ steps.build.outputs.image-path }}
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,12 @@ dmypy.json
# project adds
*.log
/app/.idea

/app/jsolex
/app/storage/raw/*
/app/storage/scans/*
/app/storage/snapshots/*
/app/storage/stacking/*
/app/storage/animations/*
/app/storage/tmp/*
/app/storage/tmp/test/*
app/main_dev.py
Expand Down
2 changes: 1 addition & 1 deletion app/Inti_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ def detect_edge (myimg,zexcl, crop, disp_log):


# releve seuil moyenne pour eviter clamp trop fort
img_mean=3*np.mean(myimg[1:-1,milieu-rayon-50:milieu+rayon+50]) #facteur 1.3 pour eviter des artefacts de bords
img_mean=1.3*np.mean(myimg[1:-1,milieu-rayon+50:milieu+rayon-50]) #facteur 1.3 pour eviter des artefacts de bords
img_c=np.copy(myimg)
img_c[img_c>img_mean]=img_mean

Expand Down
153 changes: 153 additions & 0 deletions app/animate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import os
import cv2

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from pathlib import Path

from typing import List, Optional
from PIL import Image, ImageDraw, ImageFont, ImageChops
from datetime import datetime
from storage import get_scan_tag

class PostProcessRequest(BaseModel):
paths: List[str]
watermark: bool = False
observer: str = ''
description: str = ''
frame_duration: int = 200 # Default frame duration in ms
display_datetime: bool = False # Whether to display datetime on each frame
resize_gif: bool = True # Whether to resize GIF to 50% of original size
bidirectional: bool = False # Whether to play animation in both directions
add_average_frame: bool = False # Whether to calculate and add average frames between frames
patch_size: int = 32
step_size: int = 10
intensity_threshold: int = 0

def extract_datetime_from_path(image_path: str) -> str:
"""
Extract the datetime (YYYY_MM_DD-HH_MM_SS) from the image path.
"""
path = Path(image_path)
# Assuming the datetime is always in the folder name before the image name
folder_name = path.parent.name
# Assuming the format is YYYY_MM_DD-HH_MM_SS, we will split and reformat it
date_part, time_part = folder_name.split('-')
sunscan, year, month, day = date_part.split('_')
hour, minute, second = time_part.split('_')
# Return the formatted datetime: YYYY/MM/DD HH:MM:SS
return f"{year}/{month}/{day} {hour}:{minute}:{second} UT"


def add_datetime_to_frame(image: Image.Image, datetime_str: str) -> Image.Image:
"""
Add the extracted datetime to the image with a specified font size.
"""
draw = ImageDraw.Draw(image)
font = ImageFont.truetype("/var/www/sunscan-backend/app/fonts/Roboto-Regular.ttf", 30) # Use a specific font if available
text_position = get_text_position(image)
draw.text(text_position, datetime_str, fill="white", font=font)
return image

def get_text_position(image, padding_from_bottom=50, padding_from_left=20):
# Get the image dimensions to position the text in the bottom-left corner
width, height = image.size
# Position the text in the bottom-left corner with some padding
return (padding_from_left, height - padding_from_bottom) # Padding of Npx from the left and bottom

def add_watermark(image: Image.Image, observer: str) -> Image.Image:
"""
Add the extracted datetime to the image with a specified font size.
"""
draw = ImageDraw.Draw(image)

font = ImageFont.truetype("/var/www/sunscan-backend/app/fonts/Baumans-Regular.ttf", 40) # Use a specific font if available
draw.text(get_text_position(image, 115), 'SUNSCAN', fill="white", font=font)
font = ImageFont.truetype("/var/www/sunscan-backend/app/fonts/Roboto-Regular.ttf", 20) # Use a specific font if available
draw.text(get_text_position(image, 73), observer, fill="white", font=font)
return image

def resize_frame(image: Image.Image) -> Image.Image:
"""
Resize the image to 50% of its original size.
"""
width, height = image.size
new_size = (width // 2, height // 2)
return image.resize(new_size, Image.Resampling.LANCZOS)

def calculate_average_frame(frame1: Image.Image, frame2: Image.Image) -> Image.Image:
"""
Calculate the average frame between two frames.
"""
return ImageChops.blend(frame1, frame2, alpha=0.5)

def create_gif(image_paths: List[Path], watermark: bool, observer: str,output_path: Path, frame_duration: int, display_datetime: bool, resize_gif: bool, bidirectional: bool, add_average_frame: bool):
"""
Create a GIF animation from a list of image paths.
"""
frames = []
for image_path in image_paths:
image = cv2.imread(str(image_path), cv2.IMREAD_UNCHANGED)
image = image // 256
frame = Image.fromarray(image).convert("RGB")
# Extract the datetime from the path and format it
datetime_str = extract_datetime_from_path(str(image_path))
if display_datetime:
tag = get_scan_tag(os.path.dirname(image_path))
txt = datetime_str if not tag else datetime_str+" - "+tag
frame = add_datetime_to_frame(frame, txt)
if watermark:
frame = add_watermark(frame, observer)
if resize_gif:
frame = resize_frame(frame)
frames.append(frame)

if add_average_frame:
extended_frames = []
for i in range(len(frames) - 1):
extended_frames.append(frames[i])
average_frame = calculate_average_frame(frames[i], frames[i + 1])
extended_frames.append(average_frame)
extended_frames.append(frames[-1])
frames = extended_frames

if bidirectional:
frames += frames[::-1] # Append reversed frames for bidirectional playback


# Check if the output path contains "clahe" and create a preview gif
if "helium_cont" in str(output_path).lower():
# Resize the frames to 250px width and height
preview_frames = [frame.resize((250, 250), Image.Resampling.LANCZOS) for frame in frames]
preview_output_path = os.path.join(os.path.dirname(output_path), "animated_preview.gif")
preview_frames[0].save(
preview_output_path,
save_all=True,
append_images=preview_frames[1:],
duration=frame_duration, # Frame duration in ms
loop=0, # Infinite loop
dither=True
)
print(f"Preview GIF saved at {preview_output_path}")
elif "clahe" in str(output_path).lower():
# Resize the frames to 250px width and height
preview_frames = [frame.resize((250, 250), Image.Resampling.LANCZOS) for frame in frames]
preview_output_path = os.path.join(os.path.dirname(output_path), "animated_preview.gif")
preview_frames[0].save(
preview_output_path,
save_all=True,
append_images=preview_frames[1:],
duration=frame_duration, # Frame duration in ms
loop=0, # Infinite loop
dither=True
)
print(f"Preview GIF saved at {preview_output_path}")

frames[0].save(
output_path,
save_all=True,
append_images=frames[1:],
duration=frame_duration, # Frame duration in ms
loop=0, # Infinite loop,
dither=True
)
Loading