def parse_clip(self, clip, process_background=False):
        """
        Loads a cptv file, and prepares for track extraction.
        """
        self.tracking_time = None
        start = time.time()
        clip.set_frame_buffer(
            self.high_quality_optical_flow,
            self.cache_to_disk,
            self.use_opt_flow,
            self.keep_frames,
        )

        with open(clip.source_file, "rb") as f:
            reader = CPTVReader(f)
            clip.set_res(reader.x_resolution, reader.y_resolution)
            if clip.from_metadata:
                for track in clip.tracks:
                    track.crop_regions()
            camera_model = None
            if reader.model:
                camera_model = reader.model.decode()
            clip.set_model(camera_model)

            # if we have the triggered motion threshold should use that
            # maybe even override dynamic threshold with this value
            if reader.motion_config:
                motion = yaml.safe_load(reader.motion_config)
                temp_thresh = motion.get("triggeredthresh")
                if temp_thresh:
                    clip.temp_thresh = temp_thresh

            video_start_time = reader.timestamp.astimezone(Clip.local_tz)
            clip.set_video_stats(video_start_time)
            clip.calculate_background(reader)

        with open(clip.source_file, "rb") as f:
            reader = CPTVReader(f)
            for frame in reader:
                if not process_background and frame.background_frame:
                    continue
                self.process_frame(clip, frame.pix, is_affected_by_ffc(frame))

        if not clip.from_metadata:
            self.apply_track_filtering(clip)

        if self.calc_stats:
            clip.stats.completed(clip.current_frame, clip.res_y, clip.res_x)
        self.tracking_time = time.time() - start
        return True
예제 #2
0
def main():
    args = parse_args()
    init_logging()

    config = Config.load_from_file(args.config_file)
    thermal_config = ThermalConfig.load_from_file(args.thermal_config_file)
    print("detecting on  " + args.cptv)
    with open(args.cptv, "rb") as f:
        reader = CPTVReader(f)

        headers = HeaderInfo(
            res_x=reader.x_resolution,
            res_y=reader.y_resolution,
            fps=9,
            brand="",
            model="",
            frame_size=reader.x_resolution * reader.y_resolution * 2,
            pixel_bits=16,
        )

        motion_detector = MotionDetector(
            thermal_config, config.tracking.motion_config.dynamic_thresh, None,
            headers)
        for i, frame in enumerate(reader):
            motion_detector.process_frame(frame)
예제 #3
0
def test_round_trip_header_defaults():
    buf = BytesIO()

    w = CPTVWriter(buf)
    w.write_header()
    w.close()

    buf.seek(0, 0)

    r = CPTVReader(buf)
    assert r.version == 2
    assert r.x_resolution == 160
    assert r.y_resolution == 120
    assert not r.device_name
    assert not r.device_id
    assert (datetime.now(tz=timezone.utc) - r.timestamp) < timedelta(minutes=1)
    assert r.latitude == 0
    assert r.longitude == 0

    assert r.accuracy == 0
    assert r.altitude == 0
    assert r.fps == 0
    assert r.model is None
    assert r.brand is None
    assert r.firmware is None
    assert r.camera_serial == 0
    assert r.background_frames == 0
예제 #4
0
def test_round_trip_header():
    buf = BytesIO()

    w = CPTVWriter(buf)
    w.timestamp = datetime(2018, 7, 6, 5, 4, 3, tzinfo=timezone.utc)
    w.device_name = b"hello"
    w.device_id = 42
    w.latitude = 142.3
    w.longitude = -39.2
    w.loc_timestamp = datetime(2018, 9, 6, 5, 4, 3, tzinfo=timezone.utc)

    w.preview_secs = 3
    w.motion_config = b"blob"
    w.accuracy = 20
    w.altitude = 200
    w.fps = 30
    w.model = b"ultra"
    w.brand = b"laser"
    w.firmware = b"killer"
    w.camera_serial = 221
    back_frame = random_frame(60, 30)
    back_frame.background_frame = True
    w.background_frame = back_frame
    w.write_header()
    for i in range(10):
        frame = random_frame(60, 30)
        w.write_frame(frame)
    w.close()

    buf.seek(0, 0)

    r = CPTVReader(buf)
    assert r.version == 2
    assert r.x_resolution == 160
    assert r.y_resolution == 120
    assert r.timestamp == w.timestamp
    assert r.device_name == w.device_name
    assert r.device_id == w.device_id
    assert r.latitude == approx(w.latitude, 0.000001)
    assert r.longitude == approx(w.longitude, 0.000001)
    assert r.loc_timestamp == w.loc_timestamp
    assert r.preview_secs == w.preview_secs
    assert r.motion_config == w.motion_config

    assert r.accuracy == w.accuracy
    assert r.altitude == w.altitude
    assert r.fps == w.fps
    assert r.model == w.model
    assert r.brand == w.brand
    assert r.firmware == w.firmware
    assert r.camera_serial == w.camera_serial
    assert r.background_frames == 1
    count = 0
    for frame in r:
        if count == 0:
            assert frame.background_frame
        else:
            assert frame.background_frame == False
        count += 1
    assert count == 11
