ICPC 2020 Asia Yokohama Regional 参加記

チームHiCoderで参加しました。メンバーはオータム(@autumn_314)とおがーたそん(@Ogtsn99)と私(@kametaro49) 

ちなみに国内予選は65位だった。 

お菓子の処遇

前日のリハまで手を付けませんでした!  

本番

朝早かったけど起床成功。一応ICPCのTシャツを着る。メンバーとはDiscordで通話しながらである。 

スタート!

A問題を見る。中学の技術でやった投影図みたいなシルエットが与えられるから、それが構成可能かどうか判定しろとのこと。英語なので読むのにちょい時間がかかった。

  1. 3方向から見て埋まってるなら埋めることをする。
  2. 今度は逆に埋めたものからシルエットを作成する。
  3. 与えられたものとシルエットが一致すれば構成可能、そうでなければ構成不可。

A問題AC 0:22 17位!

f:id:kametaro49:20210322162039p:plain

B問題を見る。穴あき配列が与えられるから条件を満たすように埋めよとのこと。貪欲でいけそうだという話をして、おがーたそんと並列コーディング。書いてる途中でおがーたそんがB問題AC 0:53

オータムさんが次はJかなという話をする。

C問題を見る。与えられる迷路を解ける最小行数のコードを作れとのこと。GOTOやIFすら存在できるので、こんなに自由度のある問題は全探索以外無理ではという気がする。左手法でもいけそうだと思う。左手法も存在することだしコード行数がそんなに大きくなることはないのではと薄々感じる。とりあえず全探索を書き始める。

TLEの予感がムンムンする。しかし実行時間も10秒まで許されているので、信じて書き続ける。おがーたそんとオータムさんはJを解いている。

  1. コード長を1から順に指定してDFSでコードを生成。
  2. 迷路内でコードを使ってシミュレーション。
  3. Setと状態<位置、方向、コード位置>を用いて、ループを検知したら終了。
  4. ゴールに辿り着いたら答えとして出力。

C問題WA

TLEじゃなくてWA!?と驚きながら問題とコードを眺める。

コード行を0-indexedで提出してしまっていたことに気づく。

修正してこれならTLEやろと提出、C問題AC 1:49

Jは解いてくれそうなのでGを読む。

読んでるとおがーたそんがJ問題AC 2:14 17位!!

f:id:kametaro49:20210322162113p:plain

Gの問題理解にかなり手間取る。オータムさんが一通り問題を読んで考察を入れてくれている。

条件を満たす最小のしきい値を求めなければならない。

しきい値を決めたら、UnionFindのfindとrankを使えば条件を満たすかは判別できることに気がつく。しかし、全ての値を調べるとUnionFindに時間がかかりG問題TLE(2回)しきい値が2分探索の性質を満たしていないことも確認。online dynamic connectivityか?(削除可能unionfind)という話に、java版が見つからないので頓挫。

かなり疲れが溜まっていたので停滞…

おがーたそんがEを書いてて誤差が出ているらしい。2分探索と角度という話なので、確かに!と自分もEを書き始める。が、

TIMEOVER!!

 

結果27位!。順位表的に4完では最上位。でも全員賞があるらしい、やったね!

 

懇親会は疲れと眠気でほぼダウンしていた模様

お題「回」unity1weekで謎ゲーを一週間で制作!

unityroomで開催された1WeekGameJam、#unity1week に参加しました!

 

出来上がりがこちらになります

unityroom.com

 

構想編

前前作がパズル、前作が2Dアクションだったので、今回は3Dを作りたいなと考えていた。アクション以外の3Dってどんなのがある?結果、俯瞰視点での3DゲーであるところのピクミンCivシムシティ系の方向が浮かび上がる。その頃は競技プログラミングに頭が侵されていたので、アリを表現するとおもしろいのでは…!

 

競プロ→アルゴリズム→蟻本→アリ→!!!

 

お題発表前にして、制作物が概ね決まってしまう。

お題発表「回」

