<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>astrofotografia &amp;mdash; Marcin Modest Trzaska</title>
    <link>https://blog.argilus.online/czach/tag:astrofotografia</link>
    <description>Piszę, co mi przyjdzie do głowy. Na tematy różne.</description>
    <pubDate>Tue, 06 Oct 2026 18:54:12 +0200</pubDate>
    <item>
      <title>Testy Seestar Live View</title>
      <link>https://blog.argilus.online/czach/testy-seestar-live-view</link>
      <description>&lt;![CDATA[W ramach testów teleskopu na żywo (duże podziękowania dla Mariusza za inspirację) na warsztat wziąłem dwa obiekty:&#xA;&#xA;Pętla Łabędzia — dalsze zbieranie materiału w trybie mozaiki&#xA;Pętla Łabędzia&#xA;&#xA;Galaktyka Andromedy — ponieważ wygląda to spektakularnie ;-)&#xA;M31&#xA;&#xA;#Seestar #seestarpy #python #selfhosting #astrofotografia&#xA;&#xA;-- &#xD;&#xA;Marcin &#34;czach&#34; Trzaska&#xD;&#xA;reply-to: @czach@mastodon.argilus.online]]&gt;</description>
      <content:encoded><![CDATA[<p>W ramach testów teleskopu na żywo (duże podziękowania dla <a href="https://teleskop.astronocnik.pl" rel="nofollow">Mariusza</a> za inspirację) na warsztat wziąłem dwa obiekty:</p>
<ol><li><p>Pętla Łabędzia — dalsze zbieranie materiału w trybie mozaiki
<img src="https://blgpht.argilus.online/api/files/178/original/NGC_6960_625x10_20_30s-2.jpg" alt="Pętla Łabędzia"></p></li>

<li><p>Galaktyka Andromedy — ponieważ wygląda to spektakularnie ;–)
<img src="https://blgpht.argilus.online/api/files/177/original/M_31_1012x30s.jpg" alt="M31"></p></li></ol>

<p><a href="/czach/tag:Seestar" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">Seestar</span></a> <a href="/czach/tag:seestarpy" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">seestarpy</span></a> <a href="/czach/tag:python" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">python</span></a> <a href="/czach/tag:selfhosting" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">selfhosting</span></a> <a href="/czach/tag:astrofotografia" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">astrofotografia</span></a></p>

<p>—
Marcin “czach” Trzaska
reply-to: <a href="https://blog.argilus.online/@/czach@mastodon.argilus.online" class="u-url mention" rel="nofollow">@<span>czach@mastodon.argilus.online</span></a></p>
]]></content:encoded>
      <guid>https://blog.argilus.online/czach/testy-seestar-live-view</guid>
      <pubDate>Fri, 02 Oct 2026 16:27:29 +0000</pubDate>
    </item>
    <item>
      <title>Okolice pełni Księżyca</title>
      <link>https://blog.argilus.online/czach/okolice-pelni-ksiezyca</link>
      <description>&lt;![CDATA[Dziś będzie krótko na temat jak paskudnym jest Księżyc, gdy chcesz zrobić astrofoto.&#xA;&#xA;Księżyc dzień po pełni&#xA;&#xA;Mam wrażenie, że gdy widzę w prognozach ładną, bezchmurną noc to pewnym jest, że będzie pełnia. &#xA;&#xA;Wstęp &#xA;Niepisana zasada astrofotografii brzmi: podczas pełni (i jej bliskiej okolicy) nie zbieraj materiału tylko obrabiaj albo ucz się. No, ale jak tu odpuścić, gdy teleskop aż się wyrywa na spacer? ;-)&#xA;&#xA;No to od początku. Na pierwszy ogień poszła &#xA;&#xA;Mgławica Rożek&#xA;Lub Mgławica Półksiężyc. Ciekawie się prezentuje w Seestarze S50, ale w S30 Pro ujawnia się dodatkowy smaczek, czyli to co wokół.&#xA;Szkoda jednak, że całość jest po prostu jasna od blasku Księżyca. No ale chciałem spróbować.&#xA;Ze 120 klatek po 30 sekund 4 zostały odrzucone.&#xA;&#xA;Pętla Łabędzia&#xA;Drugie podejście z S30 Pro.&#xA;Podobnie jak za pierwszym razem tryb mozaiki (x1.3), ale tym razem zbierałem surowe klatki i składałem mozaikę w Sirilu.&#xA;Tutaj obiekt był znacznie bliżej Księżyca, więcej materiału poszło do śmieci. Ze 126 klatek do obróbki nadało się 63. Zaledwie 50%.&#xA;&#xA;edit popołudniowy&#xA;Potraktowałem materiał aplikacją Seestara na tablecie i plik wynikowy jest złożony ze 126 klatek. Trochę się gwiazdy rozjechały przez kilka klatek złych, ale to się wycięło w postprodukcji. &#xA;Oto efekt:&#xA;&#xA;Trąba Słonia&#xA;Niby dalej od Księżyca, na północnej stronie a efekty równie kiepskie, jeśli nie bardziej. 641 klatki po 30 sekund. Obraz złożony z 615.&#xA;&#xA;Podsumowanie&#xA;Można się bawić tylko trzeba się liczyć, że materiał będzie po prostu kiepskiej jakości.&#xA;&#xA;#astrofotografia #Księżyc #Seestar #SeestarS30Pro&#xA;&#xA;-- &#xD;&#xA;Marcin &#34;czach&#34; Trzaska&#xD;&#xA;reply-to: @czach@mastodon.argilus.online]]&gt;</description>
      <content:encoded><![CDATA[<p>Dziś będzie krótko na temat <em>jak paskudnym jest Księżyc, gdy chcesz zrobić astrofoto</em>.</p>

<p><img src="https://blgpht.argilus.online/api/files/166/original/2026-09-28-053318-Lunar.jpg" alt="Księżyc dzień po pełni"></p>

<p>Mam wrażenie, że gdy widzę w prognozach ładną, bezchmurną noc to pewnym jest, że będzie pełnia.</p>

<h2 id="wstęp">Wstęp</h2>

<p>Niepisana zasada astrofotografii brzmi: <em>podczas pełni (i jej bliskiej okolicy) nie zbieraj materiału tylko obrabiaj albo ucz się</em>. No, ale jak tu odpuścić, gdy teleskop aż się wyrywa na spacer? ;–)</p>

<p>No to od początku. Na pierwszy ogień poszła</p>

<h2 id="mgławica-rożek">Mgławica Rożek</h2>

<p>Lub <a href="https://pl.wikipedia.org/wiki/NGC_6888" rel="nofollow"><em>Mgławica Półksiężyc</em></a>. Ciekawie się prezentuje w Seestarze S50, ale w S30 Pro ujawnia się dodatkowy smaczek, czyli to co wokół.
Szkoda jednak, że całość jest po prostu <em>jasna</em> od blasku Księżyca. No ale chciałem spróbować.
Ze 120 klatek po 30 sekund 4 zostały odrzucone.
<img src="https://blgpht.argilus.online/api/files/168/original/NGC_6888_114x30sec.jpg" alt=""></p>

<h2 id="pętla-łabędzia">Pętla Łabędzia</h2>

<p>Drugie podejście z S30 Pro.
Podobnie jak za pierwszym razem tryb mozaiki (x1.3), ale tym razem zbierałem surowe klatki i składałem mozaikę w <em>Sirilu</em>.
Tutaj obiekt był znacznie bliżej Księżyca, więcej materiału poszło do śmieci. Ze 126 klatek do obróbki nadało się 63. Zaledwie 50%.
<img src="https://blgpht.argilus.online/api/files/169/original/NGC_6960_063x30sec_og.jpg" alt=""></p>

<h3 id="edit-popołudniowy">edit popołudniowy</h3>

<p>Potraktowałem materiał aplikacją <em>Seestara</em> na tablecie i plik wynikowy jest złożony ze 126 klatek. Trochę się gwiazdy rozjechały przez kilka klatek złych, ale to się wycięło w postprodukcji.
Oto efekt:
<img src="https://blgpht.argilus.online/api/files/170/original/NGC_6960_126x30s.jpg" alt=""></p>

<h2 id="trąba-słonia-https-pl-wikipedia-org-wiki-ngc-6888"><a href="https://pl.wikipedia.org/wiki/NGC_6888" rel="nofollow">Trąba Słonia</a></h2>

<p>Niby dalej od Księżyca, na północnej stronie a efekty równie kiepskie, jeśli nie bardziej. 641 klatki po 30 sekund. Obraz złożony z 615.
<img src="https://blgpht.argilus.online/api/files/167/original/IC_1396_615x30s.jpg" alt=""></p>

<h2 id="podsumowanie">Podsumowanie</h2>

<p>Można się bawić tylko trzeba się liczyć, że materiał będzie po prostu kiepskiej jakości.</p>

<p><a href="/czach/tag:astrofotografia" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">astrofotografia</span></a> <a href="/czach/tag:Ksi%C4%99%C5%BCyc" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">Księżyc</span></a> <a href="/czach/tag:Seestar" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">Seestar</span></a> <a href="/czach/tag:SeestarS30Pro" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">SeestarS30Pro</span></a></p>

<p>—
Marcin “czach” Trzaska
reply-to: <a href="https://blog.argilus.online/@/czach@mastodon.argilus.online" class="u-url mention" rel="nofollow">@<span>czach@mastodon.argilus.online</span></a></p>
]]></content:encoded>
      <guid>https://blog.argilus.online/czach/okolice-pelni-ksiezyca</guid>
      <pubDate>Mon, 28 Sep 2026 17:02:03 +0000</pubDate>
    </item>
    <item>
      <title>Ameryka i Pelikan</title>
      <link>https://blog.argilus.online/czach/ameryka-i-pelikan</link>
      <description>&lt;![CDATA[Da się tak ustawić kadr w Seestarze S30 Pro, aby objąć te dwie mgławice.&#xA;&#xA;NGC 7000 232x30s RC&#xA;div style=&#34;text-align: center;&#34;232x30 sekund = 1h56mbrStackowane skryptem Naztronomy w Sirilu/div&#xA;---&#xA;NGC 7000 232x30s RC 2&#xA;div style=&#34;text-align: center;&#34;232x30 sekund = 1h56mbrStackowane skryptem Naztronomy w Sirilu. Tutaj mała uwaga. Miałem dwie sesje — jedna bez Pelikana, druga z Pelikanem. Połączyłem je a w Lightroomie wyciągnąłem z niego trochę więcej/div&#xA;&#xA;---&#xA;&#xA;NGC 7000 198x30s StackingWizzard + AstroWizzard&#xA;div style=&#34;text-align: center;&#34;198x30 sekund = 1h39mbrStackowanie: StackingWizard, obróbka: AstroWizard/div&#xA;&#xA;--- &#xA;#astrofotografia #MgławicaAmerykaPółnocna #MgławicaPelikan #NGC7000 #IC5070 #Seestar #SeestarS30Pro&#xA;&#xA;-- &#xD;&#xA;Marcin &#34;czach&#34; Trzaska&#xD;&#xA;reply-to: @czach@mastodon.argilus.online]]&gt;</description>
      <content:encoded><![CDATA[<p>Da się tak ustawić kadr w Seestarze S30 Pro, aby objąć te dwie mgławice.</p>

<p><a href="https://blgpht.argilus.online/api/files/164/original/NGC_7000_232x30s_RC.jpg" rel="nofollow"><img src="https://blgpht.argilus.online/api/files/164/variants/ffmpeg-1280x1280-in/NGC_7000_232x30s_RC.jpg" alt="NGC 7000 232x30s RC"></a>
<div style="text-align: center;"><em>232x30 sekund = 1h56m</em><br>Stackowane skryptem <em>Naztronomy</em> w Sirilu</div></p>

<hr>

<p><a href="https://blgpht.argilus.online/api/files/163/original/NGC_7000_232x30s_RC-2.jpg" rel="nofollow"><img src="https://blgpht.argilus.online/api/files/163/variants/ffmpeg-1280x1280-in/NGC_7000_232x30s_RC-2.jpg" alt="NGC 7000 232x30s RC 2"></a>
<div style="text-align: center;"><em>232x30 sekund = 1h56m</em><br>Stackowane skryptem <em>Naztronomy w Sirilu</em>. Tutaj mała uwaga. Miałem dwie sesje — jedna bez <em>Pelikana</em>, druga z <em>Pelikanem</em>. Połączyłem je a w <em>Lightroomie</em> wyciągnąłem z niego trochę więcej</div></p>

<hr>

<p><a href="https://blgpht.argilus.online/api/files/165/original/ngc7000.jpeg" rel="nofollow"><img src="https://blgpht.argilus.online/api/files/165/variants/ffmpeg-1280x1280-in/ngc7000.jpeg" alt="NGC 7000 198x30s StackingWizzard + AstroWizzard"></a>
<div style="text-align: center;"><em>198x30 sekund = 1h39m</em><br>Stackowanie: StackingWizard, obróbka: AstroWizard</div></p>

<hr>

<p><a href="/czach/tag:astrofotografia" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">astrofotografia</span></a> <a href="/czach/tag:Mg%C5%82awicaAmerykaP%C3%B3%C5%82nocna" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">MgławicaAmerykaPółnocna</span></a> <a href="/czach/tag:Mg%C5%82awicaPelikan" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">MgławicaPelikan</span></a> <a href="/czach/tag:NGC7000" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">NGC7000</span></a> <a href="/czach/tag:IC5070" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">IC5070</span></a> <a href="/czach/tag:Seestar" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">Seestar</span></a> <a href="/czach/tag:SeestarS30Pro" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">SeestarS30Pro</span></a></p>

<p>—
Marcin “czach” Trzaska
reply-to: <a href="https://blog.argilus.online/@/czach@mastodon.argilus.online" class="u-url mention" rel="nofollow">@<span>czach@mastodon.argilus.online</span></a></p>
]]></content:encoded>
      <guid>https://blog.argilus.online/czach/ameryka-i-pelikan</guid>
      <pubDate>Sun, 27 Sep 2026 09:54:56 +0000</pubDate>
    </item>
    <item>
      <title>Dark Shark Nebula</title>
      <link>https://blog.argilus.online/czach/dark-shark-nebula</link>
      <description>&lt;![CDATA[Od pewnego czasu próbuję ogarnąć Rekina (VdB-150).&#xA;&#xA;div class=&#34;blog-reference&#34;&#xA;  span class=&#34;reference-icon&#34;☝️/span&#xA;  div class=&#34;reference-content&#34;&#xA;    span class=&#34;reference-label&#34;Powiązane wpisy/span&#xA;    p&#xA;a href=&#34;https://blog.argilus.online/czach/rekin&#34;Rekin/aRekin po raz pierwszy/p&#xA;p&#xA;a href=&#34;https://blog.argilus.online/czach/rekin-po-raz-drugi&#34;Rekin po raz drugi/a, gdzie pojawił się pomysł na mozaikowy skrypt./p&#xA;  /div&#xA;/div&#xA;&#xA;No nie było to łatwe z Seestarem S50 ze względu na FOV. W trybie mozaiki część była prześwietlona, część niedoświetlona, widać było miejsca łączenia itp.&#xA;&#xA;Z nowym Seestarem S30 Pro wszystko jest prostsze — duże FOV i sprawa załatwiona.&#xA;Ostatniej nocy (22/23 września) pojawiło się okienko pogodowe i nazbierałem ponad 1000 klatek po 30 sekund Rekina.&#xA;Tradycyjnie — obróbka a obraz wynikowy to złożenie 949, klatek po 30 sekund, czyli łącznie 7 godzin 54 minuty i 30 sekund.&#xA;&#xA;Dark Shark Nebula / VdB-150 / Mgławica Rekin&#xA;&#xA;I różne wersje wykończenia (+textures, +noise reduction)&#xA;&#xA;Dark Shark Nebula / VdB-150 / Mgławica Rekin&#xA;Dark Shark Nebula / VdB-150 / Mgławica Rekin&#xA;&#xA;Crop Dark Shark Nebula / VdB-150 / Mgławica Rekin&#xA;&#xA;#astrofotografia #MgławicaRekin #astrophotography #DarkSharkNebula #Seestar #S30Pro&#xA;&#xA;-- &#xD;&#xA;Marcin &#34;czach&#34; Trzaska&#xD;&#xA;reply-to: @czach@mastodon.argilus.online]]&gt;</description>
      <content:encoded><![CDATA[<p>Od pewnego czasu próbuję ogarnąć <em>Rekina</em> (VdB-150).</p>

<div class="blog-reference">
  <span class="reference-icon">☝️</span>
  <div class="reference-content">
    <span class="reference-label">Powiązane wpisy</span>
    <p>
<a href="https://blog.argilus.online/czach/rekin" rel="nofollow">Rekin</a>Rekin po raz pierwszy</p>
<p>
<a href="https://blog.argilus.online/czach/rekin-po-raz-drugi" rel="nofollow">Rekin po raz drugi</a>, gdzie pojawił się pomysł na mozaikowy skrypt.</p>
  </div>
</div>

<p>No nie było to łatwe z <em>Seestarem S50</em> ze względu na <a href="https://pl.wikipedia.org/wiki/Pole_widzenia" rel="nofollow">FOV</a>. W trybie mozaiki część była prześwietlona, część niedoświetlona, widać było miejsca łączenia itp.</p>

<p>Z nowym Seestarem S30 Pro wszystko jest prostsze — duże FOV i sprawa załatwiona.
Ostatniej nocy (22/23 września) pojawiło się okienko pogodowe i nazbierałem ponad 1000 klatek po 30 sekund <em>Rekina</em>.
Tradycyjnie — obróbka a obraz wynikowy to złożenie 949, klatek po 30 sekund, czyli łącznie 7 godzin 54 minuty i 30 sekund.</p>

<p><img src="https://blgpht.argilus.online/api/files/158/original/VdB_150_949x30sek-v3.jpg" alt="*Dark Shark Nebula / VdB-150 / Mgławica Rekin"></p>

<p>I różne wersje wykończenia (+textures, +noise reduction)</p>

<p><img src="https://blgpht.argilus.online/api/files/160/original/VdB_150_949x30sek-v3-2.jpg" alt="*Dark Shark Nebula / VdB-150 / Mgławica Rekin">
<img src="https://blgpht.argilus.online/api/files/159/original/VdB_150_949x30sek-v3-3.jpg" alt="*Dark Shark Nebula / VdB-150 / Mgławica Rekin"></p>

<p><img src="https://blgpht.argilus.online/api/files/161/original/VdB_150_949x30sek-v3-4.jpg" alt="**Crop** *Dark Shark Nebula / VdB-150 / Mgławica Rekin"></p>

<p><a href="/czach/tag:astrofotografia" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">astrofotografia</span></a> <a href="/czach/tag:Mg%C5%82awicaRekin" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">MgławicaRekin</span></a> <a href="/czach/tag:astrophotography" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">astrophotography</span></a> <a href="/czach/tag:DarkSharkNebula" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">DarkSharkNebula</span></a> <a href="/czach/tag:Seestar" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">Seestar</span></a> <a href="/czach/tag:S30Pro" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">S30Pro</span></a></p>

<p>—
Marcin “czach” Trzaska
reply-to: <a href="https://blog.argilus.online/@/czach@mastodon.argilus.online" class="u-url mention" rel="nofollow">@<span>czach@mastodon.argilus.online</span></a></p>
]]></content:encoded>
      <guid>https://blog.argilus.online/czach/dark-shark-nebula</guid>
      <pubDate>Wed, 23 Sep 2026 09:30:59 +0000</pubDate>
    </item>
    <item>
      <title>Trochę astrofotografii</title>
      <link>https://blog.argilus.online/czach/troche-astrofotografii</link>
      <description>&lt;![CDATA[Ależ mi się astronoc trafiła. Udało mi się dodać 4 Messiery do kolekcji. Na liczniku już mam 88/110, czyli już niewiele brakuje.&#xA;&#xA;Na listę trafiły obiekty mniej i bardziej spektakularne.&#xA;&#xA;Te pierwsze to M21, M23 i M25. Przy dwóch ostatnich nawet nie trudziłem się ze zbieraniem jakieś większej ilości materiału — za nisko nad horyzontem a i nic szczególnego. ;-)&#xA;&#xA;div class=&#34;galeria&#34;&#xA;img src=&#34;https://blgpht.argilus.online/api/files/12/original/M23017x30sec.jpg&#34; alt=&#34;M23&#34;&#xA;img src=&#34;https://blgpht.argilus.online/api/files/49/original/M25051x20sec.jpg&#34; alt=&#34;M25&#34;&#xA;/div&#xA;&#xA;Nieco więcej materiału zebrałem przy M20 (no i przy okazji M21). Nawet ładnie to wygląda.&#xA;&#xA;Mgławica Trólistna Koniczyna&#xA;&#xA;Tuż przed północą przestawiłem się na NGC7331, aby dosmażyć nieco świeżą supernową.&#xA;div class=&#34;blog-reference&#34;&#xA;  span class=&#34;reference-icon&#34;☝️/span&#xA;  div class=&#34;reference-content&#34;&#xA;    span class=&#34;reference-label&#34;Powiązane wpisy/span&#xA;    p&#xA;    &lt;a href=&#34;&#xA;https://blog.argilus.online/czach/supernowa-sn-2026aaiv&#34;  https://blog.argilus.online/czach/supernowa-sn-2026aaiv/aSupernowa  SN-2026aaiv&#xA;   /p&#xA;  /div&#xA;/div&#xA;&#xA;div class=&#34;galeria&#34;&#xA;img src=&#34;https://blgpht.argilus.online/api/files/58/original/NGC7331992x20sgXBGSPCCGNrSR.jpeg&#34; alt=&#34;NGC7331&#34;&#xA;&#xA;img src=&#34;https://blgpht.argilus.online/api/files/94/original/NGC7331509x30sopis.jpeg&#34; alt=&#34;NGC7331 + opis&#34;&#xA;/div&#xA;&#xA;No i jeszcze wpadło trochę klatek z M27.&#xA;&#xA;M27&#xA;&#xA;#astrofotografia #Seestar #S50 #Messier&#xA;&#xA;-- &#xD;&#xA;Marcin &#34;czach&#34; Trzaska&#xD;&#xA;reply-to: @czach@mastodon.argilus.online]]&gt;</description>
      <content:encoded><![CDATA[<p>Ależ mi się astronoc trafiła. Udało mi się dodać 4 <a href="https://pl.wikipedia.org/wiki/Katalog_Messiera" rel="nofollow"><em>Messiery</em></a> do kolekcji. Na liczniku już mam <strong>88/110</strong>, czyli już niewiele brakuje.</p>

<p>Na listę trafiły obiekty mniej i bardziej spektakularne.</p>

<p>Te pierwsze to <a href="https://pl.wikipedia.org/wiki/Messier_21" rel="nofollow">M21</a>, <a href="https://pl.wikipedia.org/wiki/Messier_23" rel="nofollow">M23</a> i <a href="https://pl.wikipedia.org/wiki/Messier_25" rel="nofollow">M25</a>. Przy dwóch ostatnich nawet nie trudziłem się ze zbieraniem jakieś większej ilości materiału — za nisko nad horyzontem a i nic szczególnego. ;–)</p>

<div class="galeria">
<img src="https://blgpht.argilus.online/api/files/12/original/M_23_017x30sec.jpg" alt="M23">
<img src="https://blgpht.argilus.online/api/files/49/original/M_25_051x20sec.jpg" alt="M25">
</div>

<p>Nieco więcej materiału zebrałem przy <a href="https://pl.wikipedia.org/wiki/Mg%C5%82awica_Tr%C3%B3jlistna_Koniczyna" rel="nofollow">M20</a> (no i przy okazji M21). Nawet ładnie to wygląda.</p>

<p><img src="https://blgpht.argilus.online/api/files/63/original/M_20_182x20s.jpg" alt="Mgławica Trólistna Koniczyna"></p>

<p>Tuż przed północą przestawiłem się na NGC7331, aby dosmażyć nieco świeżą supernową.
<div class="blog-reference">
  <span class="reference-icon">☝️</span>
  <div class="reference-content">
    <span class="reference-label">Powiązane wpisy</span>
    <p>
    <a href="https://blog.argilus.online/czach/supernowa-sn-2026aaiv" rel="nofollow"><a href="https://blog.argilus.online/czach/supernowa-sn-2026aaiv" rel="nofollow">https://blog.argilus.online/czach/supernowa-sn-2026aaiv</a></a>Supernowa  SN-2026aaiv
   </p>
  </div>
</div></p>

<div class="galeria">
<img src="https://blgpht.argilus.online/api/files/58/original/NGC_7331_992x20s_gX_BG_SPCC_GNr_SR.jpeg" alt="NGC7331">

<img src="https://blgpht.argilus.online/api/files/94/original/NGC_7331_509x30s_opis.jpeg" alt="NGC7331 + opis">
</div>

<p>No i jeszcze wpadło trochę klatek z <a href="https://pl.wikipedia.org/wiki/Mg%C5%82awica_Hantle" rel="nofollow">M27</a>.</p>

<p><img src="https://blgpht.argilus.online/api/files/144/original/M_27_156x30s.jpg" alt="M27"></p>

<p><a href="/czach/tag:astrofotografia" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">astrofotografia</span></a> <a href="/czach/tag:Seestar" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">Seestar</span></a> <a href="/czach/tag:S50" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">S50</span></a> <a href="/czach/tag:Messier" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">Messier</span></a></p>

<p>—
Marcin “czach” Trzaska
reply-to: <a href="https://blog.argilus.online/@/czach@mastodon.argilus.online" class="u-url mention" rel="nofollow">@<span>czach@mastodon.argilus.online</span></a></p>
]]></content:encoded>
      <guid>https://blog.argilus.online/czach/troche-astrofotografii</guid>
      <pubDate>Wed, 16 Sep 2026 10:13:15 +0000</pubDate>
    </item>
    <item>
      <title>Rozmyślania o mozaice</title>
      <link>https://blog.argilus.online/czach/rozmyslania-o-mozaice</link>
      <description>&lt;![CDATA[Pokusiłem się zbratać z AI, aby sprawdzać pokrycie materiału w mozaice.&#xA;div class=&#34;blog-reference&#34;&#xA;  span class=&#34;reference-icon&#34;☝️/span&#xA;  div class=&#34;reference-content&#34;&#xA;    span class=&#34;reference-label&#34;Powiązane wpisy/span&#xA;    p&#xA;a href=&#34;https://blog.argilus.online/czach/seestar-mosaic-coverage&#34;Seestar Mosaic Coverage/a, gdzie pojawił się pomysł./p&#xA;p&#xA;a href=&#34;https://blog.argilus.online/czach/rekin-po-raz-drugi&#34;Rekin po raz drugi/a, gdzie pomysł się rozwinął./p&#xA;  /div&#xA;/div&#xA;I wpadłem na pomysł, żeby to wykorzystać bardziej praktycznie i zapewnić sobie w miarę równomierne pokrycie.&#xA;&#xA;Mam jakiś stary materiał z IC 1848 — 2617 klatek i zapuściłem skrypt.&#xA;Oto efekt.&#xA;wyrównanie mozaiki&#xA;&#xA;Usunął 500 klatek, zmniejszając pokrycie środka i wyrównując tym samym nieco całość.&#xA;&#xA;Teraz przekładając to praktykę:&#xA;&#xA;zgrywam pliki&#xA;traktuję je ASTAPem (wywalam najgorsze)&#xA;zapuszczam skrypt, aby nieco wyrównać pokrycie&#xA;Siril &#xA;[...]&#xA;&#xA;Nazbieram czegoś nowego i przetestuję.&#xA;&#xA;#Seestar #astrofotografia&#xA;&#xA;-- &#xD;&#xA;Marcin &#34;czach&#34; Trzaska&#xD;&#xA;reply-to: @czach@mastodon.argilus.online]]&gt;</description>
      <content:encoded><![CDATA[<p>Pokusiłem się zbratać z AI, aby sprawdzać pokrycie materiału w mozaice.
<div class="blog-reference">
  <span class="reference-icon">☝️</span>
  <div class="reference-content">
    <span class="reference-label">Powiązane wpisy</span>
    <p>
<a href="https://blog.argilus.online/czach/seestar-mosaic-coverage" rel="nofollow">Seestar Mosaic Coverage</a>, gdzie pojawił się pomysł.</p>
<p>
<a href="https://blog.argilus.online/czach/rekin-po-raz-drugi" rel="nofollow">Rekin po raz drugi</a>, gdzie pomysł się rozwinął.</p>
  </div>
</div>
I wpadłem na pomysł, żeby to wykorzystać bardziej praktycznie i zapewnić sobie w miarę równomierne pokrycie.</p>

<p>Mam jakiś stary materiał z <em>IC 1848</em> — 2617 klatek i zapuściłem skrypt.
Oto efekt.
<img src="https://blgpht.argilus.online/api/files/28/original/coverage_map_IC1848.png" alt="wyrównanie mozaiki"></p>

<p>Usunął 500 klatek, zmniejszając pokrycie środka i wyrównując tym samym nieco całość.</p>

<p>Teraz przekładając to praktykę:</p>
<ol><li>zgrywam pliki</li>
<li>traktuję je ASTAPem (wywalam najgorsze)</li>
<li>zapuszczam skrypt, aby nieco wyrównać pokrycie</li>
<li>Siril
[...]</li></ol>

<p>Nazbieram czegoś nowego i przetestuję.</p>

<p><a href="/czach/tag:Seestar" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">Seestar</span></a> <a href="/czach/tag:astrofotografia" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">astrofotografia</span></a></p>

<p>—
Marcin “czach” Trzaska
reply-to: <a href="https://blog.argilus.online/@/czach@mastodon.argilus.online" class="u-url mention" rel="nofollow">@<span>czach@mastodon.argilus.online</span></a></p>
]]></content:encoded>
      <guid>https://blog.argilus.online/czach/rozmyslania-o-mozaice</guid>
      <pubDate>Mon, 07 Sep 2026 15:57:40 +0000</pubDate>
    </item>
    <item>
      <title>Rekin po raz drugi</title>
      <link>https://blog.argilus.online/czach/rekin-po-raz-drugi</link>
      <description>&lt;![CDATA[Próbuję po raz drugi ogarnąć Dark Shark Nebula, tym razem na szerzej, to znaczy w trybie mozaiki x2 (czyli pole widzenia Seestara S50 x 4).&#xA;&#xA;Pokrycie fragmentu nieba&#xA;&#xA;Ciekawi mnie, jak to wyjdzie. Na razie za malo materiału, żeby cokolwiek zobaczyć.&#xA;&#xA;Tak przy okazji — na dysku pojawiła się nowa wersja skryptu a tak wygląda wynik jego pracy:&#xA;Pokrycie fragmentu nieba&#xA;&#xA;!/usr/bin/env python3&#xA;&#34;&#34;&#34;&#xA;seestarmosaiccoverage.py&#xA;&#xA;Wczytuje pliki FIT (Seestar, tryb mozaiki) z podanego folderu i rysuje&#xA;mape pokrycia nieba: kolorem pokazuje, ile klatek pokrywa dany fragment.&#xA;&#34;&#34;&#34;&#xA;&#xA;import argparse&#xA;import glob&#xA;import os&#xA;import sys&#xA;&#xA;import numpy as np&#xA;from astropy.io import fits&#xA;from astropy.wcs import WCS&#xA;import matplotlib.pyplot as plt&#xA;from matplotlib.path import Path as MplPath&#xA;from matplotlib.ticker import MaxNLocator&#xA;&#xA;---------- odczyt naglowkow ----------&#xA;&#xA;RAKEYS = [&#34;RA&#34;, &#34;OBJCTRA&#34;, &#34;CRVAL1&#34;]&#xA;DECKEYS = [&#34;DEC&#34;, &#34;OBJCTDEC&#34;, &#34;CRVAL2&#34;]&#xA;ROTKEYS = [&#34;ROTATION&#34;, &#34;PA&#34;, &#34;ROTATANG&#34;, &#34;ORIENTAT&#34;, &#34;ROT&#34;]&#xA;&#xA;def firstpresent(header, keys):&#xA;    for k in keys:&#xA;        if k in header:&#xA;            return header[k]&#xA;    return None&#xA;&#xA;def todecimalra(val):&#xA;    if isinstance(val, (int, float)):&#xA;        return float(val)&#xA;    val = str(val).strip()&#xA;    if &#34;:&#34; in val:&#xA;        h, m, s = [float(x) for x in val.split(&#34;:&#34;)]&#xA;        return (h + m / 60 + s / 3600)  15.0&#xA;    return float(val)&#xA;&#xA;def todecimaldec(val):&#xA;    if isinstance(val, (int, float)):&#xA;        return float(val)&#xA;    val = str(val).strip()&#xA;    sign = -1.0 if val.startswith(&#34;-&#34;) else 1.0&#xA;    val = val.lstrip(&#34;+-&#34;)&#xA;    if &#34;:&#34; in val:&#xA;        d, m, s = [float(x) for x in val.split(&#34;:&#34;)]&#xA;        return sign  (d + m / 60 + s / 3600)&#xA;    return float(val)  sign&#xA;&#xA;def readframepointing(path):&#xA;    header = fits.getheader(path)&#xA;    if &#34;CTYPE1&#34; in header and &#34;CRVAL1&#34; in header:&#xA;        try:&#xA;            wcs = WCS(header)&#xA;            footprint = wcs.calcfootprint(header=header)&#xA;            rac, decc = footprint.mean(axis=0)&#xA;            return rac, decc, 0.0, footprint&#xA;        except Exception:&#xA;            pass&#xA;&#xA;    raraw = firstpresent(header, RAKEYS)&#xA;    decraw = firstpresent(header, DECKEYS)&#xA;    if raraw is None or decraw is None:&#xA;        raise ValueError(&#34;brak RA/DEC w naglowku&#34;)&#xA;&#xA;    radeg = todecimalra(raraw)&#xA;    decdeg = todecimaldec(decraw)&#xA;    rotraw = firstpresent(header, ROTKEYS)&#xA;    rotdeg = float(rotraw) if rotraw is not None else 0.0&#xA;&#xA;    return radeg, decdeg, rotdeg, None&#xA;&#xA;---------- projekcja i footprinty ----------&#xA;&#xA;def gnomonic(radeg, decdeg, ra0deg, dec0deg):&#xA;    ra, dec = np.radians(radeg), np.radians(decdeg)&#xA;    ra0, dec0 = np.radians(ra0deg), np.radians(dec0deg)&#xA;    dra = ra - ra0&#xA;    denom = np.sin(dec0)  np.sin(dec) + np.cos(dec0)  np.cos(dec)  np.cos(dra)&#xA;    x = np.cos(dec)  np.sin(dra) / denom&#xA;    y = (np.cos(dec0)  np.sin(dec) - np.sin(dec0)  np.cos(dec)  np.cos(dra)) / denom&#xA;    return np.degrees(x), np.degrees(y)&#xA;&#xA;def framecornerstangent(rac, decc, rotdeg, fovw, fovh, ra0, dec0):&#xA;    xc, yc = gnomonic(rac, decc, ra0, dec0)&#xA;    hw, hh = fovw / 2, fovh / 2&#xA;    local = np.array([(-hw, -hh), (hw, -hh), (hw, hh), (-hw, hh)])&#xA;    theta = np.radians(rotdeg)&#xA;    rot = np.array([[np.cos(theta), -np.sin(theta)],&#xA;                    [np.sin(theta), np.cos(theta)]])&#xA;    rotated = local @ rot.T&#xA;    return rotated + np.array([xc, yc])&#xA;&#xA;def wcscornerstangent(footprintradec, ra0, dec0):&#xA;    x, y = gnomonic(footprintradec[:, 0], footprintradec[:, 1], ra0, dec0)&#xA;    return np.columnstack([x, y])&#xA;&#xA;---------- glowna logika ----------&#xA;&#xA;def buildcoverage(folder, fovw, fovh, gridn):&#xA;    files = sorted(glob.glob(os.path.join(folder, &#34;.fit&#34;)) +&#xA;                   glob.glob(os.path.join(folder, &#34;.fits&#34;)))&#xA;    if not files:&#xA;        sys.exit(f&#34;Nie znaleziono plikow .fit/.fits w: {folder}&#34;)&#xA;&#xA;    raw = []&#xA;    for f in files:&#xA;        try:&#xA;            rac, decc, rot, footprint = readframepointing(f)&#xA;            raw.append((f, rac, decc, rot, footprint))&#xA;        except Exception as e:&#xA;            print(f&#34;[pomijam] {os.path.basename(f)}: {e}&#34;)&#xA;&#xA;    if not raw:&#xA;        sys.exit(&#34;Nie udalo sie odczytac zadnej klatki.&#34;)&#xA;&#xA;    ra0 = float(np.mean([r[1] for r in raw]))&#xA;    dec0 = float(np.mean([r[2] for r in raw]))&#xA;&#xA;    polygons = []&#xA;    for f, rac, decc, rot, footprint in raw:&#xA;        if footprint is not None:&#xA;            corners = wcscornerstangent(footprint, ra0, dec0)&#xA;        else:&#xA;            corners = framecornerstangent(rac, decc, rot, fovw, fovh, ra0, dec0)&#xA;        polygons.append(corners)&#xA;&#xA;    allpts = np.vstack(polygons)&#xA;    pad = 0.15 * max(fovw, fovh)&#xA;    xmin, ymin = allpts.min(axis=0) - pad&#xA;    xmax, ymax = allpts.max(axis=0) + pad&#xA;&#xA;    xs = np.linspace(xmin, xmax, gridn)&#xA;    ys = np.linspace(ymin, ymax, gridn)&#xA;    XX, YY = np.meshgrid(xs, ys)&#xA;    pts = np.columnstack([XX.ravel(), YY.ravel()])&#xA;&#xA;    count = np.zeros(pts.shape[0], dtype=int)&#xA;    for corners in polygons:&#xA;        path = MplPath(corners)&#xA;        count += path.containspoints(pts)&#xA;&#xA;    count = count.reshape(XX.shape)&#xA;    return XX, YY, count, polygons, len(raw), ra0, dec0&#xA;&#xA;def plotcoverage(XX, YY, count, polygons, nframes, ra0, dec0, outpath):&#xA;    # Ciemny motyw pasuje do astronomii i poprawia kontrast&#xA;    plt.style.use(&#39;darkbackground&#39;)&#xA;    fig, ax = plt.subplots(figsize=(10, 9))&#xA;&#xA;    # Maskowanie obszarów gdzie count == 0, żeby tło było czyste&#xA;    countmasked = np.ma.maskedequal(count, 0)&#xA;&#xA;    maxcount = max(1, int(count.max()))&#xA;    &#xA;    # Użycie palety &#39;plasma&#39; lub &#39;magma&#39; – są bardziej czytelne niż viridis na czarnym tle&#xA;    mesh = ax.pcolormesh(XX, YY, countmasked, shading=&#34;auto&#34;,&#xA;                         cmap=&#34;plasma&#34;, vmin=1, vmax=maxcount)&#xA;    &#xA;    cbar = fig.colorbar(mesh, ax=ax, boundaries=np.arange(0.5, maxcount + 1.5, 1))&#xA;    cbar.setlabel(&#34;Liczba nakładających się klatek&#34;, color=&#39;white&#39;)&#xA;    cbar.locator = MaxNLocator(integer=True)&#xA;    cbar.updateticks()&#xA;&#xA;    # Rysowanie klatek tylko wtedy, gdy jest ich rozsądna liczba, &#xA;    # żeby nie zrobić z wykresu białej plamy&#xA;    if len(polygons) &lt;= 150:&#xA;        for corners in polygons:&#xA;            closed = np.vstack([corners, corners[0]])&#xA;            ax.plot(closed[:, 0], closed[:, 1], color=&#34;cyan&#34;, linewidth=0.3, alpha=0.4)&#xA;&#xA;    ax.setxlabel(f&#34;Odsunięcie ΔRA [deg] względem RA={ra0:.3f}°&#34;, fontsize=11)&#xA;    ax.setylabel(f&#34;Odsunięcie ΔDec [deg] względem Dec={dec0:.3f}°&#34;, fontsize=11)&#xA;    ax.settitle(f&#34;Mapa pokrycia mozaiki ({nframes} klatek)&#34;, fontsize=13, pad=12)&#xA;    &#xA;    ax.invertxaxis()  # Konwencja astronomiczna: RA rośnie w lewo&#xA;    ax.setaspect(&#34;equal&#34;)&#xA;    ax.grid(True, color=&#39;gray&#39;, linestyle=&#39;--&#39;, linewidth=0.5, alpha=0.3)&#xA;&#xA;    fig.tightlayout()&#xA;    fig.savefig(outpath, dpi=200, facecolor=fig.getfacecolor(), edgecolor=&#39;none&#39;)&#xA;    print(f&#34;Zapisano ulepszoną mapę: {outpath}&#34;)&#xA;    plt.show()&#xA;&#xA;def main():&#xA;    ap = argparse.ArgumentParser(description=&#34;Mapa pokrycia mozaiki Seestar z plikow FIT.&#34;)&#xA;    ap.addargument(&#34;folder&#34;, help=&#34;Folder z plikami .fit/.fits&#34;)&#xA;    ap.addargument(&#34;--fov-w&#34;, type=float, default=0.75, help=&#34;Szerokość FOV w stopniach&#34;)&#xA;    ap.addargument(&#34;--fov-h&#34;, type=float, default=1.33, help=&#34;Wysokość FOV w stopniach&#34;)&#xA;    ap.addargument(&#34;--grid&#34;, type=int, default=500, help=&#34;Rozdzielczość siatki (domyślnie 500 dla wyższej gładkości)&#34;)&#xA;    ap.addargument(&#34;--out&#34;, default=&#34;coverageimproved.png&#34;, help=&#34;Plik wyjściowy PNG&#34;)&#xA;    args = ap.parseargs()&#xA;&#xA;    XX, YY, count, polygons, n, ra0, dec0 = buildcoverage(&#xA;        args.folder, args.fovw, args.fovh, args.grid&#xA;    )&#xA;    plot_coverage(XX, YY, count, polygons, n, ra0, dec0, args.out)&#xA;&#xA;if name == &#34;main&#34;:&#xA;    main()&#xA;&#xA;#Seestar #S50 #astrofotografia&#xA;&#xA;-- &#xD;&#xA;Marcin &#34;czach&#34; Trzaska&#xD;&#xA;reply-to: @czach@mastodon.argilus.online]]&gt;</description>
      <content:encoded><![CDATA[<p>Próbuję po raz drugi ogarnąć <em>Dark Shark Nebula</em>, tym razem na szerzej, to znaczy w trybie mozaiki x2 (czyli pole widzenia Seestara S50 x 4).</p>

<p><img src="https://blgpht.argilus.online/api/files/130/original/coverage_VdB-150.png" alt="Pokrycie fragmentu nieba"></p>

<p>Ciekawi mnie, jak to wyjdzie. Na razie za malo materiału, żeby cokolwiek zobaczyć.</p>

<p>Tak przy okazji — na dysku pojawiła się nowa wersja skryptu a tak wygląda wynik jego pracy:
<img src="https://blgpht.argilus.online/api/files/56/original/coverage_improved_VdB-150.png" alt="Pokrycie fragmentu nieba"></p>

<pre><code class="language-python">#!/usr/bin/env python3
&#34;&#34;&#34;
seestar_mosaic_coverage.py

Wczytuje pliki FIT (Seestar, tryb mozaiki) z podanego folderu i rysuje
mape pokrycia nieba: kolorem pokazuje, ile klatek pokrywa dany fragment.
&#34;&#34;&#34;

import argparse
import glob
import os
import sys

import numpy as np
from astropy.io import fits
from astropy.wcs import WCS
import matplotlib.pyplot as plt
from matplotlib.path import Path as MplPath
from matplotlib.ticker import MaxNLocator

# ---------- odczyt naglowkow ----------

RA_KEYS = [&#34;RA&#34;, &#34;OBJCTRA&#34;, &#34;CRVAL1&#34;]
DEC_KEYS = [&#34;DEC&#34;, &#34;OBJCTDEC&#34;, &#34;CRVAL2&#34;]
ROT_KEYS = [&#34;ROTATION&#34;, &#34;PA&#34;, &#34;ROTATANG&#34;, &#34;ORIENTAT&#34;, &#34;ROT&#34;]


def _first_present(header, keys):
    for k in keys:
        if k in header:
            return header[k]
    return None


def _to_decimal_ra(val):
    if isinstance(val, (int, float)):
        return float(val)
    val = str(val).strip()
    if &#34;:&#34; in val:
        h, m, s = [float(x) for x in val.split(&#34;:&#34;)]
        return (h + m / 60 + s / 3600) * 15.0
    return float(val)


def _to_decimal_dec(val):
    if isinstance(val, (int, float)):
        return float(val)
    val = str(val).strip()
    sign = -1.0 if val.startswith(&#34;-&#34;) else 1.0
    val = val.lstrip(&#34;+-&#34;)
    if &#34;:&#34; in val:
        d, m, s = [float(x) for x in val.split(&#34;:&#34;)]
        return sign * (d + m / 60 + s / 3600)
    return float(val) * sign


def read_frame_pointing(path):
    header = fits.getheader(path)
    if &#34;CTYPE1&#34; in header and &#34;CRVAL1&#34; in header:
        try:
            wcs = WCS(header)
            footprint = wcs.calc_footprint(header=header)
            ra_c, dec_c = footprint.mean(axis=0)
            return ra_c, dec_c, 0.0, footprint
        except Exception:
            pass

    ra_raw = _first_present(header, RA_KEYS)
    dec_raw = _first_present(header, DEC_KEYS)
    if ra_raw is None or dec_raw is None:
        raise ValueError(&#34;brak RA/DEC w naglowku&#34;)

    ra_deg = _to_decimal_ra(ra_raw)
    dec_deg = _to_decimal_dec(dec_raw)
    rot_raw = _first_present(header, ROT_KEYS)
    rot_deg = float(rot_raw) if rot_raw is not None else 0.0

    return ra_deg, dec_deg, rot_deg, None


# ---------- projekcja i footprinty ----------

def gnomonic(ra_deg, dec_deg, ra0_deg, dec0_deg):
    ra, dec = np.radians(ra_deg), np.radians(dec_deg)
    ra0, dec0 = np.radians(ra0_deg), np.radians(dec0_deg)
    dra = ra - ra0
    denom = np.sin(dec0) * np.sin(dec) + np.cos(dec0) * np.cos(dec) * np.cos(dra)
    x = np.cos(dec) * np.sin(dra) / denom
    y = (np.cos(dec0) * np.sin(dec) - np.sin(dec0) * np.cos(dec) * np.cos(dra)) / denom
    return np.degrees(x), np.degrees(y)


def frame_corners_tangent(ra_c, dec_c, rot_deg, fov_w, fov_h, ra0, dec0):
    xc, yc = gnomonic(ra_c, dec_c, ra0, dec0)
    hw, hh = fov_w / 2, fov_h / 2
    local = np.array([(-hw, -hh), (hw, -hh), (hw, hh), (-hw, hh)])
    theta = np.radians(rot_deg)
    rot = np.array([[np.cos(theta), -np.sin(theta)],
                    [np.sin(theta), np.cos(theta)]])
    rotated = local @ rot.T
    return rotated + np.array([xc, yc])


def wcs_corners_tangent(footprint_radec, ra0, dec0):
    x, y = gnomonic(footprint_radec[:, 0], footprint_radec[:, 1], ra0, dec0)
    return np.column_stack([x, y])


# ---------- glowna logika ----------

def build_coverage(folder, fov_w, fov_h, grid_n):
    files = sorted(glob.glob(os.path.join(folder, &#34;*.fit&#34;)) +
                   glob.glob(os.path.join(folder, &#34;*.fits&#34;)))
    if not files:
        sys.exit(f&#34;Nie znaleziono plikow .fit/.fits w: {folder}&#34;)

    raw = []
    for f in files:
        try:
            ra_c, dec_c, rot, footprint = read_frame_pointing(f)
            raw.append((f, ra_c, dec_c, rot, footprint))
        except Exception as e:
            print(f&#34;[pomijam] {os.path.basename(f)}: {e}&#34;)

    if not raw:
        sys.exit(&#34;Nie udalo sie odczytac zadnej klatki.&#34;)

    ra0 = float(np.mean([r[1] for r in raw]))
    dec0 = float(np.mean([r[2] for r in raw]))

    polygons = []
    for f, ra_c, dec_c, rot, footprint in raw:
        if footprint is not None:
            corners = wcs_corners_tangent(footprint, ra0, dec0)
        else:
            corners = frame_corners_tangent(ra_c, dec_c, rot, fov_w, fov_h, ra0, dec0)
        polygons.append(corners)

    all_pts = np.vstack(polygons)
    pad = 0.15 * max(fov_w, fov_h)
    xmin, ymin = all_pts.min(axis=0) - pad
    xmax, ymax = all_pts.max(axis=0) + pad

    xs = np.linspace(xmin, xmax, grid_n)
    ys = np.linspace(ymin, ymax, grid_n)
    XX, YY = np.meshgrid(xs, ys)
    pts = np.column_stack([XX.ravel(), YY.ravel()])

    count = np.zeros(pts.shape[0], dtype=int)
    for corners in polygons:
        path = MplPath(corners)
        count += path.contains_points(pts)

    count = count.reshape(XX.shape)
    return XX, YY, count, polygons, len(raw), ra0, dec0


def plot_coverage(XX, YY, count, polygons, n_frames, ra0, dec0, out_path):
    # Ciemny motyw pasuje do astronomii i poprawia kontrast
    plt.style.use(&#39;dark_background&#39;)
    fig, ax = plt.subplots(figsize=(10, 9))

    # Maskowanie obszarów gdzie count == 0, żeby tło było czyste
    count_masked = np.ma.masked_equal(count, 0)

    max_count = max(1, int(count.max()))
    
    # Użycie palety &#39;plasma&#39; lub &#39;magma&#39; – są bardziej czytelne niż viridis na czarnym tle
    mesh = ax.pcolormesh(XX, YY, count_masked, shading=&#34;auto&#34;,
                         cmap=&#34;plasma&#34;, vmin=1, vmax=max_count)
    
    cbar = fig.colorbar(mesh, ax=ax, boundaries=np.arange(0.5, max_count + 1.5, 1))
    cbar.set_label(&#34;Liczba nakładających się klatek&#34;, color=&#39;white&#39;)
    cbar.locator = MaxNLocator(integer=True)
    cbar.update_ticks()

    # Rysowanie klatek tylko wtedy, gdy jest ich rozsądna liczba, 
    # żeby nie zrobić z wykresu białej plamy
    if len(polygons) &lt;= 150:
        for corners in polygons:
            closed = np.vstack([corners, corners[0]])
            ax.plot(closed[:, 0], closed[:, 1], color=&#34;cyan&#34;, linewidth=0.3, alpha=0.4)

    ax.set_xlabel(f&#34;Odsunięcie ΔRA [deg] względem RA={ra0:.3f}°&#34;, fontsize=11)
    ax.set_ylabel(f&#34;Odsunięcie ΔDec [deg] względem Dec={dec0:.3f}°&#34;, fontsize=11)
    ax.set_title(f&#34;Mapa pokrycia mozaiki ({n_frames} klatek)&#34;, fontsize=13, pad=12)
    
    ax.invert_xaxis()  # Konwencja astronomiczna: RA rośnie w lewo
    ax.set_aspect(&#34;equal&#34;)
    ax.grid(True, color=&#39;gray&#39;, linestyle=&#39;--&#39;, linewidth=0.5, alpha=0.3)

    fig.tight_layout()
    fig.savefig(out_path, dpi=200, facecolor=fig.get_facecolor(), edgecolor=&#39;none&#39;)
    print(f&#34;Zapisano ulepszoną mapę: {out_path}&#34;)
    plt.show()


def main():
    ap = argparse.ArgumentParser(description=&#34;Mapa pokrycia mozaiki Seestar z plikow FIT.&#34;)
    ap.add_argument(&#34;folder&#34;, help=&#34;Folder z plikami .fit/.fits&#34;)
    ap.add_argument(&#34;--fov-w&#34;, type=float, default=0.75, help=&#34;Szerokość FOV w stopniach&#34;)
    ap.add_argument(&#34;--fov-h&#34;, type=float, default=1.33, help=&#34;Wysokość FOV w stopniach&#34;)
    ap.add_argument(&#34;--grid&#34;, type=int, default=500, help=&#34;Rozdzielczość siatki (domyślnie 500 dla wyższej gładkości)&#34;)
    ap.add_argument(&#34;--out&#34;, default=&#34;coverage_improved.png&#34;, help=&#34;Plik wyjściowy PNG&#34;)
    args = ap.parse_args()

    XX, YY, count, polygons, n, ra0, dec0 = build_coverage(
        args.folder, args.fov_w, args.fov_h, args.grid
    )
    plot_coverage(XX, YY, count, polygons, n, ra0, dec0, args.out)


if __name__ == &#34;__main__&#34;:
    main()
</code></pre>

<p><a href="/czach/tag:Seestar" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">Seestar</span></a> <a href="/czach/tag:S50" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">S50</span></a> <a href="/czach/tag:astrofotografia" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">astrofotografia</span></a></p>

<p>—
Marcin “czach” Trzaska
reply-to: <a href="https://blog.argilus.online/@/czach@mastodon.argilus.online" class="u-url mention" rel="nofollow">@<span>czach@mastodon.argilus.online</span></a></p>
]]></content:encoded>
      <guid>https://blog.argilus.online/czach/rekin-po-raz-drugi</guid>
      <pubDate>Mon, 07 Sep 2026 08:01:14 +0000</pubDate>
    </item>
    <item>
      <title>Seestar Mosaic Coverage</title>
      <link>https://blog.argilus.online/czach/seestar-mosaic-coverage</link>
      <description>&lt;![CDATA[Tak coś mnie tknęło… dawno nie robiłem żadnej mozaiki Seestarem.&#xA;Nie robiłem, bo się zniechęciłem — jakoś nie wychodziło to najlepiej…&#xA;&#xA;No i coś mnie tknęło, żeby sprawdzić pokrycie na mapie/obrazku…&#xA;&#xA;I takie coś mam od Klaudiusza. ;-)&#xA;&#xA;!/usr/bin/env python3&#xA;&#34;&#34;&#34;&#xA;seestarmosaiccoverage.py&#xA;&#xA;Wczytuje pliki FIT (Seestar, tryb mozaiki) z podanego folderu i rysuje&#xA;mape pokrycia nieba: kolorem pokazuje, ile klatek pokrywa dany fragment.&#xA;&#xA;Wymagania:&#xA;    pip install astropy numpy matplotlib&#xA;&#xA;Uzycie:&#xA;    python seestarmosaiccoverage.py /sciezka/do/folderuzfit&#xA;    python seestarmosaiccoverage.py /sciezka --fov-w 0.75 --fov-h 1.33 --grid 400&#xA;&#34;&#34;&#34;&#xA;&#xA;import argparse&#xA;import glob&#xA;import os&#xA;import sys&#xA;&#xA;import numpy as np&#xA;from astropy.io import fits&#xA;from astropy.wcs import WCS&#xA;import matplotlib.pyplot as plt&#xA;from matplotlib.path import Path as MplPath&#xA;&#xA;---------- odczyt naglowkow ----------&#xA;&#xA;RAKEYS = [&#34;RA&#34;, &#34;OBJCTRA&#34;, &#34;CRVAL1&#34;]&#xA;DECKEYS = [&#34;DEC&#34;, &#34;OBJCTDEC&#34;, &#34;CRVAL2&#34;]&#xA;ROTKEYS = [&#34;ROTATION&#34;, &#34;PA&#34;, &#34;ROTATANG&#34;, &#34;ORIENTAT&#34;, &#34;ROT&#34;]&#xA;&#xA;def firstpresent(header, keys):&#xA;    for k in keys:&#xA;        if k in header:&#xA;            return header[k]&#xA;    return None&#xA;&#xA;def todecimalra(val):&#xA;    &#34;&#34;&#34;RA moze byc liczba (stopnie) albo string HH:MM:SS.&#34;&#34;&#34;&#xA;    if isinstance(val, (int, float)):&#xA;        return float(val)&#xA;    val = str(val).strip()&#xA;    if &#34;:&#34; in val:&#xA;        h, m, s = [float(x) for x in val.split(&#34;:&#34;)]&#xA;        return (h + m / 60 + s / 3600)  15.0&#xA;    return float(val)&#xA;&#xA;def todecimaldec(val):&#xA;    if isinstance(val, (int, float)):&#xA;        return float(val)&#xA;    val = str(val).strip()&#xA;    sign = -1.0 if val.startswith(&#34;-&#34;) else 1.0&#xA;    val = val.lstrip(&#34;+-&#34;)&#xA;    if &#34;:&#34; in val:&#xA;        d, m, s = [float(x) for x in val.split(&#34;:&#34;)]&#xA;        return sign  (d + m / 60 + s / 3600)&#xA;    return float(val)  sign&#xA;&#xA;def readframepointing(path):&#xA;    &#34;&#34;&#34;Zwraca (radeg, decdeg, rotationdeg, footprintlubNone) dla jednej klatki FIT.&#34;&#34;&#34;&#xA;    header = fits.getheader(path)&#xA;&#xA;    # Sciezka 1: pelne WCS (jesli plik byl plate-solved, np. przez ASTAP)&#xA;    if &#34;CTYPE1&#34; in header and &#34;CRVAL1&#34; in header:&#xA;        try:&#xA;            wcs = WCS(header)&#xA;            footprint = wcs.calcfootprint(header=header)  # 4x2 [ra,dec] w stopniach&#xA;            rac, decc = footprint.mean(axis=0)&#xA;            return rac, decc, 0.0, footprint&#xA;        except Exception:&#xA;            pass&#xA;&#xA;    # Sciezka 2: naglowek Seestara (RA/DEC srodka klatki + ewentualna rotacja)&#xA;    raraw = firstpresent(header, RAKEYS)&#xA;    decraw = firstpresent(header, DECKEYS)&#xA;    if raraw is None or decraw is None:&#xA;        raise ValueError(&#34;brak RA/DEC w naglowku&#34;)&#xA;&#xA;    radeg = todecimalra(raraw)&#xA;    decdeg = todecimaldec(decraw)&#xA;    rotraw = firstpresent(header, ROTKEYS)&#xA;    rotdeg = float(rotraw) if rotraw is not None else 0.0&#xA;&#xA;    return radeg, decdeg, rotdeg, None&#xA;&#xA;---------- projekcja i footprinty ----------&#xA;&#xA;def gnomonic(radeg, decdeg, ra0deg, dec0deg):&#xA;    &#34;&#34;&#34;Rzutuje RA/Dec na plaszczyzne styczna wzgledem (ra0, dec0). Zwraca stopnie.&#34;&#34;&#34;&#xA;    ra, dec = np.radians(radeg), np.radians(decdeg)&#xA;    ra0, dec0 = np.radians(ra0deg), np.radians(dec0deg)&#xA;    dra = ra - ra0&#xA;    denom = np.sin(dec0)  np.sin(dec) + np.cos(dec0)  np.cos(dec)  np.cos(dra)&#xA;    x = np.cos(dec)  np.sin(dra) / denom&#xA;    y = (np.cos(dec0)  np.sin(dec) - np.sin(dec0)  np.cos(dec)  np.cos(dra)) / denom&#xA;    return np.degrees(x), np.degrees(y)&#xA;&#xA;def framecornerstangent(rac, decc, rotdeg, fovw, fovh, ra0, dec0):&#xA;    &#34;&#34;&#34;Rogi klatki (prostokat obrocony o rotdeg) w ukladzie stycznym.&#34;&#34;&#34;&#xA;    xc, yc = gnomonic(rac, decc, ra0, dec0)&#xA;    hw, hh = fovw / 2, fovh / 2&#xA;    local = np.array([(-hw, -hh), (hw, -hh), (hw, hh), (-hw, hh)])&#xA;    theta = np.radians(rotdeg)&#xA;    rot = np.array([[np.cos(theta), -np.sin(theta)],&#xA;                    [np.sin(theta), np.cos(theta)]])&#xA;    rotated = local @ rot.T&#xA;    return rotated + np.array([xc, yc])&#xA;&#xA;def wcscornerstangent(footprintradec, ra0, dec0):&#xA;    x, y = gnomonic(footprintradec[:, 0], footprintradec[:, 1], ra0, dec0)&#xA;    return np.columnstack([x, y])&#xA;&#xA;---------- glowna logika ----------&#xA;&#xA;def buildcoverage(folder, fovw, fovh, gridn):&#xA;    files = sorted(glob.glob(os.path.join(folder, &#34;.fit&#34;)) +&#xA;                    glob.glob(os.path.join(folder, &#34;.fits&#34;)))&#xA;    if not files:&#xA;        sys.exit(f&#34;Nie znaleziono plikow .fit/.fits w: {folder}&#34;)&#xA;&#xA;    raw = []&#xA;    for f in files:&#xA;        try:&#xA;            rac, decc, rot, footprint = readframepointing(f)&#xA;            raw.append((f, rac, decc, rot, footprint))&#xA;        except Exception as e:&#xA;            print(f&#34;[pomijam] {os.path.basename(f)}: {e}&#34;)&#xA;&#xA;    if not raw:&#xA;        sys.exit(&#34;Nie udalo sie odczytac zadnej klatki - sprawdz nazwy kluczy w naglowku (patrz ponizej).&#34;)&#xA;&#xA;    ra0 = float(np.mean([r[1] for r in raw]))&#xA;    dec0 = float(np.mean([r[2] for r in raw]))&#xA;&#xA;    polygons = []&#xA;    for f, rac, decc, rot, footprint in raw:&#xA;        if footprint is not None:&#xA;            corners = wcscornerstangent(footprint, ra0, dec0)&#xA;        else:&#xA;            corners = framecornerstangent(rac, decc, rot, fovw, fovh, ra0, dec0)&#xA;        polygons.append(corners)&#xA;&#xA;    allpts = np.vstack(polygons)&#xA;    pad = 0.1  max(fovw, fovh)&#xA;    xmin, ymin = allpts.min(axis=0) - pad&#xA;    xmax, ymax = allpts.max(axis=0) + pad&#xA;&#xA;    xs = np.linspace(xmin, xmax, gridn)&#xA;    ys = np.linspace(ymin, ymax, gridn)&#xA;    XX, YY = np.meshgrid(xs, ys)&#xA;    pts = np.columnstack([XX.ravel(), YY.ravel()])&#xA;&#xA;    count = np.zeros(pts.shape[0], dtype=int)&#xA;    for corners in polygons:&#xA;        path = MplPath(corners)&#xA;        count += path.containspoints(pts)&#xA;&#xA;    count = count.reshape(XX.shape)&#xA;    return XX, YY, count, polygons, len(raw), ra0, dec0&#xA;&#xA;def plotcoverage(XX, YY, count, polygons, nframes, ra0, dec0, outpath):&#xA;    fig, ax = plt.subplots(figsize=(9, 8))&#xA;&#xA;    maxcount = max(1, int(count.max()))&#xA;    mesh = ax.pcolormesh(XX, YY, count, shading=&#34;auto&#34;,&#xA;                          cmap=&#34;viridis&#34;, vmin=0, vmax=maxcount)&#xA;    cbar = fig.colorbar(mesh, ax=ax)&#xA;    cbar.setlabel(&#34;Liczba nakladajacych sie klatek&#34;)&#xA;&#xA;    for corners in polygons:&#xA;        closed = np.vstack([corners, corners[0]])&#xA;        ax.plot(closed[:, 0], closed[:, 1], color=&#34;white&#34;, linewidth=0.4, alpha=0.6)&#xA;&#xA;    ax.setxlabel(f&#34;Odsuniecie RA [deg] wzgledem {ra0:.3f}&#34;)&#xA;    ax.setylabel(f&#34;Odsuniecie Dec [deg] wzgledem {dec0:.3f}&#34;)&#xA;    ax.settitle(f&#34;Pokrycie mozaiki - {nframes} klatek&#34;)&#xA;    ax.invertxaxis()  # konwencja: RA rosnie w lewo&#xA;    ax.setaspect(&#34;equal&#34;)&#xA;&#xA;    fig.tightlayout()&#xA;    fig.savefig(outpath, dpi=150)&#xA;    print(f&#34;Zapisano: {outpath}&#34;)&#xA;    plt.show()&#xA;&#xA;def main():&#xA;    ap = argparse.ArgumentParser(description=&#34;Mapa pokrycia mozaiki Seestar z plikow FIT.&#34;)&#xA;    ap.addargument(&#34;folder&#34;, help=&#34;Folder z plikami .fit/.fits&#34;)&#xA;    ap.addargument(&#34;--fov-w&#34;, type=float, default=0.75,&#xA;                    help=&#34;Szerokosc FOV w stopniach (domyslnie 0.75 - Seestar S50)&#34;)&#xA;    ap.addargument(&#34;--fov-h&#34;, type=float, default=1.33,&#xA;                    help=&#34;Wysokosc FOV w stopniach (domyslnie 1.33 - Seestar S50)&#34;)&#xA;    ap.addargument(&#34;--grid&#34;, type=int, default=300,&#xA;                    help=&#34;Rozdzielczosc siatki liczacej nakladki (domyslnie 300)&#34;)&#xA;    ap.addargument(&#34;--out&#34;, default=&#34;coverage.png&#34;, help=&#34;Plik wyjsciowy PNG&#34;)&#xA;    args = ap.parseargs()&#xA;&#xA;    XX, YY, count, polygons, n, ra0, dec0 = buildcoverage(&#xA;        args.folder, args.fovw, args.fovh, args.grid&#xA;    )&#xA;    plotcoverage(XX, YY, count, polygons, n, ra0, dec0, args.out)&#xA;&#xA;if name == &#34;main&#34;:&#xA;    main()&#xA;&#xA;Najpierw&#xA;$ python3 -m venv astro&#xA;$ source astro/bin/activate&#xA;a później, na przykład:&#xA;$ python seestarmosaiccoverage.py SeestarS50/Messier/M\ 31manualmosaic&#xA;&#xA;div class=&#34;galeria&#34; &#xA;       img src=&#34;https://blgpht.argilus.online/api/files/128/original/coverageIC1848.jpeg&#34; alt=&#34;pokrycie mozaiki&#34;&#xA;       img src=&#34;https://blgpht.argilus.online/api/files/112/original/coverageNGC1499.jpeg&#34; alt=&#34;pokrycie mozaiki&#34;&#xA;       /div&#xA;&#xA;div class=&#34;galeria&#34; &#xA;img src=&#34;https://blgpht.argilus.online/api/files/10/original/coverageIC443.jpeg&#34; alt=&#34;pokrycie mozaiki&#34;&#xA;img src=&#34;https://blgpht.argilus.online/api/files/109/original/coverageIC5070.jpeg&#34; alt=&#34;pokrycie mozaiki&#34;&#xA;/div&#xA;&#xA;pokrycie M31&#xA;pokrycie NGC700&#xA;&#xA;No i te dwa ostatnie obrazki pokazują mi dobitnie, dlaczego mozaiki były fallusowe*.&#xA;&#xA;: Claude AI&#xA;&#xA;#seestar #mosaic #mozaika #astrophotography #astrofotografia&#xA;&#xA;-- &#xD;&#xA;Marcin &#34;czach&#34; Trzaska&#xD;&#xA;reply-to: @czach@mastodon.argilus.online]]&gt;</description>
      <content:encoded><![CDATA[<p>Tak coś mnie tknęło… dawno nie robiłem żadnej mozaiki Seestarem.
Nie robiłem, bo się zniechęciłem — jakoś nie wychodziło to najlepiej…</p>

<p>No i coś mnie tknęło, żeby sprawdzić pokrycie na mapie/obrazku…</p>

<p>I takie coś mam od <em>Klaudiusza</em>[^1]. ;–)</p>

<pre><code class="language-python">#!/usr/bin/env python3
&#34;&#34;&#34;
seestar_mosaic_coverage.py

Wczytuje pliki FIT (Seestar, tryb mozaiki) z podanego folderu i rysuje
mape pokrycia nieba: kolorem pokazuje, ile klatek pokrywa dany fragment.

Wymagania:
    pip install astropy numpy matplotlib

Uzycie:
    python seestar_mosaic_coverage.py /sciezka/do/folderu_z_fit
    python seestar_mosaic_coverage.py /sciezka --fov-w 0.75 --fov-h 1.33 --grid 400
&#34;&#34;&#34;

import argparse
import glob
import os
import sys

import numpy as np
from astropy.io import fits
from astropy.wcs import WCS
import matplotlib.pyplot as plt
from matplotlib.path import Path as MplPath

# ---------- odczyt naglowkow ----------

RA_KEYS = [&#34;RA&#34;, &#34;OBJCTRA&#34;, &#34;CRVAL1&#34;]
DEC_KEYS = [&#34;DEC&#34;, &#34;OBJCTDEC&#34;, &#34;CRVAL2&#34;]
ROT_KEYS = [&#34;ROTATION&#34;, &#34;PA&#34;, &#34;ROTATANG&#34;, &#34;ORIENTAT&#34;, &#34;ROT&#34;]


def _first_present(header, keys):
    for k in keys:
        if k in header:
            return header[k]
    return None


def _to_decimal_ra(val):
    &#34;&#34;&#34;RA moze byc liczba (stopnie) albo string HH:MM:SS.&#34;&#34;&#34;
    if isinstance(val, (int, float)):
        return float(val)
    val = str(val).strip()
    if &#34;:&#34; in val:
        h, m, s = [float(x) for x in val.split(&#34;:&#34;)]
        return (h + m / 60 + s / 3600) * 15.0
    return float(val)


def _to_decimal_dec(val):
    if isinstance(val, (int, float)):
        return float(val)
    val = str(val).strip()
    sign = -1.0 if val.startswith(&#34;-&#34;) else 1.0
    val = val.lstrip(&#34;+-&#34;)
    if &#34;:&#34; in val:
        d, m, s = [float(x) for x in val.split(&#34;:&#34;)]
        return sign * (d + m / 60 + s / 3600)
    return float(val) * sign


def read_frame_pointing(path):
    &#34;&#34;&#34;Zwraca (ra_deg, dec_deg, rotation_deg, footprint_lub_None) dla jednej klatki FIT.&#34;&#34;&#34;
    header = fits.getheader(path)

    # Sciezka 1: pelne WCS (jesli plik byl plate-solved, np. przez ASTAP)
    if &#34;CTYPE1&#34; in header and &#34;CRVAL1&#34; in header:
        try:
            wcs = WCS(header)
            footprint = wcs.calc_footprint(header=header)  # 4x2 [ra,dec] w stopniach
            ra_c, dec_c = footprint.mean(axis=0)
            return ra_c, dec_c, 0.0, footprint
        except Exception:
            pass

    # Sciezka 2: naglowek Seestara (RA/DEC srodka klatki + ewentualna rotacja)
    ra_raw = _first_present(header, RA_KEYS)
    dec_raw = _first_present(header, DEC_KEYS)
    if ra_raw is None or dec_raw is None:
        raise ValueError(&#34;brak RA/DEC w naglowku&#34;)

    ra_deg = _to_decimal_ra(ra_raw)
    dec_deg = _to_decimal_dec(dec_raw)
    rot_raw = _first_present(header, ROT_KEYS)
    rot_deg = float(rot_raw) if rot_raw is not None else 0.0

    return ra_deg, dec_deg, rot_deg, None


# ---------- projekcja i footprinty ----------

def gnomonic(ra_deg, dec_deg, ra0_deg, dec0_deg):
    &#34;&#34;&#34;Rzutuje RA/Dec na plaszczyzne styczna wzgledem (ra0, dec0). Zwraca stopnie.&#34;&#34;&#34;
    ra, dec = np.radians(ra_deg), np.radians(dec_deg)
    ra0, dec0 = np.radians(ra0_deg), np.radians(dec0_deg)
    dra = ra - ra0
    denom = np.sin(dec0) * np.sin(dec) + np.cos(dec0) * np.cos(dec) * np.cos(dra)
    x = np.cos(dec) * np.sin(dra) / denom
    y = (np.cos(dec0) * np.sin(dec) - np.sin(dec0) * np.cos(dec) * np.cos(dra)) / denom
    return np.degrees(x), np.degrees(y)


def frame_corners_tangent(ra_c, dec_c, rot_deg, fov_w, fov_h, ra0, dec0):
    &#34;&#34;&#34;Rogi klatki (prostokat obrocony o rot_deg) w ukladzie stycznym.&#34;&#34;&#34;
    xc, yc = gnomonic(ra_c, dec_c, ra0, dec0)
    hw, hh = fov_w / 2, fov_h / 2
    local = np.array([(-hw, -hh), (hw, -hh), (hw, hh), (-hw, hh)])
    theta = np.radians(rot_deg)
    rot = np.array([[np.cos(theta), -np.sin(theta)],
                    [np.sin(theta), np.cos(theta)]])
    rotated = local @ rot.T
    return rotated + np.array([xc, yc])


def wcs_corners_tangent(footprint_radec, ra0, dec0):
    x, y = gnomonic(footprint_radec[:, 0], footprint_radec[:, 1], ra0, dec0)
    return np.column_stack([x, y])


# ---------- glowna logika ----------

def build_coverage(folder, fov_w, fov_h, grid_n):
    files = sorted(glob.glob(os.path.join(folder, &#34;*.fit&#34;)) +
                    glob.glob(os.path.join(folder, &#34;*.fits&#34;)))
    if not files:
        sys.exit(f&#34;Nie znaleziono plikow .fit/.fits w: {folder}&#34;)

    raw = []
    for f in files:
        try:
            ra_c, dec_c, rot, footprint = read_frame_pointing(f)
            raw.append((f, ra_c, dec_c, rot, footprint))
        except Exception as e:
            print(f&#34;[pomijam] {os.path.basename(f)}: {e}&#34;)

    if not raw:
        sys.exit(&#34;Nie udalo sie odczytac zadnej klatki - sprawdz nazwy kluczy w naglowku (patrz ponizej).&#34;)

    ra0 = float(np.mean([r[1] for r in raw]))
    dec0 = float(np.mean([r[2] for r in raw]))

    polygons = []
    for f, ra_c, dec_c, rot, footprint in raw:
        if footprint is not None:
            corners = wcs_corners_tangent(footprint, ra0, dec0)
        else:
            corners = frame_corners_tangent(ra_c, dec_c, rot, fov_w, fov_h, ra0, dec0)
        polygons.append(corners)

    all_pts = np.vstack(polygons)
    pad = 0.1 * max(fov_w, fov_h)
    xmin, ymin = all_pts.min(axis=0) - pad
    xmax, ymax = all_pts.max(axis=0) + pad

    xs = np.linspace(xmin, xmax, grid_n)
    ys = np.linspace(ymin, ymax, grid_n)
    XX, YY = np.meshgrid(xs, ys)
    pts = np.column_stack([XX.ravel(), YY.ravel()])

    count = np.zeros(pts.shape[0], dtype=int)
    for corners in polygons:
        path = MplPath(corners)
        count += path.contains_points(pts)

    count = count.reshape(XX.shape)
    return XX, YY, count, polygons, len(raw), ra0, dec0


def plot_coverage(XX, YY, count, polygons, n_frames, ra0, dec0, out_path):
    fig, ax = plt.subplots(figsize=(9, 8))

    max_count = max(1, int(count.max()))
    mesh = ax.pcolormesh(XX, YY, count, shading=&#34;auto&#34;,
                          cmap=&#34;viridis&#34;, vmin=0, vmax=max_count)
    cbar = fig.colorbar(mesh, ax=ax)
    cbar.set_label(&#34;Liczba nakladajacych sie klatek&#34;)

    for corners in polygons:
        closed = np.vstack([corners, corners[0]])
        ax.plot(closed[:, 0], closed[:, 1], color=&#34;white&#34;, linewidth=0.4, alpha=0.6)

    ax.set_xlabel(f&#34;Odsuniecie RA [deg] wzgledem {ra0:.3f}&#34;)
    ax.set_ylabel(f&#34;Odsuniecie Dec [deg] wzgledem {dec0:.3f}&#34;)
    ax.set_title(f&#34;Pokrycie mozaiki - {n_frames} klatek&#34;)
    ax.invert_xaxis()  # konwencja: RA rosnie w lewo
    ax.set_aspect(&#34;equal&#34;)

    fig.tight_layout()
    fig.savefig(out_path, dpi=150)
    print(f&#34;Zapisano: {out_path}&#34;)
    plt.show()


def main():
    ap = argparse.ArgumentParser(description=&#34;Mapa pokrycia mozaiki Seestar z plikow FIT.&#34;)
    ap.add_argument(&#34;folder&#34;, help=&#34;Folder z plikami .fit/.fits&#34;)
    ap.add_argument(&#34;--fov-w&#34;, type=float, default=0.75,
                    help=&#34;Szerokosc FOV w stopniach (domyslnie 0.75 - Seestar S50)&#34;)
    ap.add_argument(&#34;--fov-h&#34;, type=float, default=1.33,
                    help=&#34;Wysokosc FOV w stopniach (domyslnie 1.33 - Seestar S50)&#34;)
    ap.add_argument(&#34;--grid&#34;, type=int, default=300,
                    help=&#34;Rozdzielczosc siatki liczacej nakladki (domyslnie 300)&#34;)
    ap.add_argument(&#34;--out&#34;, default=&#34;coverage.png&#34;, help=&#34;Plik wyjsciowy PNG&#34;)
    args = ap.parse_args()

    XX, YY, count, polygons, n, ra0, dec0 = build_coverage(
        args.folder, args.fov_w, args.fov_h, args.grid
    )
    plot_coverage(XX, YY, count, polygons, n, ra0, dec0, args.out)


if __name__ == &#34;__main__&#34;:
    main()
</code></pre>

<p>Najpierw</p>

<pre><code>$ python3 -m venv astro
$ source astro/bin/activate
</code></pre>

<p>a później, na przykład:</p>

<pre><code>$ python seestar_mosaic_coverage.py SeestarS50/Messier/M\ 31_manual_mosaic
</code></pre>

<div class="galeria">
       <img src="https://blgpht.argilus.online/api/files/128/original/coverage_IC1848.jpeg" alt="pokrycie mozaiki">
       <img src="https://blgpht.argilus.online/api/files/112/original/coverage_NGC1499.jpeg" alt="pokrycie mozaiki">
       </div>

<div class="galeria">
<img src="https://blgpht.argilus.online/api/files/10/original/coverage_IC443.jpeg" alt="pokrycie mozaiki">
<img src="https://blgpht.argilus.online/api/files/109/original/coverage_IC5070.jpeg" alt="pokrycie mozaiki">
</div>

<p><img src="https://blgpht.argilus.online/api/files/137/original/coverage_M31.jpeg" alt="pokrycie M31">
<img src="https://blgpht.argilus.online/api/files/138/original/coverage_NGC7000.jpeg" alt="pokrycie NGC700"></p>

<p>No i te dwa ostatnie obrazki pokazują mi dobitnie, dlaczego mozaiki były <em>fallusowe</em>.</p>

<p>[^1]: Claude AI</p>

<p><a href="/czach/tag:seestar" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">seestar</span></a> <a href="/czach/tag:mosaic" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">mosaic</span></a> <a href="/czach/tag:mozaika" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">mozaika</span></a> <a href="/czach/tag:astrophotography" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">astrophotography</span></a> <a href="/czach/tag:astrofotografia" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">astrofotografia</span></a></p>

<p>—
Marcin “czach” Trzaska
reply-to: <a href="https://blog.argilus.online/@/czach@mastodon.argilus.online" class="u-url mention" rel="nofollow">@<span>czach@mastodon.argilus.online</span></a></p>
]]></content:encoded>
      <guid>https://blog.argilus.online/czach/seestar-mosaic-coverage</guid>
      <pubDate>Fri, 04 Sep 2026 15:59:15 +0000</pubDate>
    </item>
    <item>
      <title>Fajerwerk i Czarodziej, część 3</title>
      <link>https://blog.argilus.online/czach/fajerwerk-i-czarodziej-czesc-trzecia-druga</link>
      <description>&lt;![CDATA[Tym razem prognozy pogody się sprawdziły i noc z sierpnia na wrzesień ;-) była z (w miarę) czystym niebem. Tak w sam raz, aby dokończyć Galaktykę Fajerwerk i Mgławicę Czarodzieja.&#xA;Czarodziej&#xA;O ile z Czarodziejem nie miałem problemów i tak się prezentuje:&#xA;Mgławica Czarodzieja&#xA;div style=&#34;text-align: center; font-style: italic&#34;870x30 sek = 7h15m/div&#xA;&#xA;Fajerwerk&#xA;Tak z galaktyką coś mi nie pasowało i mam 4 wersje. Trzy pierwsze to efekt stackowania skryptem Naztronomy&#xA;div class=&#34;galeria&#34;&#xA;       img src=&#34;https://blgpht.argilus.online/api/files/119/original/NGC6946918x30.jpg&#34; alt=&#34;galaktyka Fajerwerk&#34;&#xA;       img src=&#34;https://blgpht.argilus.online/api/files/131/original/NGC6946918x30-2.jpg&#34; alt=&#34;galaktyka Fajerwerk&#34;&#xA;       img src=&#34;https://blgpht.argilus.online/api/files/15/original/NGC6946918x30-3.jpg&#34; alt=&#34;galaktyka Fajerwerk&#34;&#xA;/div&#xA;div style=&#34;text-align: center; font-style: italic&#34;918x30 sek = 7h39/div&#xA;A ostatni stackowany skryptem Seestara.&#xA;Galaktyka Fajerwerk &#xA;&#xA;div style=&#34;text-align: center; font-style: italic&#34;953x30 sek = 7h56m30s/div&#xA;&#xA;nav class=&#34;series-nav&#34;&#xA;    a href=&#34;https://blog.argilus.online/czach/galaktyka-fajerwerk-noc-2&#34; class=&#34;series-nav-item prev&#34;&#xA;        span class=&#34;series-nav-direction&#34;← Poprzedni w serii/span&#xA;        span class=&#34;series-nav-title&#34;Galaktyka Fajerwerk, noc 2./span&#xA;    /a&#xA;/nav&#xA;&#xA;#astrofotografia #astrophotography #Seestar #WizardNebula #FireworksGalaxy&#xA;&#xA;-- &#xD;&#xA;Marcin &#34;czach&#34; Trzaska&#xD;&#xA;reply-to: @czach@mastodon.argilus.online]]&gt;</description>
      <content:encoded><![CDATA[<p>Tym razem prognozy pogody się sprawdziły i noc z sierpnia na wrzesień ;–) była z (w miarę) czystym niebem. Tak w sam raz, aby dokończyć <em>Galaktykę Fajerwerk</em> i <em>Mgławicę Czarodzieja</em>.</p>

<h2 id="czarodziej"><em>Czarodziej</em></h2>

<p>O ile z <em>Czarodziejem</em> nie miałem problemów i tak się prezentuje:
<img src="https://blgpht.argilus.online/api/files/23/original/NGC_7380_870x30s.jpg" alt="Mgławica Czarodzieja" title="Mgławica Czarodzieja">
<div style="text-align: center; font-style: italic">870x30 sek = 7h15m</div></p>

<h2 id="fajerwerk"><em>Fajerwerk</em></h2>

<p>Tak z galaktyką coś mi nie pasowało i mam 4 wersje. Trzy pierwsze to efekt stackowania skryptem <em>Naztronomy</em>
<div class="galeria">
       <img src="https://blgpht.argilus.online/api/files/119/original/NGC_6946_918x30.jpg" alt="galaktyka Fajerwerk">
       <img src="https://blgpht.argilus.online/api/files/131/original/NGC_6946_918x30-2.jpg" alt="galaktyka Fajerwerk">
       <img src="https://blgpht.argilus.online/api/files/15/original/NGC_6946_918x30-3.jpg" alt="galaktyka Fajerwerk">
</div>
<div style="text-align: center; font-style: italic"><em>918x30 sek = 7h39</em></div>
A ostatni stackowany skryptem Seestara.
<img src="https://blgpht.argilus.online/api/files/125/original/NGC_6946_953x30s_v2-2.jpg" alt="Galaktyka Fajerwerk"></p>

<div style="text-align: center; font-style: italic">*953x30 sek = 7h56m30s*</div>


    <a href="https://blog.argilus.online/czach/galaktyka-fajerwerk-noc-2" class="series-nav-item prev" rel="nofollow">
        <span class="series-nav-direction">← Poprzedni w serii</span>
        <span class="series-nav-title">Galaktyka Fajerwerk, noc 2.</span>
    </a>


<p><a href="/czach/tag:astrofotografia" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">astrofotografia</span></a> <a href="/czach/tag:astrophotography" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">astrophotography</span></a> <a href="/czach/tag:Seestar" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">Seestar</span></a> <a href="/czach/tag:WizardNebula" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">WizardNebula</span></a> <a href="/czach/tag:FireworksGalaxy" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">FireworksGalaxy</span></a></p>

<p>—
Marcin “czach” Trzaska
reply-to: <a href="https://blog.argilus.online/@/czach@mastodon.argilus.online" class="u-url mention" rel="nofollow">@<span>czach@mastodon.argilus.online</span></a></p>
]]></content:encoded>
      <guid>https://blog.argilus.online/czach/fajerwerk-i-czarodziej-czesc-trzecia-druga</guid>
      <pubDate>Tue, 01 Sep 2026 12:03:18 +0000</pubDate>
    </item>
    <item>
      <title>Galaktyka Fajerwerk, noc 2.</title>
      <link>https://blog.argilus.online/czach/galaktyka-fajerwerk-noc-2</link>
      <description>&lt;![CDATA[Chmurwy się trochę zlitowały i udało mi się zebrać dodatkowego materiału. Ponieważ nie miałem pewności, kiedy znów nadejdą, więc zbierałem tylko fajerwerka.&#xA;&#xA;A chmurwy zbliżały się.&#xA;Gdy zakończyłem zabawę miałem 902 klatki po 30 sekund, trochę odrzucił ASTAP a trochę Siril. Ostatecznie plik wynikowy jest złożony z 765 klatek.&#xA;&#xA;Dalsza obróbka zaowocowała czterema wersjami pliku JPG.&#xA;&#xA;table&#xA; th colspan=&#34;2&#34;Wersja emGeneralised Hyperbolic Stretch transformations (GHS)/em/th&#xA;&#xA;  tr&#xA;    td align=&#34;center&#34;&#xA;      a href=&#34;https://blgpht.argilus.online/api/files/107/original/NGC6946765x30s-2.jpg&#34;img src=&#34;https://blgpht.argilus.online/api/files/107/variants/ffmpeg-1280x1280-in/NGC6946765x30s-2.jpg&#34; alt=&#34;NGC 6946 765x30s 2&#34;/a&#xA;    /td&#xA;    td align=&#34;center&#34;&#xA;      a href=&#34;https://blgpht.argilus.online/api/files/109/original/NGC6946765x30s.jpg&#34;img src=&#34;https://blgpht.argilus.online/api/files/109/variants/ffmpeg-1280x1280-in/NGC6946765x30s.jpg&#34; alt=&#34;NGC 6946 765x30s&#34;/a&#xA;    /td&#xA;  /tr&#xA;trtd align=&#34;center&#34;bez ekstra wyostrzania w LR/tdtd align=&#34;center&#34;z wyostrzeniem w LR/td/tr&#xA;/table&#xA;&#xA;br&#xA;&#xA;table&#xA; th colspan=&#34;2&#34;Wersja emHistogram transformation/em/th&#xA;  tr&#xA;    td align=&#34;center&#34;&#xA;      a href=&#34;https://blgpht.argilus.online/api/files/108/original/NGC6946765x30sb-2.jpg&#34;img src=&#34;https://blgpht.argilus.online/api/files/82/variants/ffmpeg-1280x1280-in/NGC6946765x30sb-2.jpg&#34; alt=&#34;NGC 6946 765x30s b 2&#34;/a&#xA;    /td&#xA;    td align=&#34;center&#34;&#xA;      a href=&#34;https://blgpht.argilus.online/api/files/110/original/NGC6946765x30sb.jpg&#34;img src=&#34;https://blgpht.argilus.online/api/files/146/variants/ffmpeg-1280x1280-in/NGC6946765x30sb.jpg&#34; alt=&#34;NGC 6946 765x30s b&#34;/a&#xA;    /td&#xA;  /tr&#xA;trtd align=&#34;center&#34;bez ekstra wyostrzania w LR/tdtd align=&#34;center&#34;z wyostrzeniem w LR/td/tr&#xA;/table&#xA;&#xA;div style=&#34;text-align: center;&#34;em765x30 sek = 6h22m30s/em/div&#xA;&#xA;nav class=&#34;series-nav&#34;&#xA;    a href=&#34;https://blog.argilus.online/czach/galaktyka-fajerwerk-i-mglawica-czarodzieja&#34; class=&#34;series-nav-item prev&#34;&#xA;        span class=&#34;series-nav-direction&#34;← Poprzedni w serii/span&#xA;        span class=&#34;series-nav-title&#34; Fajerwerk i Czarodziej /span&#xA;    /a&#xA;/nav&#xA;&#xA;#astrofotografia #astrophotography #Seestar #FireworksGalaxy&#xA;&#xA;-- &#xD;&#xA;Marcin &#34;czach&#34; Trzaska&#xD;&#xA;reply-to: @czach@mastodon.argilus.online]]&gt;</description>
      <content:encoded><![CDATA[<p><em>Chmurwy</em> się trochę zlitowały i udało mi się zebrać dodatkowego materiału. Ponieważ nie miałem pewności, kiedy znów nadejdą, więc zbierałem tylko <em>fajerwerka</em>.</p>

<p>A <em>chmurwy</em> zbliżały się.
Gdy zakończyłem <em>zabawę</em> miałem 902 klatki po 30 sekund, trochę odrzucił <em>ASTAP</em> a trochę <em>Siril</em>. Ostatecznie plik wynikowy jest złożony z 765 klatek.</p>

<p>Dalsza obróbka zaowocowała czterema wersjami pliku <em>JPG</em>.</p>

<table>
 <th colspan="2">Wersja <em>Generalised Hyperbolic Stretch transformations (GHS)</em></th>

  <tr>
    <td align="center">
      <a href="https://blgpht.argilus.online/api/files/107/original/NGC_6946_765x30s-2.jpg" rel="nofollow"><img src="https://blgpht.argilus.online/api/files/107/variants/ffmpeg-1280x1280-in/NGC_6946_765x30s-2.jpg" alt="NGC 6946 765x30s 2"></a>
    </td>
    <td align="center">
      <a href="https://blgpht.argilus.online/api/files/109/original/NGC_6946_765x30s.jpg" rel="nofollow"><img src="https://blgpht.argilus.online/api/files/109/variants/ffmpeg-1280x1280-in/NGC_6946_765x30s.jpg" alt="NGC 6946 765x30s"></a>
    </td>
  </tr>
<tr><td align="center">bez ekstra wyostrzania w LR</td><td align="center">z wyostrzeniem w LR</td></tr>
</table>

<p><br></p>

<table>
 <th colspan="2">Wersja <em>Histogram transformation</em></th>
  <tr>
    <td align="center">
      <a href="https://blgpht.argilus.online/api/files/108/original/NGC_6946_765x30s_b-2.jpg" rel="nofollow"><img src="https://blgpht.argilus.online/api/files/82/variants/ffmpeg-1280x1280-in/NGC_6946_765x30s_b-2.jpg" alt="NGC 6946 765x30s b 2"></a>
    </td>
    <td align="center">
      <a href="https://blgpht.argilus.online/api/files/110/original/NGC_6946_765x30s_b.jpg" rel="nofollow"><img src="https://blgpht.argilus.online/api/files/146/variants/ffmpeg-1280x1280-in/NGC_6946_765x30s_b.jpg" alt="NGC 6946 765x30s b"></a>
    </td>
  </tr>
<tr><td align="center">bez ekstra wyostrzania w LR</td><td align="center">z wyostrzeniem w LR</td></tr>
</table>

<div style="text-align: center;"><em>765x30 sek = 6h22m30s</em></div>


    <a href="https://blog.argilus.online/czach/galaktyka-fajerwerk-i-mglawica-czarodzieja" class="series-nav-item prev" rel="nofollow">
        <span class="series-nav-direction">← Poprzedni w serii</span>
        <span class="series-nav-title"> Fajerwerk i Czarodziej </span>
    </a>


<p><a href="/czach/tag:astrofotografia" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">astrofotografia</span></a> <a href="/czach/tag:astrophotography" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">astrophotography</span></a> <a href="/czach/tag:Seestar" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">Seestar</span></a> <a href="/czach/tag:FireworksGalaxy" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">FireworksGalaxy</span></a></p>

<p>—
Marcin “czach” Trzaska
reply-to: <a href="https://blog.argilus.online/@/czach@mastodon.argilus.online" class="u-url mention" rel="nofollow">@<span>czach@mastodon.argilus.online</span></a></p>
]]></content:encoded>
      <guid>https://blog.argilus.online/czach/galaktyka-fajerwerk-noc-2</guid>
      <pubDate>Sun, 30 Aug 2026 07:23:20 +0000</pubDate>
    </item>
  </channel>
</rss>