예제 #5
0
def test_read_v2():
    filename = str(data_dir / "v2.cptv")
    with open(filename, "rb") as f:
        r = CPTVReader(f)
        assert r.version == 2
        assert r.device_id == 44
        assert r.device_name == b"nz99"
        assert r.timestamp == datetime(2018, 9, 6, 9, 21, 25, 774768,
                                       timezone.utc)
        assert r.x_resolution == 160
        assert r.y_resolution == 120
        assert r.preview_secs == 1
        assert r.motion_config == b"motion"
        assert r.latitude == 0
        assert r.longitude == 0
        assert r.loc_timestamp == 0

        assert r.altitude == 0
        assert r.fps == 0
        assert r.model is None
        assert r.brand is None
        assert r.firmware is None
        assert r.camera_serial == 0

        count = 0
        for frame in r:
            count += 1
            assert frame.time_on is not None
            assert frame.last_ffc_time is not None
            assert frame.pix.min() > 2500
            assert frame.pix.max() < 3200
        assert count == 100
예제 #6
0
def test_lat_lon():
    filename = str(data_dir / "v2-latlon.cptv")
    with open(filename, "rb") as f:
        r = CPTVReader(f)
        assert r.version == 2
        assert r.latitude == approx(-36.943634)
        assert r.longitude == approx(174.661544)
예제 #7
0
def test_round_trip_header():
    buf = BytesIO()

    w = CPTVWriter(buf)
    w.timestamp = datetime(2018, 7, 6, 5, 4, 3, tzinfo=timezone.utc)
    w.device_name = b"hello"
    w.device_id = 42
    w.latitude = 142.2
    w.longitude = -39.2
    w.preview_secs = 3
    w.motion_config = b"blob"
    w.write_header()
    w.close()

    buf.seek(0, 0)

    r = CPTVReader(buf)
    assert r.version == 2
    assert r.x_resolution == 160
    assert r.y_resolution == 120
    assert r.timestamp == w.timestamp
    assert r.device_name == w.device_name
    assert r.device_id == w.device_id
    assert r.latitude == w.latitude
    assert r.longitude == w.longitude
    assert r.preview_secs == w.preview_secs
    assert r.motion_config == w.motion_config
def parse_cptv(cptv_file, config, thermal_config_file, preview_type):
    with open(cptv_file, "rb") as f:
        reader = CPTVReader(f)

        headers = HeaderInfo(
            res_x=reader.x_resolution,
            res_y=reader.y_resolution,
            fps=9,
            brand=reader.brand.decode() if reader.brand else None,
            model=reader.model.decode() if reader.model else None,
            frame_size=reader.x_resolution * reader.y_resolution * 2,
            pixel_bits=16,
            serial="",
            firmware="",
        )
        thermal_config = ThermalConfig.load_from_file(thermal_config_file,
                                                      headers.model)
        pi_classifier = PiClassifier(
            config,
            thermal_config,
            headers,
            thermal_config.motion.run_classifier,
            0,
            preview_type,
        )
        for frame in reader:
            if frame.background_frame:
                pi_classifier.motion_detector.background = frame.pix
                continue
            frame.received_at = time.time()
            pi_classifier.process_frame(frame)
        pi_classifier.disconnected()
 def load(self, filename):
     """
     Loads a cptv file, and prepares for track extraction.
     """
     self.source_file = filename
     self.reader = CPTVReader(open(filename, 'rb'))
     local_tz = pytz.timezone('Pacific/Auckland')
     self.video_start_time = self.reader.timestamp.astimezone(local_tz)
     self.stats.update(self.get_video_stats())