回す…回転しないと…いや回収なら…そのままいけるかも!

 

制作編

3Dということで、モデリングから始まる。

f:id:kametaro49:20210322143157p:plain

クロオオアリの画像を見ながらBlenderでローポリなアリのモデルを作成。ボーンを入れて、ウェイトペイントを追加。さらに歩行のアニメーションを作った。(絵心ゼロでも割と作れるのが3Dのいいところ)

 

コーディング

付箋アプリにまとまってきたアルゴリズムを実装していく。よくまとまっていたのでアリの行動パターンは300行で収まった。どちらかというとヘックス座標系の実装に手間取る。

public static readonly Vector2Int[] V2S = {
        new Vector2Int(20),
        new Vector2Int(11),
        new Vector2Int(-11),
        new Vector2Int(-20),
        new Vector2Int(-1, -1),
        new Vector2Int(1, -1),
        new Vector2Int(00)
};

Dictionary(他言語でのmap)を使い、方向は上記のベクトルを用いて記述する。

f:id:kametaro49:20210322145023p:plain

 

地形関係を追加すると、α版が完成!

f:id:kametaro49:20210322145246p:plain

既に見ていてたのしい。

 

仕上げ

ここから、食べ物、アイテム、テクスチャ、ライティング、UI、サウンドなどなどたくさん追加!

f:id:kametaro49:20210322145758p:plain

 

この辺でクッソ重いことに気付く。どうやら雲の描画に難あり

f:id:kametaro49:20210322150238p:plain

ポリゴンを頑張って削ってもどうにもならない。

f:id:kametaro49:20210322150243p:plain

パーティクルにすると、なんと軽い!見た目もよし、変化も有りでこちらのほうが良かった。

 

反省編

ゲーム性どこ?まあこれは最初から分かっていた……

操作性の難が大きかったのは真に反省点。civ的にクリックで移動かつ、画面は回転させないほうがよかった(かなり酔いやすい)

 

結果

f:id:kametaro49:20210322150951p:plain

なんと斬新さ10位! 楽しさ47位でした。

 

回収アリゴリズム | フリーゲーム投稿サイト unityroom

 

UbuntuをUSBブートしてSurfaceからデータを救出してみる

大学生協PCサポートを売りにしているが、Windowsがぶっ壊れた場合、初手クリーンインストールらしい。もちろんデータ救出もなし。ストレージが少ないから生協PCはアプデに失敗しやすい…

対象環境

必要条件

  • 他の動くPC
  • USB(4GB以上)

実践

スクショが一枚もない(手抜き)

LiveUSB作成編

  1. Ubuntuのisoイメージをダウンロード
    日本語Remixがおすすめ 

    www.ubuntulinux.jp

  2. Universal USB Installerをダウンロード
    USBからisoイメージを起動できるようにするもの
    こちらはインストール不要なので楽

    universal-usb-installer.jp.uptodown.com

    他のツールとしてReRuなどもある。
  3. USBをLiveUSB化
    Universal USB Installerを起動して指示に従う。
    場所を間違えてドライブを吹っ飛ばさないように…

Ubuntu起動編

  1. Surfaceの起動順序を変更
    SurfaceBIOSUEFI)は音量の+ボタンを押しながら電源を押すことで開く。
    USBから起動するように設定。
  2. USBをさしてUbuntuを起動
    今回はインストールはせずにUbuntuを試すを選択。

データ救出編

bitlockerを使ってなかったらもうデータを救出できるはずです。

  1. Wifiをつなげておく

    ネットワークがないと何もインストールできない…

  2. sudo apt update
    これいる?
  3. sudo apt install dislocker
    bitlockerを解除するためのツールをインストール
  4. sudo fdisk -l
    どのデバイスMicrosoft基本データとなっているか確認。
    今回は/dev/nvme0n1p3だった
  5. mkdir それぞれ

    解除用と、マウント用 (hoge, fuga)

  6. dislockerと回復キーを組み合わせ、bitlockerを解除

    48桁の回復キーを入力…

    sudo dislocker -r -V /dev/nvme0n1p3 -p888888-888888-...... --hoge

  7. できたファイルをマウントし、中身をみる

    sudo mount hoge/dislocker-file fuga

    ファイルビューアから見れるようになるので、データを救出!

    Ubuntuにデータを保存しても電源切ると消えるので注意

