Ketepatan waktu in-house dengan layanan cloud surveillance IPEYE

Baru-baru ini, sebuah tugas muncul setiap hari untuk membentuk selang waktu dengan sepasang kamera pengintai yang terhubung ke IPEYE. Jika Anda tertarik pada bagaimana seseorang dengan pengetahuan python minimal menangani ini, atau jika Anda ingin menunjukkan kesalahan saya kepada saya, selamat datang di ...

Intro


Ayah saya memutuskan untuk pindah dan membangun rumah di daerah lain. Dia meminta saya untuk membantu pengawasan video. Input data:

  • Tidak ada ruang teknis.
  • Peralatan bisa dicuri.
  • Butuh gambar yang berkualitas.
  • Kamera harus di luar ruangan.
  • Yang Anda butuhkan hanyalah 2 kamera.
  • Saya sangat ingin kamera PTZ dengan zoom.
  • Saya mau aplikasi mobile.

Setelah melihat harga di toko-toko untuk peralatan bermerek, diputuskan untuk membeli kamera PoE noname dengan semua roti di Ali. Kameranya cukup murah - sekitar 5 ribu per buah.

Saya tidak ingin menempatkan DVR di lokasi konstruksi, jadi diputuskan untuk menggunakan solusi cloud. Setelah kamera tiba, saya mencoba berteman dengan berbagai layanan sehingga semuanya bekerja, termasuk PTZ. Dari semua layanan yang saya coba, ternyata berteman dengan kamera China hanya dengan IPEYE.
Ini akan mengakhiri intro. Saya pikir sekarang akan menjadi jelas bagi semua orang mengapa percakapan akan tentang layanan ini.

Pengalaman dengan IPEYE


Layanan sebagai layanan. Segala sesuatu yang dijanjikan terpenuhi. Dukungan teknis menjawab pertanyaan. Poin kuncinya adalah Anda dapat menentukan tautan ke aliran rstp, memutar pengaturan PTZ dan semuanya akan berfungsi. Aplikasi seluler Android berfungsi. Dimungkinkan untuk membuat pengguna tamu untuk kamera mereka dan memberikan hak akses ke setiap kerabat. Antarmuka web di Vivaldi terkadang bermasalah, di Chrome, gangguan seperti itu kurang umum. Agak membosankan browsing arsip.
Arsip dari kamera dapat diunduh, tetapi hingga 3 jam. Prosedurnya cukup memakan waktu.

Segalanya tampak baik-baik saja, tetapi Anda merasakan dengan jiwa Anda bahwa ada sesuatu yang tidak beres. Dan kedalaman arsip tidak cukup. Anda dapat meningkatkan kedalaman, tetapi opsi yang paling mahal - 12 bulan akan menelan biaya 25 ribu rubel per tahun untuk satu kamera (saat merekam dengan deteksi).

Mari kita memikirkan sesuatu?


