Prediktera Data Server
Overview:
The Prediktera Data Server receives frames in ENVI BIL format over TCP/IP in real-time. The received frames are processed using a user-defined Analysis Tree, and the prediction results are sent back through the TCP/IP data stream or event port. See Developers reference guide
See Developer reference guide | Prediktera Data Server for integrated setup of data streaming server.
Communication:
TCP/IP Ports: The server listens on the specified port for incoming data.
Data Format: Frames must be in ENVI BIL format for correct processing. The format should align with the expected Breeze Runtime workflow, e.g.,
Float32
reflectance with a maximum signal of 1.
Python code to read an ENVI BIL file in Float32
and send it frame by frame to the Prediktera Data Server over TCP/IP. Each frame is prepended with its frame number.
Configuration
Type
Server
Streaming data from TCP server.
Port
Specify the streaming port.
Width
Frame width in pixels.
Height
Number of bands.
Max signal
The expected maximum signal value:1
for adjusted raw images (e.g., reflectance), or the maximum value for raw data.
Data size
Byte: 1 byte
Short: 2 bytes
Float: 4 bytes
Double: 8 bytes
The expected size of each data value.
Wavelength
The wavelength names, usually in nanometers, as a semicolon-separated list, or read from a header file.
Example from nuts tutorial data:
1164.52;1209.84;1255.04;1300.16;1345.2;1390.17;1435.09;1479.97;1524.81;1569.64;1614.45;1659.25;1704.05;1748.85;1793.66;1838.47;1883.3;1928.12;1972.95;2017.79;2062.62;2107.45;2152.26;2197.05;2241.81;2286.53;2331.2;2375.81;2420.34;2464.78;2509.12
Frame format
[ Frame Number (4 bytes) ][ BIL Data (Width x Height x Data Size) ]
Frame Number
Type:
UInt32
Endianness: Big-endian
Size: 4 bytes
BIL Data
Format:
Float32
for adjusted raw data (e.g., reflectance, absorption)Otherwise, raw data size based on configuration
Size:
Width x Height x Data Size
bytes
Ensure the corresponding value is set in Breeze.
Example code sending frames to Breeze
import socket
import time
import struct
import keyboard
import numpy as np
# Configuration
server_ip = '127.0.0.1' # Replace with the actual IP of the Prediktera Data Server
server_port = 2200 # Replace with the actual port for receiving data
envi_file_path = 'path to file' # Path to your ENVI BIL file
frame_width = 384 # Width of each frame in pixels
frame_height = 31 # Height of each frame in wavelengths
frame_rate = 100 # Desired frame rate in frames per second (fps)
frame_number = 1
# Function to read ENVI BIL data from disk
def read_envi_bil(filepath, width, height):
with open(filepath, 'rb') as f:
# Read the entire file into a numpy array
data = np.fromfile(f, dtype=np.float32)
# data = np.fromfile(f, dtype=np.uint16) # For standard short raw data
# Reshape the data to (frame_height, frame_width)
frames = data.reshape((-1, height, width))
return frames
# Function to send frame data to Prediktera Data Server
def send_frame(frame, connection):
global frame_number
# Flatten the frame to a 1D array
flat_frame = frame.flatten()
# Convert the frame data to bytes
frame_bytes = flat_frame.tobytes()
# Convert frame number to big endian UInt32
frame_number_bytes = struct.pack('!I', frame_number)
frame_number += 1
# Send the frame number followed by the frame data over TCP
connection.sendall(frame_number_bytes + frame_bytes)
# Main function to read and send ENVI BIL data
def main():
# Read ENVI BIL data
frames = read_envi_bil(envi_file_path, frame_width, frame_height)
# Calculate the time delay between frames
frame_delay = 1.0 / frame_rate
# Establish a connection to the Prediktera Data Server
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((server_ip, server_port))
# Loop to continuously send frames until q key is pressed
while not keyboard.is_pressed('q'):
for i, frame in enumerate(frames):
start_time = time.time()
send_frame(frame, s)
# Ensure the frame rate by waiting before sending the next frame
elapsed_time = time.time() - start_time
time_to_wait = frame_delay - elapsed_time
if time_to_wait > 0:
time.sleep(time_to_wait)
if keyboard.is_pressed('q'):
break
if __name__ == "__main__":
main()
Follow this article for additional information on device configuration: Hardware and settings guide