예제 #10
0
def send_cptv(filename, socket):
    """
    Loads a cptv file, and prepares for track extraction.
    """
    with open(filename, "rb") as f:
        reader = CPTVReader(f)
        for i, frame in enumerate(reader):
            f = np.uint16(frame.pix).byteswap()
            socket.sendall(f)
            print("sending frame {}".format(i))
예제 #11
0
def make_mp4(cptv_file, output_folder, colormap):
    with open(cptv_file, "rb") as f:
        reader = CPTVReader(f)

        # make name and folder for recording
        mp4_name = reader.timestamp.strftime("%Y%m%d-%H%M%S") + ".mp4"
        #devicename = reader.devicename
        devicename = "to-be-added"
        if devicename == None:
            devicename = "NO_DEVICE_NAME"
        else:
            mp4_name = devicename + "_" + mp4_name
        mp4_dir = join(output_folder, devicename)
        os.makedirs(mp4_dir, exist_ok=True)
        mp4_file = join(mp4_dir, mp4_name)
        print(mp4_file)

        FRAME_SCALE = 4.0
        NORMALISATION_SMOOTH = 0.95
        HEAD_ROOM = 25
        auto_min = None
        auto_max = None

        mpeg = MPEGCreator(mp4_file)
        for frame in reader:
            if (auto_min == None):
                auto_min = np.min(frame[0])
                auto_max = np.max(frame[0])

            thermal_min = np.min(frame[0])
            thermal_max = np.max(frame[0])

            auto_min = NORMALISATION_SMOOTH * auto_min + (
                1 - NORMALISATION_SMOOTH) * (thermal_min - HEAD_ROOM)
            auto_max = NORMALISATION_SMOOTH * auto_max + (
                1 - NORMALISATION_SMOOTH) * (thermal_max + HEAD_ROOM)

            # sometimes we get an extreme value that throws off the autonormalisation, so if there are values outside
            # of the expected range just instantly switch levels
            if thermal_min < auto_min or thermal_max > auto_max:
                auto_min = thermal_min
                auto_max = thermal_max

            thermal_image = convert_heat_to_img(frame[0], colormap, auto_min,
                                                auto_max)
            thermal_image = thermal_image.resize(
                (int(thermal_image.width * FRAME_SCALE),
                 int(thermal_image.height * FRAME_SCALE)), Image.BILINEAR)
            mpeg.next_frame(np.asarray(thermal_image))
        mpeg.close()
예제 #12
0
def update_metadata(recording, api):
    with open(str(recording["filename"]), "rb") as f:
        reader = CPTVReader(f)
        metadata = {}
        metadata["recordingDateTime"] = reader.timestamp.isoformat()
        # TODO Add device name when it can be processed on api server
        # metadata["device_name"] = reader.device_name

        count = 0.0
        for _ in reader:
            count += 1
        metadata["duration"] = round(count / FRAME_RATE)
    complete = not conf.do_classify
    api.update_metadata(recording, metadata, complete)
    def load(self, source, max_frames=None):
        """
        Load frames from a CPTV file.
        :param source: source file
        :param max_frames: maximum number of frames to load, None will load the whole video (default)
        """
        reader = CPTVReader(source)
        self.frames = []
        for i, (frame, offset) in enumerate(reader):
            self.frames.append(frame.copy())
            if max_frames is not None and i >= max_frames:
                break

        self.video_start_time = reader.timestamp