Itu adalah pertanyaan yang diajukan ayah saya. Ayah saya ingin menangkap semua tahapan konstruksi.
Apa sajakah pilihan untuk menyelesaikan masalah ini? Anda dapat pergi ke antarmuka web setiap hari dan mengekspor beberapa bagian video dari setiap kamera. Siapa yang akan melakukan tugas suram seperti itu? Tidak ada Beberapa kali sehari untuk membuka kamera siaran dan mengambil tangkapan layar? Yah, juga kegilaan. Tingkatkan kedalaman arsip hingga 1 tahun? Nah, solusi yang sangat murah. Google memberi tahu saya bahwa fungsi TimeLapse sudah dibangun di layanan ini, tetapi resolusinya rendah dan Anda tidak dapat mengunduhnya untuk arsip mendatang :(
UPD: Timelapse asli dapat diunduh. Untuk melakukan ini, buka selang waktu di antarmuka web. Menggunakan alat pengembang, periksa halaman web dan temukan tautan ke file kami. Format Tautan:
sr <server_number> .ipeye.ru / api / v1 / stream / <uuid> / nvr / timelapse / 0 / <unixtimestamp> /100/video.mjpeg

Diputuskan untuk menulis sesuatu untuk entah bagaimana menyimpan tangkapan layar dari kamera dan membentuk video akhir.

Penafian


Penulis karya ini bukan seorang programmer dan tidak berusaha untuk menjadi seorang programmer. OOP mengetahui dasar-dasarnya secara dangkal. Agile, dll. tidak dipelajari. Sebulan yang lalu, ia menonton kursus video pendek tentang python dan memutuskan untuk menggunakannya untuk menyelesaikan masalah saat ini.

API


Sangat menyenangkan menemukan bahwa layanan IPEYE adalah API yang tersedia untuk umum. API hanya menyediakan contoh untuk PHP, tetapi terbukti bermanfaat.

Berdasarkan fakta bahwa komputer saya tidak pernah dimatikan, konsep berikut ini dikembangkan:

  1. Penjadwal Windows menjalankan skrip setiap 30 menit.
  2. Script melalui API menentukan uuid kamera saya.
  3. Script melalui API menerima foto dari kamera dan menyimpannya ke direktori.
  4. Script sekali sehari menghasilkan file video untuk setiap kamera.
  5. Katalog dengan foto sumber dan video akhir diikat ke cloud dan dibagikan.
  6. Kerabat ketika mereka ingin menonton timelapse dan beroperasi pada file yang mereka inginkan.

Untuk bekerja dengan API, saya menulis beberapa fungsi: masuk dan menjalankan permintaan ke server API.

writeLog ()
def writeLog(logdata): if LogEnable == 1: log_time = datetime.now() log_time = log_time.isoformat(timespec='seconds') log_file = open(log_file_path, "a+") log_file.write(log_time + ": " + str(logdata) + "\n") log_file.close else: return True 


getApiResponse ()
 def getApiResponse(method, api_uri): if method == "GET": try: r = requests.get(api_url + api_uri, timeout = api_timeout) r.raise_for_status() #   HTTP    except requests.exceptions.Timeout: writeLog("Error. Timeout. Request Uri:" + api_uri) except requests.exceptions.TooManyRedirects: writeLog("Error. TooManyRedirects or bad URL. Request Uri:" + api_uri) except requests.exceptions.RequestException as e: writeLog("Error. Fatal error: " + str(e) + " Request Uri:" + api_uri) sys.exit(1) except requests.exceptions.HTTPError as e: writeLog("Error. HTTP error: " + str(e) + " Request Uri:" + api_uri) if method == "POST": try: r = requests.post(api_url + api_uri, timeout = api_timeout) r.raise_for_status() #   HTTP    except requests.exceptions.Timeout: writeLog("Error. Timeout. Request Uri:" + api_uri) except requests.exceptions.TooManyRedirects: writeLog("Error. TooManyRedirects or bad URL. Request Uri:" + api_uri) except requests.exceptions.RequestException as e: writeLog("Error. Fatal error: " + str(e) + " Request Uri:" + api_uri) sys.exit(1) except requests.exceptions.HTTPError as e: writeLog("Error. HTTP error: " + str(e) + " Request Uri:" + api_uri) return r 


Menurut API, kami memiliki kemampuan untuk mengakses / perangkat / semua dan mendapatkan info tentang semua utas. Saya langsung bingung bahwa otorisasi tidak diperlukan, jika Anda percaya dokumentasi API ... Ketika saya meminta / devices / all, saya mendapat kesalahan:
Kesalahan fatal: 401 Kesalahan Klien: Tidak sah untuk url: api.ipeye.ru : 8111 / devices / all
Saya memodifikasi fungsi getApiResponse saya untuk lulus kredensial saya, tetapi saya juga mendapat kesalahan 401. Saya tidak mencantumkan fungsinya, karena itu tidak berguna di masa depan.

Saya harus menghubungi dukungan teknis tentang ini. Tim dukungan menjelaskan bahwa untuk menggunakan API dengan otorisasi, Anda harus terlebih dahulu menyimpulkan perjanjian dengan IPEYE dan mengkonfigurasi server web Anda. Apa jenis server web dan mengapa mereka tidak menjelaskan kepada saya, tetapi pada saat yang sama mereka memberi petunjuk di mana mendapatkan kamera uuid dan mengakses API tanpa otorisasi.

Korespondensi dengan dukungan
Saya: Selamat sore. Apakah mungkin menggunakan API? Saya tidak menemukan kamera uuid di antarmuka web. Saya ingin mendapatkan daftar kamera saya ketika saya bertanya api.ipeye.ru : 8111 / devices / all kecuali tautan nama pengguna / kata sandi saya tidak berfungsi.

IPEYE: Sebagai login / kata sandi, data otorisasi dari pengguna API digunakan, kami menyediakan akses berdasarkan kontrak.

Dengan demikian, daftar kamera yang Anda lihat bukan untuk login Anda, tetapi untuk semua kamera API pengguna.

Saya: Berapa biaya untuk mengakses API dua kamera?

IPEYE: Semuanya lebih rumit di sana, Anda harus meluncurkan situs Anda dan menggunakan API kami untuk menambahkan kamera ke sana dan terus bekerja dengannya.
Apakah itu layak dilakukan demi 2 kamera?

Saya: Secara umum, untuk pemahaman, saya memerlukan akses ke API hanya untuk mengunduh tangkapan layar secara otomatis dari kamera. Untuk pembentukan selang waktu selanjutnya.

IPEYE: Dan apa yang tidak sesuai api.ipeye.ru/doc#AppDeviceJPEGOnline dalam kasus ini?

Saya: Dan di mana saya bisa menemukan UUID kamera saya?

IPEYE: Dari bilah alamat browser, misalnya. UUID yang sama muncul di "Kode untuk situs" sebagai parameter devcode.



Apa yang kita miliki dalam residu kering? Memang, kamera uuid dapat ditemukan di akun Anda, jika Anda melihat parameter GET. Ada metode / perangkat / jpeg / online /: uuid /: nama untuk mengambil tangkapan layar, ada uuid, dan kami sudah tahu nama kamera.

Saya membuat fungsi untuk menyimpan gambar dari aliran.

saveJpegFromStream ()
 def saveJpegFromStream(uuid, name): # api_uri = "/device/thumb/online/" + uuid + "/1920/" + name api_uri = "/device/jpeg/online/" + uuid + "/" + name writeLog("Trying save Stream screenshot for camera: " + name) response = getApiResponse("GET", api_uri) content_type = response.headers.get('content-type') if content_type is None: writeLog("Nothing to save") return False if 'text' in content_type.lower() or 'html' in content_type.lower(): writeLog("Received text data: " + response.content.decode("utf-8")) return False else: filename = dirToSave + "\\" + name + "-" + today.strftime("%Y-%m-%d-%H-%M-%S") + ".jpg" screenshot = open(filename, "wb") screenshot.write(response.content) screenshot.close() writeLog("File saved as: " + filename) return True 


Saya membuat permintaan dan mengerti bahwa ada sesuatu yang tidak beres ... Kami menerima file. Gambar dari kamera saya, tetapi ukurannya mencurigakan kecil - 66Kb. Saya melihat properti dan mengerti bahwa 608 * 342 sama sekali tidak 1920 * 1080. Ketika saya meminta / device / thumb / online / uuid / 1920 / name, saya mendapatkan file 1920 * 1080, tapi ini hanya file sebelumnya 608 * 342 yang direntangkan ke skala yang diperlukan. Tentu saja, keadaan ini tidak cocok untukku.

Juga selama percobaan, ditemukan bahwa parameter nama tidak dicentang atau digunakan dengan cara apa pun. Anda dapat mengirim apa pun yang Anda inginkan.

Setelah itu, saya menyimpulkan bahwa perintah / perangkat / url / rtsp / yang paling berguna adalah untuk mendapatkan tautan ke aliran RTSP. Saya harus beralih ke Google, karena Tidak ada pemahaman bagaimana bekerja dengan RTSP.

getStreamRTSP ()
 def getStreamRTSP(uuid, name): api_uri = "/device/url/rtsp/" + uuid writeLog("Trying get stream RTSP link for " + name + " " + uuid) response = json.loads(getApiResponse("GET", api_uri).text) writeLog("Stream RTSP link for " + name + ": " + str(response["message"])) return str(response["message"]) 


saveJpegFromRTSP
 def saveJpegFromRTSP(name, rtspLink): writeLog("Trying save RTSP screenshot for camera: " + name) rtspClient = cv2.VideoCapture(rtspLink) if rtspClient.isOpened(): _,frame = rtspClient.read() rtspClient.release() #       if _ and frame is not None: filename = dirToSave + "\\" + name + "-" + today.strftime("%Y-%m-%d-%H-%M-%S") + ".jpg" cv2.imwrite(filename, frame) writeLog("File saved as: " + filename) return True else: writeLog("Can't read RTSP stream") return False 


Setelah saya menulis beberapa fungsi di atas, saya menyadari bahwa tidak perlu menggunakan API sama sekali untuk tugas awal :) Saya memiliki tautan langsung ke aliran rtsp kamera, dan dengan fungsi terakhir saya dapat mengambil gambar dari kamera. Tetapi saya tidak mulai mengubah konsep pada langkah ini.

