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リポジトリ



All Articles