参考

LiveUSBをつくるとこまで

blog.mktia.com

Ubuntuを起動してから

www7390uo.sakura.ne.jp

LaTeX 記号チートシート in Hatena Blog

\LaTeX(\TeX)での数学記号・特殊文字・大型文字を雑に列挙。in HatenaBlog

なお、HatenaBlogではMathJaxライブラリが使用されている

ギリシャ文字

\alpha \alpha    
\beta \beta    
\gamma \gamma \Gamma \Gamma
\delta \delta  \Delta \Delta
\epsilon \epsilon \varepsilon \varepsilon
\zeta \zeta     
\eta  \eta      
\theta \theta \Theta \Theta
\vartheta \vartheta    
\iota \iota    
\kappa \kappa    
\lambda \lambda \Lambda \Lambda
\mu \mu    
\nu \nu    
\xi \xi \Xi \Xi
\omicron \omicron    
\pi \pi \Pi \Pi
\rho \rho \varrho \varrho
\sigma \sigma  \Sigma \Sigma
\varsigma \varsigma    
\tau \tau    
\upsilon \upsilon  \Upsilon \Upsilon
\phi \phi  \Phi \Phi
\varphi \varphi    
\chi \chi    
\psi \psi  \Psi \Psi
\omega \omega  \Omega \Omega

装飾

\hat{x} \hat{x}
\bar{x} \bar{x}
\dot{x} \dot{x}
\vec{x} \vec{x}
\check{x} \check{x}
\grave{x} \grave{x}
\tilde{x} \tilde{x}
\ddot{x} \ddot{x}
\widehat{x} \widehat{x}
\acute{x} \acute{x}
\breve{x} \breve{x}
\widetilde{x} \widetilde{x}
\mathrm{xyzXYZ} \mathrm{xyzXYZ}
\mathit{xyzXYZ} \mathit{xyzXYZ}
\mathcal{xyzXYZ} \mathcal{xyzXYZ}
\text{xyzXYZ} \text{xyzXYZ}
\mathbb{xyzXYZ} \mathbb{xyzXYZ}

演算子

+ + - -
* * / /
| | \Vert \Vert
\lceil \lceil \rceil \rceil
\lfloor \lfloor \rfloor \rfloor
\times \times \div \div
\pm \pm \mp \mp
\star \star \ast \ast
\cap \cap \cup \cup
\vee \vee \wedge \wedge
\oplus \oplus \ominus \ominus
\odot \odot \oslash \oslash
\boxplus \boxplus \boxminus \boxminus
\boxtimes \boxtimes \boxdot \boxdot
\otimes \otimes    

関係

\lt \lt \gt \gt
\le \le \ge \ge
\leqq \leqq \geqq \geqq
\ll \ll \gg \gg
= = \neq \neq
\equiv \equiv \fallingdotseq \fallingdotseq
\sim \sim \simeq \simeq
\therefore \therefore \because \because
\neg \neg    

集合

\in \in \ni \ni
\notin \notin    
\subset \subset \supset \supset
\subseteq \subseteq \supseteq \supseteq
\emptyset \emptyset \varnothing \varnothing
\forall \forall \exists \exists

矢印

\leftarrow \leftarrow \rightarrow \rightarrow
\longleftarrow \longleftarrow \longrightarrow \longrightarrow
\Leftarrow \Leftarrow \Rightarrow \Rightarrow
\leftrightarrow \leftrightarrow \Leftrightarrow \Leftrightarrow
\longleftrightarrow \longleftrightarrow \Longleftrightarrow \Longleftrightarrow
\iff \iff    

記号