Saat bekerja melalui API, ada 2 keuntungan: server IPEYE menginisialisasi aliran jauh lebih cepat daripada kamera, dan aliran kamera rtsp dapat ditutup oleh firewall.

jpg2mp4


Langkah terakhir adalah menambahkan semua gambar dari satu kamera ke video. Saya memilih codec mp4v, karena MEGA memungkinkan Anda memutar file video ini dalam antarmuka web.

makeVideoFile ()
 def makeVideoFile(name): height = 1080 width = 1920 # video = cv2.VideoWriter(dirToSave + "\\Video" + name + ".avi", cv2.VideoWriter_fourcc(*'DIVX'), 1,(width,height)) video = cv2.VideoWriter(dirToSave + "\\Video" + name + ".mp4", cv2.VideoWriter_fourcc(*'mp4v'), 1,(width,height)) files = os.listdir(dirToSave) screenshots = list(filter(lambda x: x.startswith(name + "-"), files)) for screenshot in screenshots: origImage = cv2.imread(dirToSave + "\\" + screenshot) #  ,    ,      -   ...   #  ,        FullHD ?           API heightOrig, widthOrig, channelsOrig = origImage.shape if height != heightOrig or width != widthOrig: img = cv2.resize(origImage, (width, height)) video.write(img) else: video.write(origImage) cv2.destroyAllWindows() video.release() 


Untuk referensi: 45 file jpg dengan volume total 37,3 MB dalam format video menempati 16,9 MB.

Terima kasih telah membaca artikel publik pertama saya. Saya mencoba menggambarkan segala sesuatu dalam format cerita, dan tidak mudah dilakukan, karena saya tidak ingin mendapatkan artikel kering di jalan keluar.

Saya akan senang berkomentar, karena saya bertemu python kurang dari sebulan yang lalu.

Script lengkap dengan komentar tambahan dapat ditemukan di github . Selain itu, skrip mempertimbangkan perbedaan dalam zona waktu, dan semua fungsi yang tersisa ditulis untuk dengan cepat skala ke sejumlah kamera yang berbeda.

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


All Articles