def main():
    logging.root.removeHandler(absl.logging._absl_handler)
    absl.logging._warn_preinit_stderr = False
    init_logging()
    args = parse_args()

    config = Config.load_from_file()
    thermal_config = ThermalConfig.load_from_file()
    proccesor = None
    if thermal_config.motion.run_classifier:
        classifier = get_classifier(config)
        proccesor = PiClassifier(config, thermal_config, classifier)
    else:
        proccesor = MotionDetector(
            config.res_x,
            config.res_y,
            thermal_config,
            config.tracking.dynamic_thresh,
            CPTVRecorder(thermal_config),
        )
    if args.cptv:
        with open(args.cptv, "rb") as f:
            reader = CPTVReader(f)
            for frame in reader:
                proccesor.process_frame(frame)

        proccesor.disconnected()
        return

    service = SnapshotService(proccesor)
    try:
        os.unlink(SOCKET_NAME)
    except OSError:
        if os.path.exists(SOCKET_NAME):
            raise

    sock = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
    sock.bind(SOCKET_NAME)
    sock.listen(1)
    while True:
        logging.info("waiting for a connection")
        connection, client_address = sock.accept()
        logging.info("connection from %s", client_address)
        try:
            handle_connection(connection, proccesor)
        finally:
            # Clean up the connection
            connection.close()
예제 #15
0
    def load(self, filename):
        """
        Loads a cptv file, and prepares for track extraction.
        """
        self.source_file = filename

        with open(filename, "rb") as f:
            reader = CPTVReader(f)
            local_tz = pytz.timezone('Pacific/Auckland')
            self.video_start_time = reader.timestamp.astimezone(local_tz)
            self.preview_secs = reader.preview_secs
            self.stats.update(self.get_video_stats())
            # we need to load the entire video so we can analyse the background.
            frames = ([frame.pix for frame in reader])
            self.frame_buffer.thermal = frames
            edge = self.config.edge_pixels
            self.crop_rectangle = Rectangle(edge, edge, reader.x_resolution - 2 * edge, reader.y_resolution - 2 * edge)
예제 #16
0
def check_frames(frames):
    buf = BytesIO()
    w = CPTVWriter(buf)
    w.write_header()
    for frame in frames:
        w.write_frame(frame)
    w.close()

    buf.seek(0, 0)

    r = CPTVReader(buf)
    count = 0
    for in_frame, out_frame in zip(frames, r):
        assert in_frame == out_frame
        count += 1

    assert count == len(frames)
예제 #17
0
    def parse_clip(self, clip):
        """
        Loads a cptv file, and prepares for track extraction.
        """

        clip.set_frame_buffer(
            self.config.high_quality_optical_flow,
            self.cache_to_disk,
            self.use_opt_flow,
            self.keep_frames,
        )

        with open(clip.source_file, "rb") as f:
            reader = CPTVReader(f)
            clip.set_res(reader.x_resolution, reader.y_resolution)
            video_start_time = reader.timestamp.astimezone(Clip.local_tz)
            clip.num_preview_frames = (
                reader.preview_secs * clip.frames_per_second -
                self.config.ignore_frames)
            clip.set_video_stats(video_start_time)
            # we need to load the entire video so we can analyse the background.

            if clip.background_is_preview and clip.num_preview_frames > 0:
                for frame in reader:
                    self.process_frame(clip, frame.pix,
                                       is_affected_by_ffc(frame))

                if clip.on_preview():
                    logging.warn("Clip is all preview frames")
                    if clip.background is None:
                        logging.warn("Clip only has ffc affected frames")
                        return False

                    clip._set_from_background()
                    self._process_preview_frames(clip)
            else:
                clip.background_is_preview = False
                self.process_frames(clip, [frame for frame in reader])

        if not clip.from_metadata:
            self.apply_track_filtering(clip)

        if self.calc_stats:
            clip.stats.completed(clip.frame_on, clip.res_y, clip.res_x)

        return True
예제 #18
0
def test_round_trip_header_defaults():
    buf = BytesIO()

    w = CPTVWriter(buf)
    w.write_header()
    w.close()

    buf.seek(0, 0)

    r = CPTVReader(buf)
    assert r.version == 2
    assert r.x_resolution == 160
    assert r.y_resolution == 120
    assert not r.device_name
    assert not r.device_id
    assert (datetime.now(tz=timezone.utc) - r.timestamp) < timedelta(minutes=1)
    assert r.latitude == 0
    assert r.longitude == 0
예제 #19
0
def parse_cptv(cptv_file, config, thermal_config):
    with open(cptv_file, "rb") as f:
        reader = CPTVReader(f)

        headers = HeaderInfo(
            res_x=reader.x_resolution,
            res_y=reader.y_resolution,
            fps=9,
            brand="",
            model="",
            frame_size=reader.x_resolution * reader.y_resolution * 2,
            pixel_bits=16,
        )
        processor = get_processor(config, thermal_config, headers)
        for frame in reader:
            processor.process_frame(frame)

        processor.disconnected()
