Ketika kami menulis aplikasi di NASA Space Apps Challenge hackathon

Pada 20-21 Oktober, NASA Space Apps Challenge hackathon internasional diadakan di Moskow. Penyelenggaranya di Rusia adalah orang-orang dari komunitas Rusia . Sebagai bagian dari acara tersebut, para peserta diminta untuk menyelesaikan 20 kasus tentang berbagai topik: mulai dari pembuatan film tentang hackathon hingga mengembangkan aplikasi pemantauan dan merancang pesawat terbang otonom. Daftar lengkap topik dapat dipelajari dengan referensi atau dalam artikel tentang HabrΓ© .

Tim kami "Space Monkeys", yang termasuk Oleg Borodin (Pengembang front-end di laboratorium Singularis), Vladislav Plotnikov (insinyur QA di laboratorium Singularis), Yegor Shvetsov, Dmitry Petrov, Yuri Bederov dan Nikolai Denisenko, memutuskan untuk menyelesaikan masalah di bawah kondisi yang menarik. berjudul β€œSpot that fire!”, yang diucapkan sebagai berikut: β€œ Terapkan crowdsourcing sehingga orang dapat berkontribusi untuk deteksi, konfirmasi, dan pelacakan kebakaran hutan. Solusinya bisa berupa aplikasi seluler atau web. ”

Karena fakta bahwa tim mengumpulkan 5 pengembang dengan pengalaman dalam mengembangkan untuk berbagai platform, segera diputuskan bahwa prototipe aplikasi kami akan diimplementasikan untuk platform Web dan Mobile.

Data NASA apa yang kami gunakan?


Tetap saja, hackathon diadakan di bawah naungan Badan Penerbangan dan Antariksa Nasional, sehingga tidak benar untuk tidak menggunakan data terbuka dari dapur NASA. Selain itu, kami segera menemukan dataset Data Api Aktif yang kami butuhkan. Dataset ini berisi informasi tentang koordinat kebakaran di seluruh dunia (Anda dapat mengunduh informasi di benua tertentu). Data diperbarui setiap hari (Anda dapat menerima data selama 24 jam, 48 jam, 7 hari).


File tersebut berisi informasi tentang bidang-bidang berikut: lintang, bujur, kecerahan, pindai, lacak, acq_date, acq_time, satelit, kepercayaan diri, versi, bright_t31, frp, daynight, di mana kami hanya menggunakan koordinat titik api (lintang dan bujur).


Prinsip aplikasi


Karena aplikasi ini adalah crowdsourced, idealnya itu harus digunakan oleh sejumlah besar pengguna. Prinsip aplikasi adalah sebagai berikut:


  1. Pengguna, setelah mendeteksi kebakaran, memotretnya (dengan penandaan geografis) dan memuatnya menggunakan layanan. Foto dengan tag geo dan koordinat pengiriman ke server aplikasi. Fotografi dapat diunduh dari versi aplikasi Web atau Mobile.

  2. Foto yang dihasilkan diproses di server oleh jaringan saraf terlatih untuk mengkonfirmasi bahwa foto tersebut benar-benar terbakar. Hasil skrip adalah akurasi prediksi, jika> 0,7, maka foto benar-benar menyala. Kalau tidak, kami tidak merekam informasi ini dan meminta pengguna untuk mengunggah foto lain.

  3. Jika skrip analisis gambar memberikan hasil positif, maka koordinat dari geotag ditambahkan ke dataset dengan semua koordinat. Selanjutnya, jarak antara titik ke-1 dari dataset NASA dan titik dari pengguna dihitung. Jika jarak antara titik adalah ≀ 3 km, maka titik dari set NASA ditambahkan ke kamus. Jadi kita membahas semua poin. Setelah itu, kembalikan json dengan koordinat yang memenuhi kondisi ke sisi klien aplikasi. Jika tidak ada koordinat yang ditemukan oleh kondisi yang diberikan, maka kami mengembalikan satu-satunya titik yang kami terima dari pengguna.

  4. Jika server mengembalikan array poin, maka bagian klien dari aplikasi menggambar zona api di peta. Jika server mengembalikan satu titik, itu ditandai pada peta dengan label khusus.


