Укладка астрономических изображений с помощью Python - PullRequest
17 голосов
/ 12 февраля 2012

Я думал, что это будет легче, но через некоторое время я наконец отказываюсь от этого, по крайней мере, на пару часов ...

Я хотел воспроизвести это изображение в виде звездочек из набора фотографий с интервальной съемкой. Вдохновленный этим: Inspiration

Оригинальный автор использовал видеокадры с низким разрешением, снятые с помощью VirtualDub и объединенные с imageJ. Я подумал, что мог бы легко воспроизвести этот процесс, но с более внимательным подходом к памяти с Python, поэтому я мог бы использовать исходные изображения с высоким разрешением для лучшего вывода.

Идея моего алгоритма проста: объединять два изображения за раз, а затем повторять, объединяя полученное изображение со следующим. Это сделано несколько сотен раз и правильно взвешено, чтобы каждое изображение имело одинаковый вклад в конечный результат.

Я довольно новичок в python (и я не профессиональный программист, это будет очевидно), но, глядя на него, мне кажется, что Python Imaging Library очень стандартна, поэтому я решил ее использовать (поправьте меня если вы думаете, что-то еще будет лучше).

Вот что у меня есть:

#program to blend many images into one
import os,Image
files = os.listdir("./")
finalimage=Image.open("./"+files[0]) #add the first image
for i in range(1,len(files)): #note that this will skip files[0] but go all the way to the last file
  currentimage=Image.open("./"+files[i])
  finalimage=Image.blend(finalimage,currentimage,1/float(i+1))#alpha is 1/i+1 so when the image is a combination of i images any adition only contributes 1/i+1.
  print "\r" + str(i+1) + "/" + str(len(files)) #lousy progress indicator
finalimage.save("allblended.jpg","JPEG")

Это делает то, что должно, но получающееся изображение темное, и если я просто попытаюсь улучшить его, очевидно, что информация была потеряна из-за недостаточной глубины значений пикселей. (Я не уверен, что правильный термин здесь, глубина цвета, точность цвета, размер пикселя). Вот конечный результат с использованием изображений с низким разрешением:

Low resolution result

или один, который я пробовал с полным разрешением 4k на 2k (из другого набора фотографий):

High resolution result with another set of images

Итак, я попытался это исправить, установив режим изображения:

firstimage=Image.open("./"+files[0])
size = firstimage.size
finalimage=Image.new("I",size)

но, видимо, Image.blend не принимает этот режим изображения.

ValueError: изображение имеет неправильный режим

Есть идеи?

(я также пытался сделать изображения «менее темными», умножив их, прежде чем объединить их с im.point (лямбда i: i * 2), но результаты были такими же плохими)

1 Ответ

20 голосов
/ 13 февраля 2012

Проблема в том, что вы усредняете яркость каждого пикселя.Это может показаться разумным, но на самом деле это совсем не то, что вам нужно - яркие звезды будут «усредняться», потому что они движутся по всему изображению.Возьмите следующие четыре кадра:

1000 0000 0000 0000
0000 0100 0000 0000
0000 0000 0010 0000
0000 0000 0000 0001

Если вы усредните их, вы получите:

0.25 0    0    0
0    0.25 0    0
0    0    0.25 0
0    0    0    0.25

Когда вы хотите:

1000
0100
0010
0001

Вместо смешиванияИзображения, которые вы можете попытаться получить максимально видимыми на любом изображении для каждого пикселя.Если у вас есть PIL, вы можете попробовать более легкую функцию в ImageChops.

from PIL import ImageChops
import os, Image
files = os.listdir("./")
finalimage=Image.open("./"+files[0])
for i in range(1,len(files)):
    currentimage=Image.open("./"+files[i])
    finalimage=ImageChops.lighter(finalimage, currentimage)
finalimage.save("allblended.jpg","JPEG")

Вот что я получил: Low res image set stacked

РЕДАКТИРОВАТЬ: Я прочитал пост Redditи увидите, что он на самом деле объединил два подхода - один для звездных троп, а другой для Земли.Вот лучшая реализация усреднения, которое вы пробовали, с правильным взвешиванием.Я использовал массив numpy для промежуточного хранилища вместо массива изображений uint8.

import os, Image
import numpy as np
files = os.listdir("./")
image=Image.open("./"+files[0])
im=np.array(image,dtype=np.float32)
for i in range(1,len(files)):
    currentimage=Image.open("./"+files[i])
    im += np.array(currentimage, dtype=np.float32)
im /= len(files) * 0.25 # lowered brightness, with magic factor
# clip, convert back to uint8:
final_image = Image.fromarray(np.uint8(im.clip(0,255)))
final_image.save('all_averaged.jpg', 'JPEG')

Вот изображение, которое вы можете затем объединить со звездными следами из предыдущего.Low res images added together

...