\triangle \triangle \square \square
\angle \angle \nabla \nabla
\S \S    
\LaTeX \LaTeX \TeX \TeX
\sum \sum \prod \prod
\int \int \iint \iint
\partial \partial  \cdot \cdot
\dots \dots \cdots \cdots
\vdots \vdots \ddots \ddots
\infty \infty \lim \lim
' ' \prime \prime
\bot \bot \top \top
\lbrack \lbrack \lbrace \lbrace

大型演算子の記法

\sum_{i=0}^{N} \sum_{i=0}^{N}
\int_{0}^{\infty} \int_{0}^{\infty}
\lim_{0\rightarrow \infty} \lim_{0\rightarrow \infty}
\frac{1}{N} \frac{1}{N}
a\left(\frac{1}{b}\left(c+d\right)\right) a\left(\frac{1}{b}\left(c+d\right)\right)
displaystyle化
\displaystyle{\sum_{i=0}^{N}} \displaystyle{\sum_{i=0}^{N}}
\displaystyle{\int_{0}^{\infty}} \displaystyle{\int_{0}^{\infty}}
\displaystyle{\lim_{0\rightarrow \infty}} \displaystyle{\lim_{0\rightarrow \infty}}
\displaystyle{\frac{1}{N}} \displaystyle{\frac{1}{N}}
\displaystyle{a\left(\frac{1}{b}\left(c+d\right)\right)} \displaystyle{a\left(\frac{1}{b}\left(c+d\right)\right)}

VOICEROIDを買ってみた ~VOICEROIDで出来ること~

VOICEROIDとは

VOICEROIDとは音声合成ソフトで、かわいい声で文章を読み上げてくれます。 Youtubeやニコニコでもよく使用されていますね。

購入

買ったのはVOICEROID2 の琴葉姉妹(茜・葵) 関西弁を喋れる茜ちゃんと、標準語の葵ちゃんの二人であることと、単純に好みで選んだ。 https://www.ah-soft.com/images/press/voiceroid2/voiceroid2_kotonoha_box.jpg ダウンロード版にしたので箱はないですが。

基本

テキストボックスに文章を入れて、音声を再生または保存することができる。保存するなら.wavファイルになる。

自分は作ってるゲームに音声を入れたくなったので、セリフを作るのに使った。動画制作でも同じく、音声をファイル化して動画に入れ込むことになる。

チューニング

いわゆる調声。デフォルトでもゆっくりよりよっぽど良いものが出来るのでほぼ触ることはない。 単語登録も一般的な語句は既に辞書に入っている。専門用語や固有名詞は単語登録してアクセントを変えることがある。 英語は一応喋れる。一応なので日本人風に読むし、辞書も弱い。

VOICEROID2なので、喜び・怒り・悲しみの度合いを変えることも出来る。怒りは結構かわいく怒って、悲しみはわかりやすく落ち込んだ感じになる。

各種連携

VOICEROID自体にはapiは一切着いていませんが、色んな人がUIAutomationで自動化したものを公開しています。

wikiwiki.jp

f:id:kametaro49:20210121192401j:plain
ボイスロイド連携

YMM ゆっくりムービーメーカー

ゆっくりとは書いてあるが、プラグインでVOICEROIDに対応することが出来る。 ゆっくりムービーメーカー自体はAviUtlの拡張で、これがおそらくVoiceroid動画を作る定石になる。

棒読みちゃん

棒読みちゃんは、連携に特化しているゆっくり音声のソフト。 ニコ生・Youtube Liveのコメ読み上げや、Twitter読み上げ、ゲームのチャット読み上げなどに使われている。 そして棒読みちゃんはsocket通信、http通信で外部プログラムから読み上げを指示することが出来る。 その棒読みちゃんのゆっくりを、プラグインでVOICEROIDに変更することが出来るので、読み上げに関しては実質的になんでも連携できる。

Unityで動的に地形ポリゴン生成&Collider生成

 

目標