예제 #20
0
def update_metadata(conf, recording, api):
    with open(str(recording["filename"]), "rb") as f:
        reader = CPTVReader(f)
        metadata = {}
        metadata["recordingDateTime"] = reader.timestamp.isoformat()
        if reader.latitude != 0 and reader.longitude != 0:
            metadata["location"] = (reader.latitude, reader.longitude)

        if reader.preview_secs:
            metadata["additionalMetadata"] = {"previewSecs": reader.preview_secs}

        count = 0
        for _ in reader:
            count += 1
        metadata["duration"] = round(count / FRAME_RATE)
        recording["duration"] = metadata["duration"]
    complete = not conf.do_classify
    api.update_metadata(recording, metadata, complete)
예제 #21
0
def test_read_v1():
    filename = str(data_dir / "v1.cptv")
    with open(filename, "rb") as f:
        r = CPTVReader(f)
        assert r.version == 1
        assert r.device_name == b"livingsprings03"
        assert r.timestamp == datetime(2018, 9, 6, 9, 21, 25, 774768,
                                       timezone.utc)
        assert r.x_resolution == 160
        assert r.y_resolution == 120
        assert r.preview_secs == 0
        assert r.motion_config is None

        count = 0
        for frame in r:
            count += 1
            assert frame.time_on is None
            assert frame.last_ffc_time is None
        assert count == 100
def main():
    args = parse_args()
    init_logging()

    config = Config.load_from_file()
    thermal_config = ThermalConfig.load_from_file()
    location_config = LocationConfig.load_from_file()
    res_x = config.res_x
    res_y = config.res_y
    print("detecting on  " + args.cptv)
    motion_detector = MotionDetector(
        res_x,
        res_y,
        thermal_config.motion,
        location_config,
        thermal_config.recorder,
        config.tracking.dynamic_thresh,
        None,
    )
    with open(args.cptv, "rb") as f:
        reader = CPTVReader(f)
        for i, frame in enumerate(reader):
            motion_detector.process_frame(frame)
예제 #23
0
import sys
from cptv import CPTVReader


filename = sys.argv[1]

with open(filename, "rb") as f:
    reader = CPTVReader(f)
    print("version:", reader.version)
    print("device:", reader.device_name)
    print("time:", reader.timestamp)
    print("dims:", reader.x_resolution, reader.y_resolution)
    print("preview secs:", reader.preview_secs)
    print("motion config:", reader.motion_config)

    for frame in reader:
        print(
            "t:",
            frame.time_on,
            "ffc:",
            frame.last_ffc_time,
            "min:",
            frame.pix.min(),
            "max:",
            frame.pix.max(),
        )
예제 #24
0
def process_cptv_file(cptv_file, output_folder, copy, delete, colormap):
    with open(cptv_file, "rb") as f:
        reader = CPTVReader(f)

        # make name and folder for recording
        fileName = reader.timestamp.strftime("%Y%m%d-%H%M%S")
        raw_name = fileName + ".cptv"
        mp4_name = fileName + ".mp4"
        mp4_temp = join(tempfile.gettempdir(), mp4_name)
        devicename = reader.device_name
        if not devicename:
            devicename = "NO_DEVICE_NAME"
        else:
            raw_name = devicename + "_" + raw_name
            mp4_name = devicename + "_" + mp4_name
        raw_dir = join(output_folder, devicename, "raw-cptv")
        mp4_dir = join(output_folder, devicename, "cptv-processed")
        os.makedirs(mp4_dir, exist_ok=True)
        raw_file = join(raw_dir, raw_name)
        mp4_file = join(mp4_dir, mp4_name)
        print(mp4_file)
        if copy:
            os.makedirs(raw_dir, exist_ok=True)
            copy_file(cptv_file, raw_file)

        FRAME_SCALE = 4.0
        NORMALISATION_SMOOTH = 0.95
        HEAD_ROOM = 25
        auto_min = None
        auto_max = None

        mpeg = MPEGCreator(mp4_temp)
        for frame in reader:
            if (auto_min == None):
                auto_min = np.min(frame[0])
                auto_max = np.max(frame[0])

            thermal_min = np.min(frame[0])
            thermal_max = np.max(frame[0])

            auto_min = NORMALISATION_SMOOTH * auto_min + (
                1 - NORMALISATION_SMOOTH) * (thermal_min - HEAD_ROOM)
            auto_max = NORMALISATION_SMOOTH * auto_max + (
                1 - NORMALISATION_SMOOTH) * (thermal_max + HEAD_ROOM)

            # sometimes we get an extreme value that throws off the autonormalisation, so if there are values outside
            # of the expected range just instantly switch levels
            if thermal_min < auto_min or thermal_max > auto_max:
                auto_min = thermal_min
                auto_max = thermal_max

            thermal_image = convert_heat_to_img(frame[0], colormap, auto_min,
                                                auto_max)
            thermal_image = thermal_image.resize(
                (int(thermal_image.width * FRAME_SCALE),
                 int(thermal_image.height * FRAME_SCALE)), Image.BILINEAR)
            mpeg.next_frame(np.asarray(thermal_image))
        mpeg.close()
    copy_file(mp4_temp, mp4_file)
    os.remove(mp4_temp)
    if copy and delete:
        os.remove(cptv_file)
