2017年8月14日

用定點攝影加上OpenCV看英仙座流星雨


2017英仙座流星雨疊圖

2017/8/12晚上有英仙座流星雨,不過我當天晚上沒看。隔天看資料的時候,看到它的輻射點似乎和我定點攝影拍的方位一致,心想自己持續架在窗邊的定點攝影機是不是有拍到。昨天就檢視那些影片,果然看到了一些流星還有火流星呢。

不過自己用眼睛看啊看,實在是很累的事情。因為是快轉看的,甚至還會因此而錯失某些路徑短的流星。所以就想應該來寫一個python script來自動搜夜空的流星才是。

分析流程如下:
1.把夜空畫面切出來轉成灰階
2.偵測畫面的灰階值是否有大於某個閾值,如果有代表天空有亮點
3.把偵測到亮點的畫面資料存出來,包括亮點的灰階值、位置、檔案名稱(代表時間),還有把具有亮點的影格也存出來。


最後用眼睛確認那個亮點到底是飛機還是流星,其實這個用程式也能判斷,就是看亮點的移動速度就可以。過程中還發生一個插曲,我的程式分析的影片到凌晨三點多就開始偵測到持續的亮點,以至於資料量爆增,事後去看,原來是那個時間點月亮出來了。


最後我再把影格用imagej處理,匯出影片還有疊圖。影片濃縮了七八個小時的流星片段,要許願就看這片就行了。疊圖(最上面的圖片)則是可以看出輻射點的位置,就在畫面上方。



 我想未來可以做一個「流星自動許願機」,就只要在程式裡輸入願望,然後把攝影機對準夜空,就可以去睡覺了,不用熬夜看流星。機器偵測到流星之後,就會自動語音播報願望,保證不會錯失流星,這樣真是太偉大了。 

以下就是流星雨的出現資料,打星號為明顯而持續的流星,可能是火流星。
2017/08/12 19:10:37
2017/08/12 20:28:52
2017/08/12 21:30:14
2017/08/12 21:38:19
2017/08/12 21:59:43
2017/08/12 22:06:33 *
2017/08/12 22:37:14
2017/08/12 23:08:32
2017/08/12 23:09:11
2017/08/13 00:12:54
2017/08/13 00:44:56 *
2017/08/13 01:05:42
2017/08/13 01:09:20 *
2017/08/13 01:34:5
2017/08/13 01:39:34
2017/08/13 01:40:24
2017/08/13 01:50:19
2017/08/13 01:50:40
2017/08/13 01:54:35
2017/08/13 02:35:11
2017/08/13 02:38:31 *
2017/08/13 02:46:35
2017/08/13 03:05:29
2017/08/13 03:10:16
2017/08/13 03:12:36










****以下為程式的部份***************************************
#!/usr/bin/env python
#-*- coding: utf-8 -*-
import numpy as np
import cv2
import os
import math
from collections import deque
from operator import itemgetter


def meterFinding(file,video_index):

    frameNum = 0
    cap = cv2.VideoCapture(file)

    #開始處理影格
    while(cap.isOpened()):
        #現在處理到哪個檔案
        print(videofiles[video_index])
        ret, frame = cap.read()


        #獲知每秒多少影格frame per second
        fps = cap.get(cv2.CAP_PROP_FPS)
       
        #影格播完了,就播放下一個,直到video_index到達影片檔案的數量,就停止
        if frame is None:

            video_index += 1
            if video_index >= len(videofiles):
                break
            cap = cv2.VideoCapture(videofiles[ video_index ])
            ret, frame = cap.read()
            frameNum=0
        #把天空從影格中裁切出來[y1:y2,x1,x2]
        sky=frame[0:202,271:1270]

        #天空轉換成灰階
        gray_sky = cv2.cvtColor(sky, cv2.COLOR_BGR2GRAY)



        #找黑天空上的最大灰階值
        max_value = max(max(l) for l in gray_sky)
        #print(max_value)





        #如果最大灰階值大於120,代表有流星,就把檔案路徑印出
        if max_value >120:
            print(videofiles[video_index])

            with open("output.txt", "a") as text_file:

                #輸出檔案名稱
                text_file.write(videofiles[video_index])
                text_file.write("\t")

                #輸出秒數
                text_file.write(str(int(frameNum/fps)))
                text_file.write("\t")

                #輸出最大值
                text_file.write(str(max_value))
                text_file.write("\t")

                #輸出流星的位置
                ar = np.array(gray_sky)
                max_index = np.where(ar == max_value)



                #y的位置
                text_file.write(str(max_index[0]))

                text_file.write("\t")

                #X的位置(越大,越靠右,500多在山邊,900多就是在山上)
                text_file.write(str(max_index[1]))



                text_file.write("\n")


                #把畫面存起來

                pngName = videofiles[video_index]
                pngName = pngName.lstrip("/home/pancala/Desktop/video/test/")
                pngName = pngName.rstrip(".mp4")
                pngName = pngName.replace('/', '')
                pngName = pngName + "_" + str(int(frameNum/fps)) + "_" + str(frameNum)
                pngName = pngName + ".png"
               
                cv2.imwrite(pngName,frame)

        #if max(gray_sky,key=itemgetter(1))[0] >30:
            #print(max(gray_sky,key=itemgetter(1))[0])

        #呈現夜空
        #cv2.imshow('sky',gray_sky)

        frameNum = frameNum +1
        #調整waitkey 控制播放速度
        k = cv2.waitKey(5) & 0xff
        if k == 27:
            break



    cap.release()
    cv2.destroyAllWindows()


video_index = 0
videofiles = []
for dirPath, dirNames, fileNames in sorted(os.walk("/home/pancala/Desktop/video/test")):
    for f in sorted(fileNames):
        inputFile=os.path.join(dirPath, f)
        lastFile=os.path.splitext(f)[-1]
        if lastFile==".mp4":
            #file='output.mp4'
            #把檔案路徑都放進videofiles的list
            videofiles.append(inputFile)

#videofiles = [n for n in os.listdir('.') if n[0]=='c' and n[-4:]=='.mp4']
#videofiles = sorted(videofiles, key=lambda item: int( item.partition('.')[0][3:]))

meterFinding(videofiles[0],video_index)