いわゆる穴掘りゲームで、3Dポリゴン表示かつ、いい感じに掘りたい。操作性は2Dでいい。いやこれMinecraftじゃん。 

f:id:kametaro49:20201215154241p:plain

イメージ

掘ると何が起こる?

ポリゴンの構成要素である頂点、面(辺は面に付属する)から考えると、穴を掘って洞窟的になると頂点も面も増えます。一般的な街づくりゲームとかの地形編集は、頂点を上下させるだけなので、洞窟は作れません。

f:id:kametaro49:20201215144734p:plain

左:単純に頂点を上下 右:頂点・面を増加

In Unity

ブロック的な地形になるので、キューブを大量に配置するだけでも一応作れます。しかし、大量のオブジェクトを扱うと重いです。そのためオブジェクトとしては1つで、そのポリゴンを編集することで表現したいですね。

Unityはどのようにポリゴンを扱っている?

コンポーネントとして、MeshFilter、MeshRendererがありますね。MeshFilterがMesh(ポリゴン)のデータを保持し、MeshRendererがそのレンダリング設定を担当しているようです。つまりMeshFilterが保持しているMeshを編集すればよいわけですね。

Meshには、まず頂点配列であるVertices、面を頂点番号から保持しているtriangles(すべて三角面)、面がどちらを向いているかを示す法線のnormals、そしてテクスチャマッピングに使うuvがあります。これらを編集です…(多いわ)

実装(どうやった?)

最初は実際の見た目と同じように、最小限の頂点で構成しようとしていました。しかし、そうすると掘るたびに頂点を追加し、面も貼らなくてはなりません。頂点番号と面の対応付けが難しくて実装できんかった。

頂点

イメージの通り、奥行きは手前と奥の2段階です。そのため2層のグリッド状に頂点を事前に配置することにしました。使わない頂点には面を付けなければ問題ありません。掘るたびに頂点を更新する必要もなくなります。uvは頂点と対応しているのでついでにめちゃくちゃを設定しておきます。

        List<Vector3vertices = new List<Vector3>(4 * Size * Size);
        List<Vector2uvs = new List<Vector2>();

        for (int d = 0d < 4d++)
        {
            for (int y = 0y < Sizey++)
            {
                for (int x = 0x < Sizex++)
                {
                    vertices.Add(vectormap[dxy]);
                    uvs.Add(new Vector2(Random.valueRandom.value));
                }
            }
        }
        mesh.SetVertices(vertices);
        mesh.SetUVs(0uvs);

vectormapには単純に頂点座標のVector3が入っています。4層になっているのは後述。

面貼りには、四角形の面を貼りたいところですが、全て三角形でなければなりません。meshに四角形で指定すると三角形に変換して設定してくれるメソッドがあるので使います。

        List<intmeshing = new List<int>();

        for (int y = 0y <= RealSizey++)
        {
            for (int x = 0x <= RealSizex++)
            {
                if (IsDigged(xy))
                {
                    meshing.Add(Indexer(1xy));
                    meshing.Add(Indexer(1x + 1y));
                    meshing.Add(Indexer(1x + 1y + 1));
                    meshing.Add(Indexer(1xy + 1));

                    if (!IsDigged(x - 1y))
                    {
                        meshing.Add(Indexer(3xy));
                        meshing.Add(Indexer(3xy + 1));
                        meshing.Add(Indexer(2xy + 1));
                        meshing.Add(Indexer(2xy));
                    }
                    if (!IsDigged(xy - 1))
                    {
             省略
                    }
                }
                else
                {
             省略

                    if (IsDigged(x - 1y))
                    {
             省略
                    }
                    if (IsDigged(xy - 1))
                    {
             省略
                    }

                }
            }
        }

        mesh.SetIndices(meshing.ToArray(), MeshTopology.Quads0);

まさにゴリ押し。IsDiggedとIndexerは自作関数です。Indexerは頂点番号が帰ってきますね。側面があるかどうかには非常に多くの場合分けが発生します…

法線

法線は、便利なメソッドを実行すればおk 

