Emgu CVで星空を撮影する

画像

こんにちは、Habr。

偶然にも写真と天文学に長い間興味を持っていました。 星空を撮るのが好きです。 夜はほとんど光がないので、本当に美しいものを得るには、かなり長い露出をする必要があります。 しかし、ここで別の問題が発生します-地球が回転するという事実のために、空の星が動きます。 したがって、比較的長い露出では、星は点でなくなり、弧を描き始めます。 深空のオブジェクトを撮影/観察するときにこの動きを補正するために、デバイス- マウントがあります。 残念ながら、現時点ではマウントを購入する方法はないので、自分で質問することにしました-プログラムで同様の効果を実装することは可能ですか?

カットの下にたくさんの写真。 投稿内のすべての写真は私のものであり、(ほとんどすべて)クリック可能で、無料でダウンロードできます。

はじめに


流れ星の問題はこれです:彼らは動きます。 一見したところ、この動きは非常に目立たないように見えるかもしれませんが、比較的短いシャッタースピード(20″ +)でも、星はもはやポイントになりません。空を通る短い弧が見え始めます。

画像
露出〜15 "

画像
露出〜20 '

理論


地球は自身の軸を中心に回転します。 比較的遠い星、この期間は86164.090530833秒です。
したがって、シャッタースピードがわかれば、フレーム内のすべての星が中心からどの程度回転したかを計算できます。 この値によってフレーム全体を反対方向に回転させることでこの回転を補正する場合、すべての星が所定の位置に残る必要があるという考え方です。

すべてが回転する中心を見つける問題は問題ではありません。 極星を見つけるのに十分です-地球の回転軸は非常に近くを通過します。

画像
天球-同じ軸。

実装



このアイデアを実装するために、私はEmgu CV-ラッパーライブラリOpenCV for .NETを使用することにしました。

プログラム全体をペイントするのではなく、基本的な方法についてのみ説明します。

写真が重なり合っている場合、Photoshopでは通常、ブレンドモード:明るくします。 その本質は2つの画像の本質であり、最高の明るさを持つピクセルを選択する1つです。 つまり、2つのソース画像に2つのピクセルがある場合、結果の画像にはより明るいピクセルが含まれます。

Emgu CVでは、このメソッドは既に実装されています。

public Image<TColor, TDepth> Max( Image<TColor, TDepth> img2 ) 


モード1:回転なしの画像の追加

ここでは複雑なことはありません-リストのすべての写真を交互に重ねるだけです。

 List<string> fileNames = (List<string>)filesList; // input Image<Bgr, Byte> image = new Image<Bgr, Byte>(fileNames.First()); // resulting foreach (string filename in fileNames) { Image<Bgr, Byte> nextImage = new Image<Bgr, byte>(filename); image = image.Max(nextImage); nextImage.Dispose(); pictureProcessed(this, new PictureProcessedEventArgs(image)); // updating image in imagebox } 


なぜこのモードが必要ですか? 次に、写真を加算した後、星の動きから弧が生じます。 回転の中心(極星)を簡単に見つけることができます。 また、トレース付きの非常に興味深い写真が得られることもあります。

モード2:回転補正による画像の補正

このモードでは、すべてが少し複雑になります。 最初に、撮影中の星の変位の角度を計算する必要があります。 単に持久力に基づいて計算するのはアイデアでしたが、これは最も正確ではないかもしれないことに気付きました。 そのため、 EXIF写真データから撮影時間を引き出します。

 Bitmap referencePic = new Bitmap(fileNames.First()); //loading first image byte[] timeTakenRaw = referencePic.GetPropertyItem(36867).Value; // EXIF DateTime taken string timeTaken = System.Text.Encoding.ASCII.GetString(timeTakenRaw, 0, timeTakenRaw.Length - 1); // array to string without last char (newline) DateTime referenceTime = DateTime.ParseExact(timeTaken, "yyyy:MM:d H:m:s", System.Globalization.CultureInfo.InvariantCulture); 


順番に。
残りのフレームのカウントを開始するには、撮影開始の瞬間を判断する必要があります。
写真をアップロードして、PropertyItem ID:36867-フレームが受信された日時を取得します。
文字の配列を文字列に変換します(最後の文字は\ nなので、除外します)。
撮影が始まった時間を手に入れました。

後続の各写真について、同じものを見つけ、時間差を使用して回転角度を計算します。
地球の完全な回転にかかる秒数を知っているため 、すべてが単純であると見なされます

 double secondsShift = (dateTimeTaken - referenceTime).TotalSeconds; double rotationAngle = secondsShift / stellarDay * 360; 


アフィン変換によって画像を回転させますが、このために回転行列を計算する必要があります。
幸いなことに、Emgu CVではこれはすべて私たちのために行われます。

 RotationMatrix2D<double> rotationMatrix = new RotationMatrix2D<double>(rotationCenter, -rotationAngle, 1); //change rotationAngle sign for CW/CCW 


マトリックスがあれば、現在の写真にアフィン変換を適用し、最初のモードのように追加できます。
 using (Image<Bgr, Byte> imageToRotate = new Image<Bgr, Byte>(currentPic)) { referenceImage = referenceImage.Max(imageToRotate.WarpAffine<double>(rotationMatrix, Emgu.CV.CvEnum.INTER.CV_INTER_CUBIC, Emgu.CV.CvEnum.WARP.CV_WARP_FILL_OUTLIERS, background)); } 


それだけです。 写真ごとに、これら2つの方法を実行し、何が起こったのかを確認します。

テスト


ソース画像:

27個

テスト1:スタック

すべての写真を1つにオーバーレイした結果。
画像

テスト2:回転とスタック

回転の中心と前方に注目しました。


2番目のテストでは、かなり奇妙な効果が得られました。
1.地球が汚れている-これは正常です。 スターを修正する必要があります。
2.中心の星はそれぞれの場所に残りました。つまり、すべてが正常に機能しました。
3.端の周りに「浮いている」星

なぜこれが起こったのですか? わからない! レンズの歪みのために、星の軌道は円ではなくなり、楕円になったと思います。

画像
露出〜43 '

この写真では、軌跡が理想的な円とは異なることが明確にわかります。これはすべて計算されたものです。

装備品

すべてがキヤノンEF-S 10-22mmでキヤノン7Dで撮影されました。 このレンズには、最適な光学パラメータ、つまり歪みがありません。 したがって、すべてがそれほどスムーズではなかったという事実を私が責めるのは彼です。 次回は、歪みを修正してもう一度テストしてみます。

晴天!

Githubリポジトリ

Source: https://habr.com/ru/post/J179541/


All Articles