Tumpukan teknologi yang digunakan


Bagian ujung depan aplikasi web


Aplikasi web, dapat diakses dari browser, fokus pada layar komputer, dan tidak adaptif, namun, teknologi yang digunakan dengan mudah memungkinkan untuk memperbaiki aspek ini untuk perangkat seluler. Kami menggunakan tumpukan teknologi berikut di sisi web:



Skenario kerja


Pengguna membuka aplikasi dan melihat lokasinya:




Inisialisasi peta dan geo pengguna:


this.map = L.map('map').setView([latitude, longitude], 17); L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '& copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' }).addTo(this.map); L.circle([latitude, longitude]).addTo(this.map) .bindPopup('You are here') .openPopup(); 

Jika ada api di jari-jari n (variabel ubahsuaian) kilometer, maka akan ditampilkan dalam bentuk poligon dengan ringkasan informasi tambahan:




Pengguna memilih lokasi api di peta:




Pengaturan tag api:


 let marker; this.map.on('click', function (e) { if (marker) { self.map.removeLayer(marker); } marker = L.circle([e.latlng.lat, e.latlng.lng], { color: 'red', fillColor: '#f03', fillOpacity: 0.5, radius: 15 }).addTo(self.map) .bindPopup(' ') .openPopup(); self.appService.coordinatesStorage.latitude = e.latlng.lat; self.appService.coordinatesStorage.longitude = e.latlng.lng; console.log('fire', self.appService.coordinatesStorage); }); 

Selanjutnya, pengguna mengunggah foto api menggunakan ng2-file-upload .


Sebagai hasil dari tindakan ini, data berikut ditransfer ke server:


  • koordinat pengguna
  • koordinat api yang ditentukan
  • foto api

Output dari aplikasi adalah hasil pengakuan.



Aplikasi aplikasi seluler


Teknologi yang digunakan


  • Bereaksi asli - kerangka kerja untuk mengembangkan aplikasi lintas platform untuk iOS dan Android
  • Redux - aplikasi kontrol aliran data
  • Redux-saga - perpustakaan menggunakan efek samping di Redux

Skenario kerja


Pilih foto api


Komentar dari pengguna


Tanda api



Bagian belakang aplikasi


  • Bahasa Pemrograman - JAVA 8

  • Platform Cloud - Microsoft Azure

  • Kerangka kerja aplikasi web - Kerangka Mainkan

  • Pemetaan objek-relasional - Kerangka Ebean


Server memiliki 2 skrip yang ditulis dalam Python: predict.py dan getZone.py, pustaka Python berikut diinstal untuk pekerjaan mereka:


  • panda - untuk pemrosesan dan analisis data
  • geopanda - untuk bekerja dengan geodata
  • numpy - untuk bekerja dengan array multidimensi
  • matplotlib - untuk visualisasi data grafik dua dimensi (2D) (grafik 3D juga didukung)
  • rupawan - untuk manipulasi dan analisis objek geometri datar.

API Server: fire.iconx.app/api


  • memuat koordinat

 post /pictures {} return { id } 

  • unggah gambar

 post /pictures/:id 

Script predict.py


Sebuah skrip input menerima gambar, sebuah preprocessing gambar sederhana terjadi (lebih lanjut tentang ini di bagian "Model Training") dan berdasarkan pada file yang disimpan dengan bobot, yang juga terletak di server, sebuah prediksi dikeluarkan. Jika model menghasilkan akurasi> 0,7, maka api tetap, jika tidak - tidak.


Script dijalankan dengan cara klasik.

 $ python predict.py image.jpg 

