SK-AM62A-LP: Running python script using gstreamer pipeline, script breakdown.

Part Number: SK-AM62A-LP

Tool/software:

I am trying to run the following code on the board but instead of using the opencv gui window, I want to use the gstreamer pipeline with kmssink to display the output frame directly. I am following this example : https://github.com/TexasInstruments-Sandbox/edgeai-gst-apps-people-tracking 

import numpy as np
import tflite_runtime.interpreter as tflite  # Use tflite_runtime for TIDL delegate support
import faiss
import cv2
from PIL import Image
import os

MODEL_PATH = '/opt/edgeai-tidl-artifacts/cl-tfl-fomo-01/trained.tflite'
CAPTURED_IMAGES_DIR = './captured_frames'  # Directory to save captured frames
FAISS_INDEX_PATH = 'faiss_index.bin'
ANOMALY_THRESHOLD = 0.5

# Preprocess frame to match model input
def process_frame(frame, interpreter):
    img = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
    input_details = interpreter.get_input_details()
    output_details = interpreter.get_output_details()
    input_shape = input_details[0]['shape']

    img_resized = img.resize([input_shape[1], input_shape[2]])
    np_frame = np.array(img_resized, dtype=np.float32) / 255.0
    np_frame = np.expand_dims(np_frame, axis=0)  # Add batch dimension

    interpreter.set_tensor(input_details[0]['index'], np_frame)
    interpreter.invoke()
    output_data = interpreter.get_tensor(output_details[0]['index'])
    return output_data

# Build the FAISS index using reference ("good") examples
def build_faiss_index(captured_images, interpreter, output_resolution=[12, 12]):
    first_example_response = process_frame(cv2.imread(captured_images[0]), interpreter)
    feature_dim = first_example_response.shape[-1]
    faiss_index = faiss.IndexFlatL2(feature_dim)

    for image_path in captured_images:
        response = process_frame(cv2.imread(image_path), interpreter)
        for i in range(output_resolution[0]):
            for j in range(output_resolution[1]):
                patch_features = response[0, i, j, :].reshape(1, -1)
                faiss_index.add(patch_features.astype(np.float32))

    return faiss_index

# Save FAISS index to disk
def save_faiss_index(faiss_index, index_path):
    faiss.write_index(faiss_index, index_path)

# Load FAISS index from disk
def load_faiss_index(index_path):
    return faiss.read_index(index_path)

# Compute anomaly scores using FAISS
def compute_anomaly_faiss(image_features, faiss_index, output_resolution):
    distances = np.zeros(output_resolution)
    for i in range(output_resolution[0]):
        for j in range(output_resolution[1]):
            f_vec = image_features[0, i, j, :].reshape(1, -1)
            distance, _ = faiss_index.search(f_vec, 1)
            distances[i, j] = distance[0][0]
    return distances

# GStreamer pipeline configuration for TI AM62A board
def gstreamer_pipeline():
    return (
        'v4l2src device=/dev/video3 io-mode=dmabuf-import ! '
        'video/x-bayer, width=640, height=480, framerate=15/1, format=rggb10 ! '
        'tiovxisp sink_0::device=/dev/v4l-subdev2 sensor-name="SENSOR_SONY_IMX219_RPI" '
        'dcc-isp-file=/opt/imaging/imx219/linear/dcc_viss_10b_640x480.bin sink_0::dcc-2a-file=/opt/imaging/imx219/linear/dcc_2a_10b_640x480.bin format-msb=9 ! '
        'video/x-raw, format=NV12, width=640, height=480, framerate=15/1 ! videoconvert ! video/x-raw, format=BGR ! appsink'
    )