mesh.RecalculateNormals();

なぜ4層?

f:id:kametaro49:20201215161742p:plain

2層で表現・4層で表現

1つの場所に2つの頂点を配置し、側面と使い分けています。こうするとスムージングが働かなくなるようです。ちなみに、Unityのデフォルトキューブも8頂点ではなく24頂点。

Collider生成

残念ながら、いい感じにCollider2Dを自動生成してくれるものがありません!(collider3Dは知らない)

Colliderも大量生成すると重いので、まとめてColliderを生成したいと思います。EdgeCollider2Dを使用。これも頂点配列をセットすることで実現できます。EdgeCollider1つにつき一本の線なので、まとまりごとに1つのColliderですね。迷路を解くときみたいに右手方を実装しました。16通り場合分け…

line = gameObject.AddComponent<EdgeCollider2D>();
List<Vector2points = new List<Vector2>();
省略
line.points = points.ToArray();

 

完成

f:id:kametaro49:20201215163927p:plain

f:id:kametaro49:20201215163955p:plain

今回の方法だと右下ちょっとバグる

f:id:kametaro49:20201215164045p:plain

ちゃんと3D

 Unity2019.2.4f1

ふたご座流星群を撮影して画像処理

はじめに

12月最大の流星群はふたご座流星群です。今年2020年は条件がとても良いらしい。条件というと、月が出ていなくて、都市の光源から離れていて、雲ひとつなく晴れていることです。今年は新月と重なっています! 12日土曜日の夜は雲がほとんどなく晴れていたので、ふたご座流星群の撮影をしました。はじめに書きますがそんなに撮れてないです。肉眼ではかなり沢山見えました。

(流星群のピークは月曜ですが幅は一週間くらいあります)

 

f:id:kametaro49:20201213180229j:plain

Take a picture

最近の夜景に対応したスマホでも撮れないこともないですが、まあね?

今回はSonyのカメラであるILCE-7M3と、レンズはFE 16-35mm F2.8 GMを使います。簡単に説明すると、ちょっと大きい一眼カメラと、広角レンズの組み合わせです。

今回の機材

  • カメラ (ILCE-7M, FE 16-35mm F2.8 GM)
  • 三脚
  • ノートPC (Surface)
  • 毛布

撮影した場所が海の側で、深夜になるのでマジ寒いので防寒は必須… 

カメラとノートPCをUSBで繋ぎ、PCから操作します。SonyなのでImagingEdgeというアプリです。これなら撮影中に操作してもカメラが動いたりする心配がない!

設定

15秒おきに以下の設定でインターバル撮影!.jpgの他に生データの.arwも保存。

絞り値 f/2.8
露出時間 10秒
ISO 6400
焦点距離

16mm

まず、絞り値は全開(最小の値)にします。光を多く取り入れるためですね。

露出時間は流星を収めたいので長めに、10秒の間に流れ星が通れば映るということです。長すぎると星が線になってしまいます。(日周運動) ここで赤道儀という、日周運動と同じ速さでカメラを動かすアイテムがありますが、今回はスルー

Amazon.co.jp: Vixen ポータブル赤道儀 星空雲台ポラリエ(WT) ホワイト 355051: カメラ

ISOは光の感度です、センサー側でどれだけ光を増幅するか決められます。高ければより明るく映りますが、高すぎるとノイズまみれになります。

焦点距離はいわゆるズームで、大きいと望遠、小さいと広角ですね。今回は最小にしています。

最後にピントですが、暗いと難しいです。オートフォーカスで運良くピントが合えば、マニュアルに切り替えて触らないようにします。

あとは待ち続けました。(1,2時間)

現像

タイムラプスに編集するもよし、流れ星が映っている写真を探すもよし、結合して星の線を描くもよし。

タイムラプス編

タイムラプスとは、細かく撮影した写真を連続して表示した動画である。動画の早送りと異なり1コマに対する画像があまり圧縮されていないので綺麗。

同じくSonyPlayMemories Homeを使うと簡単。