Daftar kode:
 import keras import sys from keras.layers import Dense from keras.models import model_from_json from sklearn.externals import joblib from PIL import Image import numpy as np from keras import models, layers, optimizers from keras.applications import MobileNet from keras.models import Sequential from keras.layers import Dense, Dropout, Flatten from keras.layers import Conv2D, MaxPooling2D def crop_resize(img_path, img_size_square): # Get dimensions mysize = img_size_square image = Image.open(img_path) width, height = image.size # resize if (width and height) >= img_size_square: if width > height: wpercent = (mysize/float(image.size[1])) vsize = int((float(image.size[0])*float(wpercent))) image = image.resize((vsize, mysize), Image.ANTIALIAS) else: wpercent = (mysize/float(image.size[0])) hsize = int((float(image.size[1])*float(wpercent))) image = image.resize((mysize, hsize), Image.ANTIALIAS) # crop width, height = image.size left = (width - mysize)/2 top = (height - mysize)/2 right = (width + mysize)/2 bottom = (height + mysize)/2 image=image.crop((left, top, right, bottom)) return image conv_base = MobileNet(weights='imagenet', include_top=False, input_shape=(224, 224, 3)) def build_model(): model = models.Sequential() model.add(conv_base) model.add(layers.Flatten()) model.add(layers.Dense(256, activation='relu')) model.add(layers.Dense(64, activation='relu')) model.add(layers.Dense(1, activation='sigmoid')) model.compile(loss='binary_crossentropy', optimizer=optimizers.RMSprop(lr=2e-5), metrics=['acc']) return model image=crop_resize(sys.argv[1],224) image = np.reshape(image,[1,224,224,3]) #Loading models and text processing model = build_model() print('building a model') model.load_weights('./models/mobile_weights.h5') print('model loaded') pred_cat=model.predict(image) if pred_cat > 0.7: print('fire {}'.format(pred_cat)) else: print('no fire {}'.format(pred_cat)) 



Script getZone.py


Input ke skrip adalah koordinat titik yang berasal dari sisi klien dari aplikasi. Script mempererat semua koordinat dari NASA, menambahkan lintang dan bujur baru ke file ini, menimpa file asli dan mulai mencari titik terdekat. Jarak antar titik dihitung menggunakan rumus Haversine .


Untuk melakukan ini, garis lintang dan bujur titik dikonversi ke radian:


 pt1_lon, pt1_lat, pt2_lon, pt2_lat = map(radians, [pt1_lon, pt1_lat, pt2_lon, pt2_lat]) 

Ada perbedaan antara garis lintang dan garis bujur untuk masing-masing titik:


 d_lon = pt2_lon - pt1_lon d_lat = pt2_lat - pt1_lat 

Semua ini disubstitusi ke dalam formula haversine:


 a = sin(d_lat/2)**2 + cos(pt1_lat) * cos(pt2_lat) * sin(d_lon/2)**2 

Kami mengambil akar dari hasil perhitungan, menghitung arcsine dan mengalikan hasilnya dengan 2.


 c = 2 * asin(sqrt(a)) 

Jaraknya akan menjadi produk jari-jari Bumi (6371 km) dan hasil perhitungan sebelumnya.


Pelatihan model


Untuk menganalisis gambar untuk api, kami membutuhkan satu set pelatihan foto dengan api. Foto dikumpulkan oleh skrip dari situs https://www.flickr.com/ dan ditandai secara manual.


Pengunduhan dilakukan menggunakan FlikerAPI. Script melakukan operasi preprocessing standar dengan gambar: cropping - square dengan centering (rasio 1: 1), dan mengubah ukuran ke format 256 Γ— 256.


