Quantcast
Channel: Raspberry Pi Forums
Viewing all articles
Browse latest Browse all 8015

AI Camera - IMX500 • Re: CCTV security environment

$
0
0
therealdavidp,

Here's an issue I have with it. Hopefully the code isn't too long..

Pi5, imx500, mp4s saved to /run/shm/

It captures OK but there seems to be an issue in the mp4 file, Kdenlive reports the attached issue and my video editing software on my windows Pc won't open the mp4s. It appears to be related to timestamps ?

mp4s show OK in vlc but any video after the first captured show strange times, eg start time not 0.

Any help appreciated ...

Code:

#!/usr/bin/env python3"""Based on imx500_object_detection_demo.py."""import argparseimport sysfrom functools import lru_cacheimport cv2import numpy as npimport timeimport datetimefrom picamera2 import MappedArray, Picamera2, Previewfrom picamera2.devices import IMX500from picamera2.devices.imx500 import (NetworkIntrinsics,postprocess_nanodet_detection)from picamera2.encoders import H264Encoderfrom picamera2.outputs import CircularOutput2, PyavOutputfrom libcamera import controls# detection objectsobjects      = ["cat","bear","clock","person"]threshold    = 0.5   # set detection threshold   # video settingsv_width      = 2028  # video widthv_height     = 1520  # video heightv_length     = 5     # secondsshow_detects = 0     # show detections on video# initialiselast_detections = []label    = " ( "encoding = Falseclass Detection:    def __init__(self, coords, category, conf, metadata):        """Create a Detection object, recording the bounding box, category and confidence."""        self.category = category        self.conf = conf        self.box = imx500.convert_inference_coords(coords, metadata, picam2)    def parse_detections(metadata: dict):    """Parse the output tensor into a number of detected objects, scaled to the ISP output."""    global last_detections    bbox_normalization = intrinsics.bbox_normalization    bbox_order = intrinsics.bbox_order    threshold = args.threshold    iou = args.iou    max_detections = args.max_detections    np_outputs = imx500.get_outputs(metadata, add_batch=True)    input_w, input_h = imx500.get_input_size()    if np_outputs is None:        return last_detections    if intrinsics.postprocess == "nanodet":        boxes, scores, classes = \            postprocess_nanodet_detection(outputs=np_outputs[0], conf=threshold, iou_thres=iou,                                          max_out_dets=max_detections)[0]        from picamera2.devices.imx500.postprocess import scale_boxes        boxes = scale_boxes(boxes, 1, 1, input_h, input_w, False, False)    else:        boxes, scores, classes = np_outputs[0][0], np_outputs[1][0], np_outputs[2][0]        if bbox_normalization:            boxes = boxes / input_h        if bbox_order == "xy":            boxes = boxes[:, [1, 0, 3, 2]]        boxes = np.array_split(boxes, 4, axis=1)        boxes = zip(*boxes)    last_detections = [        Detection(box, category, score, metadata)        for box, score, category in zip(boxes, scores, classes)        if score > threshold    ]    return last_detections@lru_cachedef get_labels():    labels = intrinsics.labels    if intrinsics.ignore_dash_labels:        labels = [label for label in labels if label and label != "-"]    return labelsdef draw_detections(request, stream="main"):    """Draw the detections for this request onto the ISP output."""    global label,show_detects, mp4_anno,scale    detections = last_results    if detections is None:        return    labels = get_labels()    with MappedArray(request, stream) as m:        for detection in detections:            x, y, w, h = detection.box            label = f"{labels[int(detection.category)]} ({detection.conf:.2f})"            if show_detects == 1:                # Calculate text size and position                (text_width, text_height), baseline = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1)                text_x = x + 5                text_y = y + 15                # Create a copy of the array to draw the background with opacity                overlay = m.array.copy()                # Draw the background rectangle on the overlay                cv2.rectangle(overlay,                          (text_x, text_y - text_height),                          (text_x + text_width, text_y + baseline),                          (255, 255, 255),  # Background color (white)                          cv2.FILLED)                alpha = 0.30                cv2.addWeighted(overlay, alpha, m.array, 1 - alpha, 0, m.array)                # Draw text on top of the background                cv2.putText(m.array, label, (text_x, text_y),                        cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1)                # Draw detection box                cv2.rectangle(m.array, (x, y), (x + w, y + h), (0, 255, 0, 0), thickness=2)        if intrinsics.preserve_aspect_ratio:            b_x, b_y, b_w, b_h = imx500.get_roi_scaled(request)            color = (255, 0, 0)  # red            cv2.putText(m.array, "ROI", (b_x + 5, b_y + 15), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 1)            cv2.rectangle(m.array, (b_x, b_y), (b_x + b_w, b_y + b_h), (255, 0, 0, 0))def get_args():    parser = argparse.ArgumentParser()    parser.add_argument("--model", type=str, help="Path of the model",                        default="/usr/share/imx500-models/imx500_network_ssd_mobilenetv2_fpnlite_320x320_pp.rpk")    parser.add_argument("--fps", type=int, help="Frames per second")    parser.add_argument("--bbox-normalization", action=argparse.BooleanOptionalAction, help="Normalize bbox")    parser.add_argument("--bbox-order", choices=["yx", "xy"], default="yx",                        help="Set bbox order yx -> (y0, x0, y1, x1) xy -> (x0, y0, x1, y1)")    parser.add_argument("--threshold", type=float, default=0.55, help="Detection threshold")    parser.add_argument("--iou", type=float, default=0.65, help="Set iou threshold")    parser.add_argument("--max-detections", type=int, default=10, help="Set max detections")    parser.add_argument("--ignore-dash-labels", action=argparse.BooleanOptionalAction, help="Remove '-' labels ")    parser.add_argument("--postprocess", choices=["", "nanodet"],                        default=None, help="Run post process of type")    parser.add_argument("-r", "--preserve-aspect-ratio", action=argparse.BooleanOptionalAction,                        help="preserve the pixel aspect ratio of the input tensor")    parser.add_argument("--labels", type=str,                        help="Path to the labels file")    parser.add_argument("--print-intrinsics", action="store_true",                        help="Print JSON network_intrinsics then exit")    return parser.parse_args()if __name__ == "__main__":    args = get_args()    # This must be called before instantiation of Picamera2    imx500 = IMX500(args.model)    intrinsics = imx500.network_intrinsics    if not intrinsics:        intrinsics = NetworkIntrinsics()        intrinsics.task = "object detection"    elif intrinsics.task != "object detection":        print("Network is not an object detection task", file=sys.stderr)        exit()    # Override intrinsics from args    for key, value in vars(args).items():        if key == 'labels' and value is not None:            with open(value, 'r') as f:                intrinsics.labels = f.read().splitlines()        elif hasattr(intrinsics, key) and value is not None:            setattr(intrinsics, key, value)    # Defaults    if intrinsics.labels is None:        with open("assets/coco_labels.txt", "r") as f:            intrinsics.labels = f.read().splitlines()    intrinsics.update_with_defaults()    if args.print_intrinsics:        print(intrinsics)        exit()    # Configure and start Picamera2.    model_h, model_w = imx500.get_input_size()    video_w, video_h = v_width,v_height    main  = {'size': (video_w, video_h), 'format': 'YUV420'}    lores = {'size': (model_w, model_h), 'format': 'YUV420'}    picam2 = Picamera2(imx500.camera_num)    config = picam2.create_preview_configuration(main, lores=lores,controls={"FrameRate": intrinsics.inference_rate}, buffer_count=12)    imx500.show_network_fw_progress_bar()    picam2.configure(config)    encoder = H264Encoder(bitrate=2000000)    circular = CircularOutput2(buffer_duration_ms=5000)    picam2.start_preview(Preview.QTGL, x=0, y=0, width=480, height=480)    picam2.start_recording(encoder, circular)    if intrinsics.preserve_aspect_ratio:        imx500.set_auto_aspect_ratio()    last_results = None    picam2.pre_callback = draw_detections    while True:        last_results = parse_detections(picam2.capture_metadata())        # capture frame        frame = picam2.capture_array('lores')        frame = cv2.cvtColor(frame, cv2.COLOR_YUV420p2RGB)        frame = frame[0:320, 0:320]        # detected label        data = label.split("(")        category = data[0][:-1]        value = data[1][:-1]        if category in objects and float(value) > threshold:            # restart timer            startrec = time.monotonic()            # start recording            if not encoding:                encoding = True                now = datetime.datetime.now()                timestamp = now.strftime("%y%m%d_%H%M%S")                print("New  Detection",timestamp,label)                circular.open_output(PyavOutput("/run/shm/" + timestamp +".mp4"))        # stop recording after v_length + 5 seconds to empty circular buffer        if encoding and (time.monotonic() - startrec > v_length + 5):            now = datetime.datetime.now()            timestamp2 = now.strftime("%y%m%d_%H%M%S")            print("Stopped Record", timestamp2)            circular.close_output()            encoding = False        category = ""        value = 0.0        label = " ( "
message.jpg

Statistics: Posted by gordon77 — Fri Mar 21, 2025 8:44 am



Viewing all articles
Browse latest Browse all 8015

Trending Articles