# Webcam stream with training and inference functionality
def evaluate_fomo_stream(interpreter):
    cap = cv2.VideoCapture(gstreamer_pipeline(), cv2.CAP_GSTREAMER)
    captured_images = []

    faiss_index = None  # No FAISS index initially

    def capture_frame(event, x, y, flags, param):
        nonlocal captured_images
        if event == cv2.EVENT_LBUTTONDOWN:
            print("Capturing frame for training...")
            img_path = os.path.join(CAPTURED_IMAGES_DIR, f'captured_{len(captured_images)}.png')
            cv2.imwrite(img_path, frame)  # Save the frame without heatmap
            captured_images.append(img_path)
            print(f"Captured and saved: {img_path}")

    cv2.namedWindow("Anomaly Detection")
    cv2.setMouseCallback("Anomaly Detection", capture_frame)

    while True:
        ret, frame = cap.read()
        if not ret:
            print("Failed to grab frame")
            break

        # If we have enough images for training (say, 10), build FAISS index
        if len(captured_images) >= 10 and faiss_index is None:
            print("Building FAISS index with captured images...")
            faiss_index = build_faiss_index(captured_images, interpreter)
            save_faiss_index(faiss_index, FAISS_INDEX_PATH)
            print("FAISS index saved and inference mode is enabled.")

        if faiss_index is not None:
            image_feat = process_frame(frame, interpreter)
            anomaly_score = compute_anomaly_faiss(image_feat, faiss_index, [12, 12])

            global_anomaly_score = np.mean(anomaly_score)
            classification = 'Anomaly' if global_anomaly_score > ANOMALY_THRESHOLD else 'No Anomaly'

            anomaly_heatmap = cv2.resize(anomaly_score, (frame.shape[1], frame.shape[0]), interpolation=cv2.INTER_NEAREST)
            anomaly_heatmap_normalized = cv2.normalize(anomaly_heatmap, None, 0, 255, cv2.NORM_MINMAX)
            anomaly_heatmap_colored = cv2.applyColorMap(np.uint8(anomaly_heatmap_normalized), cv2.COLORMAP_JET)

            overlay_frame = cv2.addWeighted(frame, 0.6, anomaly_heatmap_colored, 0.4, 0)

            cv2.putText(overlay_frame, f'Anomaly Score: {global_anomaly_score:.2f}', (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1,
                        (255, 255, 255), 2)
            cv2.putText(overlay_frame, f'Classification: {classification}', (10, 70), cv2.FONT_HERSHEY_SIMPLEX, 1,
                        (0, 0, 255) if classification == 'Anomaly' else (0, 255, 0), 2)

            cv2.imshow("Anomaly Detection", overlay_frame)
        else:
            cv2.imshow("Anomaly Detection", frame)

        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

    cap.release()
    cv2.destroyAllWindows()

# Create a directory to save captured frames
if not os.path.exists(CAPTURED_IMAGES_DIR):
    os.makedirs(CAPTURED_IMAGES_DIR)

# Load the TFLite model with TIDL delegate support
tidl_delegate = [tflite.load_delegate('libtidl_tfl_delegate.so', {'artifacts_folder': '/opt/edgeai-tidl-artifacts/cl-tfl-fomo-01'})]
interpreter = tflite.Interpreter(model_path=MODEL_PATH, experimental_delegates=tidl_delegate)
interpreter.allocate_tensors()

# Start real-time anomaly detection with live training
evaluate_fomo_stream(interpreter)

But I am a little confused as to how I am supposed to break down the code. What parts would I need as a pre or post process and especially how can I do the mouse clicking function for 10 times to click pictures and then use them to generate and save the faiss index. How do I create the gstreamer pipeline(do I even have to do that manually or is it automatically generated using the example above?), what parts of the pipeline are already taken care of through the scripts in the example? I want to use OptiFlow so that the pipeline is not slow. If you could please help me break down the classes/files/pipeline I would need, it would be great.

Here is the link to the config yaml file I have made, could you please tell me if it is alright for this purpose? drive.google.com/.../view

Thank you 

  • Hi Pragya,

    It is out pleasure to help. The Linux Edgeai SDK documentation provides details about setting up the edgeai-gst-apps. https://software-dl.ti.com/processor-sdk-linux/esd/AM62AX/10_00_00/exports/edgeai-docs/common/sdk_overview.html

    But I am a little confused as to how I am supposed to break down the code. What parts would I need as a pre or post process

    The edgeai-gst-apps takes care of all functionality related to image capture, pre-processing, model initialization and inference, and display. It also provides simple post process functionality which you can expand for your own application. See this link for examples of the pipeline: https://software-dl.ti.com/processor-sdk-linux/esd/AM62AX/10_00_00/exports/edgeai-docs/common/edgeai_dataflows.html#object-detection

    The post process is implemented in this file https://github.com/TexasInstruments-Sandbox/edgeai-gst-apps-people-tracking/blob/main/apps_python/post_process.py#L357. You see at line 357, a new class is created for the postprocess work related for the people tracking demo. Note that the post process in this case takes care of annotating the picture and also generating the entire display with the dashboard. 

    How do I create the gstreamer pipeline(do I even have to do that manually or is it automatically generated using the example above?), what parts of the pipeline are already taken care of through the scripts in the example?

    The gstreamer pipeline is generated for you based on the yaml file. For details about setting up the yaml file see this part of the documentation: https://software-dl.ti.com/processor-sdk-linux/esd/AM62AX/10_00_00/exports/edgeai-docs/common/configuration_file.html

    I want to use OptiFlow so that the pipeline is not slow.

    Optiflow is fast because it uses a gstreamer plugins to call the model inference and post process. These plugins are already compiled for predefined types of post processes (classification, detection, and segmentation). Using optiflow for any other postprocess require editing and building the plugins. The instructions to generate a pipeline for optiflow are here: https://software-dl.ti.com/processor-sdk-linux/esd/AM62AX/10_00_00/exports/edgeai-docs/common/sample_apps.html?highlight=optiflow#optiflow. Note that the input to the script in the link above is the same yaml file. 

    If you could please help me break down the classes/files/pipeline I would need, it would be great.

    Follow the code in this class to change the post process to what you desire. https://github.com/TexasInstruments-Sandbox/edgeai-gst-apps-people-tracking/blob/main/apps_python/post_process.py#L357

    Here is the link to the config yaml file I have made, could you please tell me if it is alright for this purpose? drive.google.com/.../view

    I would like to highlight that scaling the picture will be automatically taken care of by the hardware. So you can still take the input from the camera in its actual full resolution and the pipeline will call the hardware multiscaler to scale down based on the expected model's input. The resolution for the kmssink should be the same resolution supported by the actual screen. 

    especially how can I do the mouse clicking function for 10 times to click pictures and then use them to generate and save the faiss index.

    The edgeai-gst-apps does not support mouse functionality. I suggest designing the project in a way where mouse is not needed. Otherwise, you can look at the out of box gui examples which is built based on QT. The source code for this project is available here: https://git.ti.com/cgit/apps/edgeai-gui-app/. Please, pay attention that this is a static gui application and it is intended for ease of use to run the out of box demos which are a collection of gstreamer application.

    Best regards,

    Qutaiba

  • Hello, thank you for the reply. 

    You mentioned that edgeai-gst-apps dont support mouse funcionality then what about keys functionality from an attached keyboard maybe? 

    Also, in the script is it possible to deploy and run two models simultaneously on the AI accelerator? 

    Thank you. 

  • Hi Pragya,

    You mentioned that edgeai-gst-apps dont support mouse funcionality then what about keys functionality from an attached keyboard maybe?

    The limiting factor here is the GUI rendering and not the hardware. So using a keyboard is a good alternative. You can use a full USB keyboard connected to the EVM or you can use a custom keypad using and connect it through GPIO: https://github.com/TexasInstruments/ti-gpio-py

    Also, in the script is it possible to deploy and run two models simultaneously on the AI accelerator? 

    Yes it is possible to run multiple models simultaneously on the AI accelerator. See an example in the edgeai-gst-apps here: https://github.com/TexasInstruments/edgeai-gst-apps/blob/main/configs/multi_input_multi_infer.yaml. Data flow is explained here: https://software-dl.ti.com/processor-sdk-linux/esd/AM62AX/10_00_00/exports/edgeai-docs/common/edgeai_dataflows.html#single-input-multi-inference 

    Best regards,

    Qutaiba

  • Okay so circling back to the initial question : the Keyboard functionality of clicking pictures and generating and storing the faiss index would then be part of preprocessing or not? and the index comparison part and score and heatmap generation would be postprocess right? 

    Also, I wanted to ask if it is possible to deploy a tf or onnx model on the AI accelerator without generating model aritfacts for it? 

    Thank you

  • Hi Pragya,

    The short answer is yes, any functionality that is after the ML inference can be implementing as part of the postprocess. I would like to highlight that depending on the complexity and time consumption of these processes, you might want to use multi-threading to balance the load and avoid delay in displaying the annotated frame. 

    Best regards,

    Qutaiba

  • Hi, 

    But what I am trying to understand is that the clicking of (10) images and then passing them through the model for feature extraction is PREprocessing right becuase here the streaming and image clicking is happening before passing it to the model? and which files of the edgeai gst apps should this functionality fall into?

    Also, I wanted to ask if it is possible to deploy a tf or onnx model on the AI accelerator without generating model aritfacts for it? 

    Thanks,
    Pragya

  • Hi Pragya,

    The pre-processing can be implemented/called in the infer_pipe.py file. Following are some notes about the flow of this file:

    What you are asking for is pre-processing in a sense that you would like to select pictures before sending them to ML inference. However, you have to display them first so that the users can see and decide what to select. In such scenario, the edgeai-gst-apps is not directly applicable to your use case. This application assume continuous flow of frames from camera to inference to postprocess to display. There is no interference in this flow except at the postprocess step. You will have to make some changes to achieve your desired functionality. 

    Now I would like to understand the exact functionality you are trying to achieve. My understanding is that you want to see a contentious live stream from the camera to the monitor. The user can press a key on the keyboard to select the frame to send to ML inference. The result of that inference is saved in a file. Is this correct? If this is the case, then what don't you continuously make the ML inference and display the annotated frame for the user and then the user can still press a key on the keyboard to store that frame? In this case, pressing the key will be in the postprocess step. 

    Best regards,

    Qutaiba

  • Hello, 

    1. So yes what I want to do is have a contentious live stream from the camera to the monitor. The user selects 10 frames by clicking a key on the keyboard and only those 10 frames are passed to the model to for the output to then be saved in a file(index). After this process, each and every frame is passed through the model and compared against the outputs saved in the file(generated from those 10 frames) and a heatmap is generated to detect anomalies. Hope this is clear. 

    2. I think you missed by question earlier but is it possible to deploy a tf or onnx model on the AI accelerator without generating model aritfacts for it? 

    3. In the model zoo is it okay to have my model and its artifacts in this format (as generated by your script) : https://drive.google.com/drive/folders/1hNAvUqlz3-oJ4WNqRDZebvilGTG3Rf5w?usp=drive_link or do I need to have them in the format mentioned here : https://software-dl.ti.com/jacinto7/esd/processor-sdk-linux-sk-tda4vm/09_02_00/exports/edgeai-docs/common/inference_models.html

    Thank you. 

  • Hi Pragya,

    Thank you for explaining more details about your project. If you don't want all frames to be processed by ML, I suggest you edit the infer_pipe.py file to display the frame directly on screen and based on customers key press you decide which frames to be processed by ML. Clearly, the functionality you are trying to achieve here does not directly map to the edgeai-gst-apps projects but you can use it as a starting point. 

    I think you missed by question earlier but is it possible to deploy a tf or onnx model on the AI accelerator without generating model aritfacts for it? 

    I missed this part. The answer is no. You have to compiler the model and generate the artifacts in order to be able to offload it to the AI accelerator. 

    n the model zoo is it okay to have my model and its artifacts in this format (as generated by your script) :

    The artifacts you shared in the google drive folder look fine. Did you try them? 

    Best regards,

    Qutaiba

  • Hello, 

    I tried running everything(python ./app_edgeai.py ../configs/anomaly_detection.yaml) and  I get this output : 


    Number of subgraphs:1 , 24 nodes delegated out of 24 nodes

    APP: Init ... !!!
    MEM: Init ... !!!
    MEM: Initialized DMA HEAP (fd=6) !!!
    MEM: Init ... Done !!!
    IPC: Init ... !!!
    IPC: Init ... Done !!!
    REMOTE_SERVICE: Init ... !!!
    REMOTE_SERVICE: Init ... Done !!!
    114.118990 s: GTC Frequency = 200 MHz
    APP: Init ... Done !!!
    114.121339 s: VX_ZONE_INIT:Enabled
    114.121381 s: VX_ZONE_ERROR:Enabled
    114.121391 s: VX_ZONE_WARNING:Enabled
    114.123672 s: VX_ZONE_INIT:[tivxInitLocal:130] Initialization Done !!!
    114.125239 s: VX_ZONE_INIT:[tivxHostInitLocal:101] Initialization Done for HOST !!!
    ==========[INPUT PIPELINE(S)]==========

    [PIPE-0]

    v4l2src device=/dev/video3 io-mode=5 pixel-aspect-ratio=None ! queue leaky=2 ! capsfilter caps="video/x-bayer, width=(int)640, height=(int)480, format=(string)rggb;" ! tiovxisp dcc-isp-file=/opt/imaging/imx219/linear/dcc_viss.bin sensor-name=SENSOR_SONY_IMX219_RPI ! capsfilter caps="video/x-raw, format=(string)NV12;" ! tiovxmultiscaler name=split_01
    split_01. ! queue ! capsfilter caps="video/x-raw, width=(int)640, height=(int)480;" ! tiovxdlcolorconvert out-pool-size=4 ! capsfilter caps="video/x-raw, format=(string)RGB;" ! appsink max-buffers=2 drop=True name=sen_0
    split_01. ! queue ! capsfilter caps="video/x-raw, width=(int)384, height=(int)288;" ! tiovxmultiscaler target=1 ! capsfilter caps="video/x-raw, width=(int)128, height=(int)96;" ! tiovxdlcolorconvert out-pool-size=4 ! capsfilter caps="video/x-raw, format=(string)RGB;" ! videobox qos=True left=16 right=16 ! tiovxdlpreproc out-pool-size=4 channel-order=1 ! capsfilter caps="application/x-tensor-tiovx;" ! appsink max-buffers=2 drop=True name=pre_0


    ==========[OUTPUT PIPELINE]==========

    appsrc do-timestamp=True format=3 block=True name=post_0 ! tiovxdlcolorconvert ! capsfilter caps="video/x-raw, format=(string)NV12, width=(int)640, height=(int)480;" ! queue ! mosaic_0.sink_0

    tiovxmosaic target=1 background=/tmp/background_0 name=mosaic_0 src::pool-size=4
    sink_0::startx="<0>" sink_0::starty="<0>" sink_0::widths="<640>" sink_0::heights="<480>"
    ! capsfilter caps="video/x-raw, format=(string)NV12, width=(int)640, height=(int)480;" ! queue ! tiperfoverlay title=Anomaly Detection ! kmssink sync=False max-lateness=5000000 qos=True processing-deadline=15000000 driver-name=tidss connector-id=40 plane-id=31 force-modesetting=True



    | Anomaly Detection | +--------------------------------------------------------------------------+ +--------------------------------------------------------------------------+ | Input Src: /dev/video3 | | Model Name: cl-tfl-fomo-01 | | Model Type: classification | +--------------------------------------------------------------------------+ +--------------------------------------------------------------------------+ +--------------------------------------------------------------------------+ | Anomaly Detection | +--------------------------------------------------------------------------+ +--------------------------------------------------------------------------+ | Input Src: /dev/video3 | | Model Name: cl-tfl-fomo-01 | | Model Type: classification | +--------------------------------------------------------------------------+ +--------------------------------------------------------------------------

    The screen shows nothing, just the homepage

    but I also get ERROR : Error pulling tensor from GST pipeline. 

    This is my param.yaml file : 

    postprocess:
      data_layout: NHWC
    preprocess:
      crop:
      - 96
      - 96
      data_layout: NHWC
      mean:
      - 0
      - 0
      - 0
      resize:
      - 96
      - 96
      scale:
      - 0.003921569790691137
      - 0.003921569790691137
      - 0.003921569790691137
      reverse_channels: false
    session:
      artifacts_folder: ''
      model_folder: model
      model_path: trained.tflite
      session_name: tflitert
      input_data_layout: NHWC
      input_details:
      - name: "serving_default_x:0"  
        type: <class 'numpy.float32'>
        shape:
        - 1
        - 96
        - 96
        - 3
      input_optimization: True
      output_details:
      - name: "StatefulPartitionedCall:0"  
        type: <class 'numpy.float32'>
        shape:
        - 1
        - 12
        - 12
        - 96
    target_device: AM62A
    task_type: anomaly_detection



    and this is my new postprocess class : 
    class PostProcessAnomalyDetection(PostProcess):
        def __init__(self, flow):
            super().__init__(flow)
            self.captured_images = []
            self.faiss_index = None
    
            if not os.path.exists(CAPTURED_IMAGES_DIR):
                os.makedirs(CAPTURED_IMAGES_DIR)
    
        def __call__(self, frame, results):
            image_feat = results
    
            # Check for keyboard input to save the frame
            key = cv2.waitKey(1) & 0xFF
            if key == ord('s'):  # Press 's' key to save frame
                img_path = os.path.join(CAPTURED_IMAGES_DIR, f'captured_{len(self.captured_images)}.png')
                cv2.imwrite(img_path, frame)
                self.captured_images.append(img_path)
                print(f"Captured and saved: {img_path}")
    
            # Build FAISS index once we have enough images
            if len(self.captured_images) >= 10 and self.faiss_index is None:
                print("Building FAISS index with captured images...")
                self.faiss_index = self.build_faiss_index()
                print("FAISS index saved and ready for inference.")
    
            # Only compute anomaly score and generate heatmap if FAISS index is available
            if self.faiss_index is not None:
                anomaly_score = self.compute_anomaly_score(image_feat)
                global_anomaly_score = np.mean(anomaly_score)
                classification = 'Anomaly' if global_anomaly_score > ANOMALY_THRESHOLD else 'No Anomaly'
    
                # Generate and display heatmap overlay
                overlay_frame = self.generate_heatmap_overlay(frame, anomaly_score, global_anomaly_score, classification)
                cv2.imshow("Anomaly Detection", overlay_frame)
            else:
                # Display raw frame if FAISS index is unavailable
                cv2.imshow("Anomaly Detection", frame)
    
            return frame
    
        def build_faiss_index(self, output_resolution=[12, 12]):
            first_example_response = self.process_frame_for_features(cv2.imread(self.captured_images[0]))
            feature_dim = first_example_response.shape[-1]
            faiss_index = faiss.IndexFlatL2(feature_dim)
    
            for image_path in self.captured_images:
                response = self.process_frame_for_features(cv2.imread(image_path))
                for i in range(output_resolution[0]):
                    for j in range(output_resolution[1]):
                        patch_features = response[0, i, j, :].reshape(1, -1)
                        faiss_index.add(patch_features.astype(np.float32))
    
            faiss.write_index(faiss_index, FAISS_INDEX_PATH)
            return faiss_index
    
        def compute_anomaly_score(self, image_features, output_resolution=[12, 12]):
            distances = np.zeros(output_resolution)
            for i in range(output_resolution[0]):
                for j in range(output_resolution[1]):
                    f_vec = image_features[0, i, j, :].reshape(1, -1)
                    distance, _ = self.faiss_index.search(f_vec, 1)
                    distances[i, j] = distance[0][0]
            return distances
    
        def generate_heatmap_overlay(self, frame, anomaly_score, global_anomaly_score, classification):
            anomaly_heatmap = cv2.resize(anomaly_score, (frame.shape[1], frame.shape[0]), interpolation=cv2.INTER_NEAREST)
            anomaly_heatmap_normalized = cv2.normalize(anomaly_heatmap, None, 0, 255, cv2.NORM_MINMAX)
            anomaly_heatmap_colored = cv2.applyColorMap(np.uint8(anomaly_heatmap_normalized), cv2.COLORMAP_JET)
    
            overlay_frame = cv2.addWeighted(frame, 0.6, anomaly_heatmap_colored, 0.4, 0)
            cv2.putText(overlay_frame, f'Anomaly Score: {global_anomaly_score:.2f}', (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1,
                        (255, 255, 255), 2)
            cv2.putText(overlay_frame, f'Classification: {classification}', (10, 70), cv2.FONT_HERSHEY_SIMPLEX, 1,
                        (0, 0, 255) if classification == 'Anomaly' else (0, 255, 0), 2)
            return overlay_frame


    and this is my anomaly_detection.yaml
    title: "Anomaly Detection"
    log_level: 2
    inputs:
        input0:
            source: /dev/video-rpi-cam0
            subdev-id: /dev/v4l-rpi-subdev0
            width: 640
            height: 480
            format: rggb
            framerate: 30
    
    models:
        model0:
            model_path: /opt/model_zoo/cl-tfl-fomo-01
    
    outputs:
        output0:
            sink: kmssink
            width: 640
            height: 480
            format: NV12
            overlay-perf-type: graph
    
    flows:
        flow0: [input0,model0,output0,[0,0,640,480]]
    


  • Hi Pragya,

    There are several variables that can go wrong here. I suggest to take this one step  at a time. First I would like to ask:

    • I see in your anomaly_detection.yaml, you are using /dev/video-rpi-cam0 as input however the gstreamer pipeline you shared is trying to connect to /dev/video3. Is this the correct camera you would like to use?
    • Does this camera support 640x480? Please keep in mind that the hardware multiscalor accelerator will take care of any scaling tasks so you can use the actual resolution of the camera. 
    • The output is set at 640x480, does your monitor support this resolution?
    • In your python code, you are suing cv2.waitkey(1) function. Did you try this function in a separate test script to make sure that it actually work? The method I used to connect a hardware keyboard to the EVM is evdev. You can also try the input() method if you are trying to use a keyboard from the host computer.

    My suggestion is to test the model first without any custom post process. I see that your model is for classification task. I suggest to edit the example at config/image_classification.yaml to test your model.

    You can use GST_DEBUG=2 to print more details about what went wrong in the pipeline. For instance you can use:

    GST_DEBUG=2 ./app_edgeai.py ../configs/image_classification.yaml -n

    The -n at the end is to disable the performance statistics on the terminal. 

    Please let me know what you find.

    Best regards,

    Qutaiba

  • Hello, 

    I figured out what issue I was having, in gst_wrapper.py the dsp and dcc files being used on line 644 and 1304 were : 

    "/opt/imaging/%s/linear/dcc_viss.bin" , "/opt/imaging/%s/linear/dcc_2a.bin"

    whereas for 640x480 resolutions, the files that should we used are : 

    "/opt/imaging/%s/linear/dcc_viss_10b_640x480.bin" and "/opt/imaging/%s/linear/dcc_2a_10b_640x480.bin"

    This solved the error, but now the output stream I am seeing on my screen seems distorted and colours seem incorrect(very green/purple) and the resolution still seems to be 1920x1080 dimension and I am unable to resolve that, could you please help me with that? Thank you 

  • Hi Pragya,

    Would you please share terminal output when running with "-n" option? 

    Aside from this color issue, does the model work fine?

    Best regards,

    Qutaiba

  • Hello, here is the terminal output: 

    (venv) root@am62axx-evm:/opt/edgeai-gst-apps-anomaly-detection/apps_python# GST_DEBUG=2 python ./app_edgeai.py ../configs/anomaly_detection.yaml -n
    
     Number of subgraphs:1 , 24 nodes delegated out of 24 nodes
    
    APP: Init ... !!!
    MEM: Init ... !!!
    MEM: Initialized DMA HEAP (fd=6) !!!
    MEM: Init ... Done !!!
    IPC: Init ... !!!
    IPC: Init ... Done !!!
    REMOTE_SERVICE: Init ... !!!
    REMOTE_SERVICE: Init ... Done !!!
      4056.446834 s: GTC Frequency = 200 MHz
    APP: Init ... Done !!!
      4056.446957 s:  VX_ZONE_INIT:Enabled
      4056.446976 s:  VX_ZONE_ERROR:Enabled
      4056.446986 s:  VX_ZONE_WARNING:Enabled
      4056.448450 s:  VX_ZONE_INIT:[tivxInitLocal:130] Initialization Done !!!
      4056.448732 s:  VX_ZONE_INIT:[tivxHostInitLocal:101] Initialization Done for HOST !!!
    0:00:01.613211890  2101     0x26815c60 WARN                 v4l2src gstv4l2src.c:814:gst_v4l2src_query:<source0> Can't give latency since framerate isn't fixated !
    0:00:01.613380195  2101     0x26815c60 WARN              aggregator gstaggregator.c:2104:gst_aggregator_query_latency_unlocked:<tiovxisp0> Latency query failed
    0:00:01.613637735  2101     0x26815c60 WARN                 v4l2src gstv4l2src.c:814:gst_v4l2src_query:<source0> Can't give latency since framerate isn't fixated !
    0:00:01.613735035  2101     0x26815c60 WARN              aggregator gstaggregator.c:2104:gst_aggregator_query_latency_unlocked:<tiovxisp0> Latency query failed
    0:00:01.615398350  2101     0x26815c60 WARN              video-info video-info.c:191:validate_colorimetry: color matrix RGB is only supported with RGB format, ENCODED is not
    0:00:01.615473925  2101     0x26815c60 WARN              video-info video-info.c:515:gst_video_info_from_caps: invalid colorimetry, using default
    0:00:01.616115175  2101     0x26815c60 WARN                 v4l2src gstv4l2src.c:814:gst_v4l2src_query:<source0> Can't give latency since framerate isn't fixated !
    0:00:01.616181655  2101 0xffff8c009520 WARN              video-info video-info.c:191:validate_colorimetry: color matrix RGB is only supported with RGB format, ENCODED is not
    0:00:01.616196985  2101     0x26815c60 WARN              aggregator gstaggregator.c:2104:gst_aggregator_query_latency_unlocked:<tiovxisp0> Latency query failed
    0:00:01.616225660  2101 0xffff8c009520 WARN              video-info video-info.c:515:gst_video_info_from_caps: invalid colorimetry, using default
    0:00:01.616317665  2101 0xffff8c009520 WARN              video-info video-info.c:191:validate_colorimetry: color matrix RGB is only supported with RGB format, ENCODED is not
    0:00:01.616346640  2101 0xffff8c009520 WARN              video-info video-info.c:515:gst_video_info_from_caps: invalid colorimetry, using default
    ==========[INPUT PIPELINE(S)]==========
    
    0:00:01.616968635  2101 0xffff8c009520 WARN              video-info video-info.c:191:validate_colorimetry: color matrix RGB is only supported with RGB format, ENCODED is not
    0:00:01.617023955  2101 0xffff8c009520 WARN              video-info video-info.c:515:gst_video_info_from_caps: invalid colorimetry, using default
    0:00:01.617138360  2101 0xffff8c009520 WARN              video-info video-info.c:191:validate_colorimetry: color matrix RGB is only supported with RGB format, ENCODED is not
    0:00:01.617169890  2101 0xffff8c009520 WARN              video-info video-info.c:515:gst_video_info_from_caps: invalid colorimetry, using default
    0:00:01.617234725  2101 0xffff8c009520 WARN              video-info video-info.c:191:validate_colorimetry: color matrix RGB is only supported with RGB format, ENCODED is not
    0:00:01.617263410  2101 0xffff8c009520 WARN              video-info video-info.c:515:gst_video_info_from_caps: invalid colorimetry, using default
    0:00:01.621072415  2101     0x27490150 WARN                    v4l2 v4l2_calls.c:929:gst_v4l2_get_attribute:<source0:src> Failed to get value for control 9963776 on device '/dev/video3'.
    0:00:01.621310525  2101     0x27490150 WARN                    v4l2 v4l2_calls.c:929:gst_v4l2_get_attribute:<source0:src> Failed to get value for control 9963777 on device '/dev/video3'.
    0:00:01.621440425  2101     0x27490150 WARN                    v4l2 v4l2_calls.c:929:gst_v4l2_get_attribute:<source0:src> Failed to get value for control 9963778 on device '/dev/video3'.
    0:00:01.621564630  2101     0x27490150 WARN                    v4l2 v4l2_calls.c:929:gst_v4l2_get_attribute:<source0:src> Failed to get value for control 9963779 on device '/dev/video3'.
    0:00:01.697565895  2101 0xffff8c009520 WARN          v4l2bufferpool gstv4l2bufferpool.c:1397:gst_v4l2_buffer_pool_dqbuf:<source0:pool0:src> Driver should never set v4l2_buffer.field to ANY
    0:00:01.976961865  2101     0x26815c60 WARN              video-info video-info.c:191:validate_colorimetry: color matrix RGB is only supported with RGB format, ENCODED is not
    0:00:01.977053265  2101     0x26815c60 WARN              video-info video-info.c:515:gst_video_info_from_caps: invalid colorimetry, using default
    0:00:02.055998070  2101 0xffff7c004180 WARN                  appsrc gstappsrc.c:2534:gst_app_src_push_internal:<post_0> do-timestamp=TRUE but buffers are provided before reaching the PLAYING state and having a clock. Timestamps will not be accurate!
    [PIPE-0]
    
    v4l2src device=/dev/video3 io-mode=5 pixel-aspect-ratio=None ! queue leaky=2 ! capsfilter caps="video/x-bayer, width=(int)640, height=(int)480, format=(string)rggb;" ! tiovxisp dcc-isp-file=/opt/imaging/imx219/linear/dcc_viss_640x480.bin sensor-name=SENSOR_SONY_IMX219_RPI format-msb=9 ! capsfilter caps="video/x-raw, format=(string)NV12;" ! tiovxmultiscaler name=split_01
    split_01. ! queue ! capsfilter caps="video/x-raw, width=(int)640, height=(int)480;" ! tiovxdlcolorconvert out-pool-size=4 ! capsfilter caps="video/x-raw, format=(string)RGB;" ! appsink max-buffers=2 drop=True name=sen_0
    split_01. ! queue ! capsfilter caps="video/x-raw, width=(int)368, height=(int)288;" ! tiovxmultiscaler target=1 ! capsfilter caps="video/x-raw, width=(int)96, height=(int)96;" ! tiovxdlpreproc out-pool-size=4 channel-order=1 ! capsfilter caps="application/x-tensor-tiovx;" ! appsink max-buffers=2 drop=True name=pre_0
    
    
    ==========[OUTPUT PIPELINE]==========
    
    0:00:02.064797235  2101     0x26815f60 WARN             tiovxmosaic gsttiovxmosaic.c:720:gst_tiovx_mosaic_check_dimension:<mosaic_0> Pad width: -1 is larger than input width: 640, setting input width
    0:00:02.064932340  2101     0x26815f60 WARN             tiovxmosaic gsttiovxmosaic.c:720:gst_tiovx_mosaic_check_dimension:<mosaic_0> Pad height: -1 is larger than input height: 480, setting input height
    0:00:02.064982930  2101     0x26815f60 WARN             tiovxmosaic gsttiovxmosaic.c:720:gst_tiovx_mosaic_check_dimension:<mosaic_0> Pad width: -1 is larger than input width: 640, setting input width
    0:00:02.065025215  2101     0x26815f60 WARN             tiovxmosaic gsttiovxmosaic.c:720:gst_tiovx_mosaic_check_dimension:<mosaic_0> Pad height: -1 is larger than input height: 480, setting input height
    0:00:02.065066555  2101     0x26815f60 WARN             tiovxmosaic gsttiovxmosaic.c:720:gst_tiovx_mosaic_check_dimension:<mosaic_0> Pad width: -1 is larger than input width: 640, setting input width
    0:00:02.065108215  2101     0x26815f60 WARN             tiovxmosaic gsttiovxmosaic.c:720:gst_tiovx_mosaic_check_dimension:<mosaic_0> Pad height: -1 is larger than input height: 480, setting input height
    0:00:02.065149365  2101     0x26815f60 WARN             tiovxmosaic gsttiovxmosaic.c:720:gst_tiovx_mosaic_check_dimension:<mosaic_0> Pad width: -1 is larger than input width: 640, setting input width
    0:00:02.065211155  2101     0x26815f60 WARN             tiovxmosaic gsttiovxmosaic.c:720:gst_tiovx_mosaic_check_dimension:<mosaic_0> Pad height: -1 is larger than input height: 480, setting input height
    0:00:02.065253620  2101     0x26815f60 WARN             tiovxmosaic gsttiovxmosaic.c:720:gst_tiovx_mosaic_check_dimension:<mosaic_0> Pad width: -1 is larger than input width: 640, setting input width
    0:00:02.065294730  2101     0x26815f60 WARN             tiovxmosaic gsttiovxmosaic.c:720:gst_tiovx_mosaic_check_dimension:<mosaic_0> Pad height: -1 is larger than input height: 480, setting input height
    0:00:02.065335815  2101     0x26815f60 WARN             tiovxmosaic gsttiovxmosaic.c:720:gst_tiovx_mosaic_check_dimension:<mosaic_0> Pad width: -1 is larger than input width: 640, setting input width
    0:00:02.065376635  2101     0x26815f60 WARN             tiovxmosaic gsttiovxmosaic.c:720:gst_tiovx_mosaic_check_dimension:<mosaic_0> Pad height: -1 is larger than input height: 480, setting input height
    0:00:02.065417595  2101     0x26815f60 WARN             tiovxmosaic gsttiovxmosaic.c:720:gst_tiovx_mosaic_check_dimension:<mosaic_0> Pad width: -1 is larger than input width: 640, setting input width
    0:00:02.076151985  2101 0xffff7c004180 WARN                  appsrc gstappsrc.c:2534:gst_app_src_push_internal:<post_0> do-timestamp=TRUE but buffers are provided before reaching the PLAYING state and having a clock. Timestamps will not be accurate!
    0:00:02.395995455  2101     0x26815f60 WARN             tiovxmosaic gsttiovxmosaic.c:720:gst_tiovx_mosaic_check_dimension:<mosaic_0> Pad height: -1 is larger than input height: 480, setting input height
    0:00:02.396150885  2101     0x26815f60 WARN             tiovxmosaic gsttiovxmosaic.c:720:gst_tiovx_mosaic_check_dimension:<mosaic_0> Pad width: -1 is larger than input width: 640, setting input width
    0:00:02.396271645  2101     0x26815f60 WARN             tiovxmosaic gsttiovxmosaic.c:720:gst_tiovx_mosaic_check_dimension:<mosaic_0> Pad height: -1 is larger than input height: 480, setting input height
    0:00:02.396381325  2101     0x26815f60 WARN             tiovxmosaic gsttiovxmosaic.c:720:gst_tiovx_mosaic_check_dimension:<mosaic_0> Pad width: -1 is larger than input width: 640, setting input width
    0:00:02.396486335  2101     0x26815f60 WARN             tiovxmosaic gsttiovxmosaic.c:720:gst_tiovx_mosaic_check_dimension:<mosaic_0> Pad height: -1 is larger than input height: 480, setting input height
    0:00:02.396591640  2101     0x26815f60 WARN             tiovxmosaic gsttiovxmosaic.c:720:gst_tiovx_mosaic_check_dimension:<mosaic_0> Pad width: -1 is larger than input width: 640, setting input width
    0:00:02.396695865  2101     0x26815f60 WARN             tiovxmosaic gsttiovxmosaic.c:720:gst_tiovx_mosaic_check_dimension:<mosaic_0> Pad height: -1 is larger than input height: 480, setting input height
    0:00:02.396800800  2101     0x26815f60 WARN             tiovxmosaic gsttiovxmosaic.c:720:gst_tiovx_mosaic_check_dimension:<mosaic_0> Pad width: -1 is larger than input width: 640, setting input width
    0:00:02.396903980  2101     0x26815f60 WARN             tiovxmosaic gsttiovxmosaic.c:720:gst_tiovx_mosaic_check_dimension:<mosaic_0> Pad height: -1 is larger than input height: 480, setting input height
    0:00:02.397007805  2101     0x26815f60 WARN             tiovxmosaic gsttiovxmosaic.c:720:gst_tiovx_mosaic_check_dimension:<mosaic_0> Pad width: -1 is larger than input width: 640, setting input width
    0:00:02.397112040  2101     0x26815f60 WARN             tiovxmosaic gsttiovxmosaic.c:720:gst_tiovx_mosaic_check_dimension:<mosaic_0> Pad height: -1 is larger than input height: 480, setting input height
    0:00:02.397216045  2101     0x26815f60 WARN             tiovxmosaic gsttiovxmosaic.c:720:gst_tiovx_mosaic_check_dimension:<mosaic_0> Pad width: -1 is larger than input width: 640, setting input width
    0:00:02.397320045  2101     0x26815f60 WARN             tiovxmosaic gsttiovxmosaic.c:720:gst_tiovx_mosaic_check_dimension:<mosaic_0> Pad height: -1 is larger than input height: 480, setting input height
    0:00:02.397427120  2101     0x26815f60 WARN             tiovxmosaic gsttiovxmosaic.c:720:gst_tiovx_mosaic_check_dimension:<mosaic_0> Pad width: -1 is larger than input width: 640, setting input width
    0:00:02.397530660  2101     0x26815f60 WARN             tiovxmosaic gsttiovxmosaic.c:720:gst_tiovx_mosaic_check_dimension:<mosaic_0> Pad height: -1 is larger than input height: 480, setting input height
    0:00:02.409206520  2101 0xffff7c004180 WARN                  appsrc gstappsrc.c:2534:gst_app_src_push_internal:<post_0> do-timestamp=TRUE but buffers are provided before reaching the PLAYING state and having a clock. Timestamps will not be accurate!
    0:00:02.730157805  2101     0x26815f60 WARN             tiovxmosaic gsttiovxmosaic.c:720:gst_tiovx_mosaic_check_dimension:<mosaic_0> Pad width: -1 is larger than input width: 640, setting input width
    0:00:02.730382935  2101     0x26815f60 WARN             tiovxmosaic gsttiovxmosaic.c:720:gst_tiovx_mosaic_check_dimension:<mosaic_0> Pad height: -1 is larger than input height: 480, setting input height
    appsrc do-timestamp=True format=3 block=True name=post_0 ! tiovxdlcolorconvert ! capsfilter caps="video/x-raw, format=(string)NV12, width=(int)640, height=(int)480;" ! queue ! mosaic_0.sink_0
    
    0:00:02.769778185  2101 0xffff7c004180 WARN                  appsrc gstappsrc.c:2534:gst_app_src_push_internal:<post_0> do-timestamp=TRUE but buffers are provided before reaching the PLAYING state and having a clock. Timestamps will not be accurate!
    tiovxmosaic target=1 background=/tmp/background_0 name=mosaic_0 src::pool-size=4
    sink_0::startx="<0>" sink_0::starty="<0>" sink_0::widths="<640>" sink_0::heights="<480>"
    ! capsfilter caps="video/x-raw, format=(string)NV12, width=(int)640, height=(int)480;" ! queue ! tiperfoverlay title=Anomaly Detection ! kmssink sync=False max-lateness=5000000 qos=True processing-deadline=15000000 driver-name=tidss connector-id=40 plane-id=31 force-modesetting=True
    
    0:00:02.781042960  2101 0xffff7c004180 WARN                  appsrc gstappsrc.c:2534:gst_app_src_push_internal:<post_0> do-timestamp=TRUE but buffers are provided before reaching the PLAYING state and having a clock. Timestamps will not be accurate!
    0:00:02.908970845  2101     0x26815f00 WARN            kmsallocator gstkmsallocator.c:553:gst_kms_allocator_dmabuf_import:<KMSMemory::allocator> Failed to close GEM handle: Invalid argument 22
    0:00:02.934420125  2101     0x26815f00 WARN            kmsallocator gstkmsallocator.c:553:gst_kms_allocator_dmabuf_import:<KMSMemory::allocator> Failed to close GEM handle: Invalid argument 22
    0:00:02.948359030  2101     0x26815f00 WARN            kmsallocator gstkmsallocator.c:553:gst_kms_allocator_dmabuf_import:<KMSMemory::allocator> Failed to close GEM handle: Invalid argument 22
    0:00:02.960857240  2101     0x26815f00 WARN            kmsallocator gstkmsallocator.c:553:gst_kms_allocator_dmabuf_import:<KMSMemory::allocator> Failed to close GEM handle: Invalid argument 22
    ^C0:00:21.105987410  2101     0x26815cc0 WARN               tiovxsimo gsttiovxsimo.c:1381:gst_tiovx_simo_push_buffers:<tiovxmultiscaler2> Error pushing to pad: <tiovxmultiscaler2:src_0>
    



    and yes other than that the model works fine 

  • Hi Pragya,

    I see you are using the 10 bits format for the .bin files in gst_wrapper. I suggest to use "/opt/imaging/%s/linear/dcc_viss_640x480.bin" and "/opt/imaging/%s/linear/dcc_2a_640x480.bin" instead. 

    Also edit the file at edgeai-gst-apps/script/setup_cameras.sh line 36 https://github.com/TexasInstruments/edgeai-gst-apps/blob/main/scripts/setup_cameras.sh#L36, use IMX219_CAM_FMT="${IMX219_CAM_FMT:-[fmt:SRGGB8_1X8/640x480]}". Run this script before running running the edge AI app. 

    I just tried it and it worked on my side. 

    Best regards,

    Qutaiba

  • Hello, thank you for your help, now the script works well on 640x480 resolution. 

    But now when I try to run it on 1920x1080 then I get the following error: 

    ==========[INPUT PIPELINE(S)]==========
    
    
    ** (python:1498): CRITICAL **: 11:25:01.438: gst_tiovx_multi_scaler_fixate_caps: assertion 'src_caps_list' failed
    
    ** (python:1498): CRITICAL **: 11:25:01.456: gst_tiovx_multi_scaler_fixate_caps: assertion 'src_caps_list' failed
    
    ** (python:1498): CRITICAL **: 11:25:01.479: gst_tiovx_multi_scaler_fixate_caps: assertion 'src_caps_list' failed
    
    ** (python:1498): CRITICAL **: 11:25:01.493: gst_tiovx_multi_scaler_fixate_caps: assertion 'src_caps_list' failed
    [ERROR] Error pulling tensor from GST Pipeline
    


    1. I changed gst_wrapper.py to set width and height to 1920x1080 and also changed files to "/opt/imaging/%s/linear/dcc_viss.bin" , "/opt/imaging/%s/linear/dcc_2a.bin".

    2. I also changed my yaml file to have the same height and width and format as rggb. 

    3. I also changed the setup_cameras.sh file back to this [fmt:SRGGB8_1X8/1920x1080]

  • Hi Pragya,

    Your model has too small input of 96x96 compared to the 1920x1080 resolution of the camera. This will require several down scaling cycles on the frame. I am checking to see if the edgeai-gst-apps can generate the pipeline for such extreme use case. Meanwhile, you can update the resize property in the param.yaml file to be 256 instead of 96 while keeping the crop property to 96. The generated pipeline will work fine. In this solution, the frame will be scaled down to 256 and then the middle 96x96 area is cropped. 

    Best regards,

    Qutaiba

  • Hi, 

    I tried setting resize to 256 but that didn't solve the problem. I am still getting the same error. 

  • Hi Pragya,

    The edgeai-gst-apps is not design to prepare a gstreamer pipeline to scale the frame from 1920x1080 to 96x96. This require several downscaling cycles. The hardware can sill do it but the software is not prepared for such use case. You can either create your own pipeline or update the software for edgeai-gst-apps. 

    Now as a work around you can scale down to 256 and then crop to 96x96. This in theory should work. To help you better would you please share your param.yaml file and also the entire terminal print out when you tried running the example. 

    If possible, you can share the model artifacts to try it at my end but expect some delay until I am able to run it. 

    Best regards,

    Qutaiba