f:id:kametaro49:20201213173753g:plain

100枚の写真をまとめたタイムラプスGIF

はてなブログの10MB制限に引っかかり解像度は縦横20分の1になっている。流星はぶっちゃけわからん。ホワイトバランスの設定をミスっており若干赤みがかっている。

流星検出編

計300枚ほど撮った写真を一枚づつ見ていく… 割と地味なので見つからない。記事の最初に貼った写真が見つけたもの。写真は6K×4Kなのでそもそもディスプレイの解像度が足りない。プログラムで自動化したいが、日周運動と雲ノイズの扱いがムズそう…専用のソフトもちらほらあるっぽい。

写真結合編

よく見る空が北極星を中心に回転している画像は、露出時間をめっちゃ長くするか、結合するとできる。結合の仕方は簡単に2枚の画像の画素単位で比較し、明るい方を残す「比較明合成」でできる。 GIMPとかでもできる。ただし一枚一枚操作が要るので多分面倒。こっちも専用のソフトはあると思う。でも面倒事はプログラムにやらせよう!(ようやくITっぽくなった)画像処理といえばpythonらしい(ほんとか?

jupyter notebookにて

import cv2
import glob
import matplotlib.pyplot as plt
import numpy as np
maindir = "2020-12-13-RAW\\group3\\"
imgfiles = glob.glob(os.path.join(maindir, '*.JPG'))
im = cv2.imread(imgfiles[0])
for fn in imgfiles:
    nextim = cv2.imread(fn)
    im = np.maximum(nextim,im)
plt.figure(figsize=(6.4 * 34.8 * 3))
plt.imshow(cv2.cvtColor(im, cv2.COLOR_BGR2RGB))
cv2.imwrite(str(time.time())+".jpg",im)

OpenCVに比較明合成くらいあるかと探したんですが、見つかりませんでした。普通にnumpyで最大値をとっています。でもこれだと多分R,G,Bでそれぞれ個別に最大値をとっているので、少しおかしいです。見た目はほぼ変わりませんが。ちなみにpyplotはRGBなのにOpenCVがBGRという罠があります。

せっかくなのでJavaでRGBまとめて比較するのを書いた。

    MeteorPic(File dir) {
        File[] files = dir.listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File dirString name) {
                return name.endsWith(".JPG");
            }
        });
        try {
            BufferedImage sum = ImageIO.read(files[0]);
            ColorModel color = ColorModel.getRGBdefault();
            for (int i = 1i < files.lengthi++) {
                BufferedImage image = ImageIO.read(files[i]);
                for (int x = 0x < sum.getWidth(); x++) {
                    for (int y = 0y < sum.getHeight(); y++) {
                        int sumbright = brightness(colorsumxy);
                        int imagebright = brightness(colorimagexy);
                        if (sumbright < imagebright) {
                            sum.setRGB(xyimage.getRGB(xy));
                        }
                    }
                }
            }

            ImageIO.write(sum"jpg"new File(dir.getName() + ".jpg"));
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    private int brightness(ColorModel colorBufferedImage imageint xint y) {
        int rgb = image.getRGB(xy);
        int bright = color.getRed(rgb) + color.getGreen(rgb) + color.getBlue(rgb);
        return bright;
    }

numpyでやるよりは遅くなります… 多分並列化してどっこいどっこい。

BufferedImageでは、1ピクセルのRGBがint値一つにまとまって返されます。こいつもBGRで、一色8bitらしい。ColorModelクラスでそこらへんのややこしい話がコンテナ化されている。単純にR+G+Bで比較明合成。

f:id:kametaro49:20201213184324p:plain

Java,右numpy 圧縮率も違うので何もわからん。

f:id:kametaro49:20201213184622j:plain

この中に流星だけ違う方向に流れてすごい!ってなる予定だった。

f:id:kametaro49:20201213185828j:plain

航空機が写り込むと、機体の点滅と撮影のインターバルが写りこむ。雲が流れても写り込む。