예제 #25
0
    def process_file(self, filename, cache=None, reuse_frames=None):
        """
        Process a file extracting tracks and identifying them.
        :param filename: filename to process
        :param enable_preview: if true an MPEG preview file is created.
        """

        base_filename = os.path.splitext(os.path.basename(filename))[0]
        meta_file = os.path.join(os.path.dirname(filename), base_filename + ".txt")
        if not os.path.exists(filename):
            raise Exception("File {} not found.".format(filename))
        if not os.path.exists(meta_file):
            raise Exception("File {} not found.".format(meta_file))
        meta_data = tools.load_clip_metadata(meta_file)
        logging.info("Processing file '{}'".format(filename))
        cache_to_disk = (
            cache if cache is not None else self.config.classify.cache_to_disk
        )
        start = time.time()
        clip = Clip(self.config.tracking, filename)
        clip.set_frame_buffer(
            self.high_quality_optical_flow,
            cache_to_disk,
            self.config.use_opt_flow,
            True,
        )
        clip.load_metadata(
            meta_data,
            self.config.load.tag_precedence,
        )
        frames = []
        with open(clip.source_file, "rb") as f:
            reader = CPTVReader(f)
            clip.set_res(reader.x_resolution, reader.y_resolution)
            clip.calculate_background(reader)
            f.seek(0)
            for frame in reader:
                if frame.background_frame:
                    continue
                clip.add_frame(
                    frame.pix,
                    frame.pix - clip.background,
                    ffc_affected=is_affected_by_ffc(frame),
                )
        predictions_per_model = {}
        if self.model:
            prediction = self.classify_clip(
                clip, self.model, meta_data, reuse_frames=reuse_frames
            )
            predictions_per_model[self.model.id] = prediction
        else:
            for model in self.config.classify.models:
                prediction = self.classify_clip(
                    clip, model, meta_data, reuse_frames=reuse_frames
                )
                predictions_per_model[model.id] = prediction

        if self.previewer:
            mpeg_filename = os.path.join(
                os.path.dirname(filename), base_filename + ".mp4"
            )
            logging.info("Exporting preview to '{}'".format(mpeg_filename))

            self.previewer.export_clip_preview(
                mpeg_filename, clip, list(predictions_per_model.values())[0]
            )
        logging.info("saving meta data %s", meta_file)
        models = [self.model] if self.model else self.config.classify.models
        meta_data = self.save_metadata(
            meta_data,
            meta_file,
            clip,
            predictions_per_model,
            models,
        )
        if cache_to_disk:
            clip.frame_buffer.remove_cache()
        return meta_data
예제 #26
0
#!/usr/bin/python3

import sys
import pytz

from cptv import CPTVReader

local_tz = pytz.timezone('Pacific/Auckland')

reader = CPTVReader(open(sys.argv[1], "rb"))
print(reader.timestamp.astimezone(local_tz))

for i, (frame, offset) in enumerate(reader):
    print(i, offset, frame.min(), frame.max())