Daftar kode:
 import flickrapi import urllib.request from PIL import Image import pathlib import os from tqdm import tqdm # Flickr api access key flickr=flickrapi.FlickrAPI('your API key', 'your secret key', cache=True) def get_links(): search_term = input("Input keywords for images: ") keyword = search_term max_pics=2000 photos = flickr.walk(text=keyword, tag_mode='all', tags=keyword, extras='url_c', per_page=500, # mb you can try different numbers.. sort='relevance') urls = [] for i, photo in enumerate(photos): url = photo.get('url_c') if url is not None: urls.append(url) if i > max_pics: break num_of_pics=len(urls) print('total urls:',len(urls)) # print number of images available for a keywords return urls, keyword, num_of_pics #resizing and cropping output images will be besquare def crop_resize(img_path, img_size_square): # Get dimensions mysize = img_size_square image = Image.open(img_path) width, height = image.size # resize if (width and height) >= img_size_square: if width > height: wpercent = (mysize/float(image.size[1])) vsize = int((float(image.size[0])*float(wpercent))) image = image.resize((vsize, mysize), Image.ANTIALIAS) else: wpercent = (mysize/float(image.size[0])) hsize = int((float(image.size[1])*float(wpercent))) image = image.resize((mysize, hsize), Image.ANTIALIAS) # crop width, height = image.size left = (width - mysize)/2 top = (height - mysize)/2 right = (width + mysize)/2 bottom = (height + mysize)/2 image=image.crop((left, top, right, bottom)) return image def download_images(urls_,keyword_, num_of_pics_): num_of_pics=num_of_pics_ keyword=keyword_ urls=urls_ i=0 base_path='./flickr_data/' # your base folder to save pics for item in tqdm(urls): name=''.join([keyword,'_',str(i),'.jpg']) i+=1 keyword_=''.join([keyword,'_',str(num_of_pics)]) dir_path= os.path.join(base_path,keyword_) file_path=os.path.join(dir_path,name) pathlib.Path(dir_path).mkdir(parents=True, exist_ok=True) urllib.request.urlretrieve(item, file_path) resized_img=crop_resize(file_path, 256) #set output image size try: resized_img.save(file_path) except: pass urls, keyword, num_of_pics =get_links() continue = input("continue or try other keywords (y,n): ") if continue =='y': download_images(urls, keyword, num_of_pics) elif continue =='n': get_links() else: pass 


Secara alami, arsitektur konvolusional dari jaringan saraf, di mana model pra-dilatih digunakan, digunakan untuk bekerja dengan gambar. Pilihan jatuh pada (diharapkan) di MobileNet , karena:


  • Ringan - Penting agar waktu respons aplikasi minimal.
  • Cepat - Penting agar waktu respons aplikasi minimal.
  • Tepat - MobileNet memprediksi dengan akurasi yang diperlukan.

Setelah pelatihan, jaringan menghasilkan akurasi ~ 0,85.


Untuk membangun model, pelatihan dan prediksi, sekelompok Keras + Tensorflow digunakan . Pekerjaan dengan data dilakukan melalui Panda .


Karena NASA DataSet adalah data geografis, kami ingin menggunakan perpustakaan GeoPandas . Perpustakaan ini adalah perpanjangan dari kemampuan Pandas untuk menyediakan metode spasial dan operasi pada tipe geometris. Operasi geometrik diimplementasikan melalui pustaka bentuk, bekerja dengan file - fiona, grafik - matplotlib.


Setelah menghabiskan hampir satu setengah hari mencoba mencari tahu perpustakaan ini, kami meninggalkannya karena kami tidak dapat menemukan di mana perpustakaan itu dapat memberi kami keuntungan nyata dari bekerja dengannya. Tugas kami menghitung koordinat sangat kecil, jadi pada akhirnya, semuanya dilaksanakan secara asli.


Apa selanjutnya


Secara alami, semua yang kami dapatkan adalah aplikasi yang sangat tidak stabil dan kasar, yang memiliki hak untuk diselesaikan.


Kami telah berhasil:


  1. Terapkan prototipe aplikasi seluler dan Web yang dapat mengambil foto (hanya versi seluler), unggah, dan kirim ke server. Juga, koordinat pengiriman berhasil datang ke server.
  2. Di server, dimungkinkan untuk menggunakan 2 skrip yang mengimplementasikan logika utama aplikasi. Alur data input ke skrip ini dan penerimaan data output dengan pengiriman berikutnya ke bagian klien diatur.
  3. Terapkan "prototipe" nyata dari aplikasi kita.

Kami tidak berhasil mengimplementasikannya, tetapi saya ingin menyelesaikan masalah berikut dan menambahkan fitur (item sesuai dengan prioritas tugas):


  1. Atur rekaman semua koordinat dari dataset ke database untuk berinteraksi langsung dengan database.
  2. Kelola unggahan otomatis file baru dari situs web NASA, mis. mengatur pembaruan koordinat harian otomatis.
  3. Tambahkan notifikasi kepada pengguna yang berada di area dekat api.
  4. Tambahkan registrasi (diperlukan untuk mengimplementasikan paragraf pertama).
  5. Tulis ulang algoritma perhitungan zona api.
  6. Selesaikan tugas desain - menghadirkan keindahan ke versi seluler dan web aplikasi.

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


All Articles