High CPU usage for a (mostly) simple flow

So, this is my flow:

[
    {
        "id": "b7765500.4889a8",
        "type": "subflow",
        "name": "Iterate",
        "in": [
            {
                "x": 220,
                "y": 219,
                "wires": [
                    {
                        "id": "a1ad0c48.5e52f"
                    }
                ]
            }
        ],
        "out": [
            {
                "x": 454,
                "y": 174,
                "wires": [
                    {
                        "id": "a1ad0c48.5e52f",
                        "port": 0
                    }
                ]
            },
            {
                "x": 455,
                "y": 259,
                "wires": [
                    {
                        "id": "a1ad0c48.5e52f",
                        "port": 1
                    }
                ]
            }
        ]
    },
    {
        "id": "a1ad0c48.5e52f",
        "type": "function",
        "z": "b7765500.4889a8",
        "name": "Iterate",
        "func": "//Node has 2 outputs - 1 for itteration and 1 for completion\nvar nextObj, out;\nvar itt = msg.iterationInfo;\n\n\n//If the iterating has not yet begun set up the iteration metadata in the msg\nif (typeof itt === 'undefined') {\n    //Make sure payload is an array\n    if( Object.prototype.toString.call(msg.payload) !== '[object Array]' ) {\n       msg.payload = [msg.payload];\n    }\n\n    msg.iterationInfo = itt = {};\n    itt.index = -1;\n    itt.inArray = msg.payload;\n    itt.outArray = [];\n\n//Otherwise just push the input to the output array\n} else {\n    itt.outArray.push(msg.payload)\n}\n\n//Goto next object\nitt.index ++;\n\n//If there are stil objects left to iterate goto the next one in the original array\nif (itt.index < itt.inArray.length) {\n    nextObj = msg;\n    msg.payload = itt.inArray[itt.index];\n\n//otherwise pass the out array as the payload\n} else {\n    out = msg;\n    msg.payload = itt.outArray;\n    delete msg.iterationInfo;\n}\n\nreturn [nextObj, out];",
        "outputs": "2",
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 347,
        "y": 220,
        "wires": [
            [],
            []
        ]
    },
    {
        "id": "948c48ca73f5065d",
        "type": "tab",
        "label": "CCTV Deepstack",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "4636310187a53d46",
        "type": "deepstack-object-detection",
        "z": "948c48ca73f5065d",
        "name": "",
        "server": "02ee2a12bd79fd30",
        "confidence": "60",
        "drawPredictions": true,
        "outlineColor": "red",
        "custom": "",
        "filters": [
            "person"
        ],
        "outputs": 2,
        "x": 610,
        "y": 320,
        "wires": [
            [
                "03072dc93ca0f941"
            ],
            [
                "b0f493e52b54d1a2"
            ]
        ]
    },
    {
        "id": "38fa0fd501d4be02",
        "type": "link in",
        "z": "948c48ca73f5065d",
        "name": "Object Flow",
        "links": [
            "0efcd91ce5a34d88",
            "f357dd794b4c7f3d",
            "b0f493e52b54d1a2"
        ],
        "x": 75,
        "y": 440,
        "wires": [
            [
                "c413614ccf0d9fac",
                "e424ceef1a53a61f"
            ]
        ]
    },
    {
        "id": "bc5025dc4fbbf62b",
        "type": "comment",
        "z": "948c48ca73f5065d",
        "name": "Object Flow",
        "info": "",
        "x": 130,
        "y": 400,
        "wires": []
    },
    {
        "id": "03072dc93ca0f941",
        "type": "debug",
        "z": "948c48ca73f5065d",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 770,
        "y": 300,
        "wires": []
    },
    {
        "id": "b0f493e52b54d1a2",
        "type": "link out",
        "z": "948c48ca73f5065d",
        "name": "",
        "mode": "link",
        "links": [
            "38fa0fd501d4be02"
        ],
        "x": 755,
        "y": 340,
        "wires": []
    },
    {
        "id": "7878167172d9a67a",
        "type": "change",
        "z": "948c48ca73f5065d",
        "name": "Latest Filename",
        "rules": [
            {
                "t": "set",
                "p": "filename",
                "pt": "msg",
                "to": "/images/objects/front_door-object-latest.jpg",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 580,
        "y": 480,
        "wires": [
            [
                "ebc3d0719cfb1403",
                "f81455b05c7ef915"
            ]
        ]
    },
    {
        "id": "e424ceef1a53a61f",
        "type": "debug",
        "z": "948c48ca73f5065d",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 190,
        "y": 480,
        "wires": []
    },
    {
        "id": "c413614ccf0d9fac",
        "type": "subflow:b7765500.4889a8",
        "z": "948c48ca73f5065d",
        "name": "Iterate",
        "x": 190,
        "y": 440,
        "wires": [
            [
                "bd60cdfa85a3df7e"
            ],
            [
                "896cd41acb74c5a6"
            ]
        ]
    },
    {
        "id": "bd60cdfa85a3df7e",
        "type": "function",
        "z": "948c48ca73f5065d",
        "name": "Text Position",
        "func": "msg.payload.text_y = msg.payload.y_min - 18;\nmsg.payload.text = msg.payload.label + \": \" + msg.payload.confidence;\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 350,
        "y": 400,
        "wires": [
            [
                "0396dbd6456358ea"
            ]
        ]
    },
    {
        "id": "0396dbd6456358ea",
        "type": "jimp-image",
        "z": "948c48ca73f5065d",
        "name": "",
        "data": "outlinedImage",
        "dataType": "msg",
        "ret": "img",
        "parameter1": "FONT_SANS_16_WHITE",
        "parameter1Type": "jimpFont",
        "parameter2": "payload.x_min",
        "parameter2Type": "msg",
        "parameter3": "payload.text_y",
        "parameter3Type": "msg",
        "parameter4": "payload.text",
        "parameter4Type": "msg",
        "parameter5": "",
        "parameter5Type": "none",
        "parameter6": "",
        "parameter6Type": "none",
        "parameter7": "",
        "parameter7Type": "msg",
        "parameter8": "",
        "parameter8Type": "msg",
        "sendProperty": "outlinedImage",
        "sendPropertyType": "msg",
        "parameterCount": 6,
        "jimpFunction": "print",
        "selectedJimpFunction": {
            "name": "print",
            "fn": "print",
            "description": "Print text to the image",
            "parameters": [
                {
                    "name": "font|str",
                    "type": "jimpFont",
                    "required": true,
                    "hint": "font to print. NOTE: This can be one of the presets or the path to a fnt file"
                },
                {
                    "name": "x",
                    "type": "num",
                    "required": true,
                    "hint": "x coordinate to print text"
                },
                {
                    "name": "y",
                    "type": "num",
                    "required": true,
                    "hint": "y coordinate to print text"
                },
                {
                    "name": "text",
                    "type": "str",
                    "required": true,
                    "hint": "text to print"
                },
                {
                    "name": "maxWidth",
                    "type": "num",
                    "required": false,
                    "hint": "wrap text at maxWidth"
                },
                {
                    "name": "maxHeight",
                    "type": "num",
                    "required": false,
                    "hint": "max height"
                }
            ]
        },
        "x": 550,
        "y": 400,
        "wires": [
            [
                "c413614ccf0d9fac"
            ]
        ]
    },
    {
        "id": "87a08e71ff80198b",
        "type": "moment",
        "z": "948c48ca73f5065d",
        "name": "Date Filename",
        "topic": "",
        "input": "",
        "inputType": "date",
        "inTz": "Australia/Melbourne",
        "adjAmount": 0,
        "adjType": "days",
        "adjDir": "add",
        "format": "[/images/objects/front_door/]YYYY-MM-DD[/]HH-mm-ss[.jpg]",
        "locale": "en-US",
        "output": "dated_filename",
        "outputType": "msg",
        "outTz": "Australia/Melbourne",
        "x": 400,
        "y": 320,
        "wires": [
            [
                "4636310187a53d46"
            ]
        ]
    },
    {
        "id": "ddf86c4a672a44a9",
        "type": "catch",
        "z": "948c48ca73f5065d",
        "name": "",
        "scope": null,
        "uncaught": false,
        "x": 120,
        "y": 740,
        "wires": [
            [
                "db2d13b6ea2b3fb4"
            ]
        ]
    },
    {
        "id": "db2d13b6ea2b3fb4",
        "type": "debug",
        "z": "948c48ca73f5065d",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": true,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 270,
        "y": 740,
        "wires": []
    },
    {
        "id": "9ece4f46ee6a8301",
        "type": "comment",
        "z": "948c48ca73f5065d",
        "name": "Error Trap",
        "info": "",
        "x": 120,
        "y": 700,
        "wires": []
    },
    {
        "id": "8efae47685320e2f",
        "type": "comment",
        "z": "948c48ca73f5065d",
        "name": "Submit images to Deepstack",
        "info": "",
        "x": 180,
        "y": 280,
        "wires": []
    },
    {
        "id": "df6679c2f4b9d408",
        "type": "link in",
        "z": "948c48ca73f5065d",
        "name": "",
        "links": [
            "35f07af40d428e32",
            "abdc0c9478ce9a61",
            "73c8475e16c7367d"
        ],
        "x": 75,
        "y": 320,
        "wires": [
            [
                "9821b8430a1ff713"
            ]
        ]
    },
    {
        "id": "b08206ecc54d559e",
        "type": "http in",
        "z": "948c48ca73f5065d",
        "name": "",
        "url": "/motion/1/on",
        "method": "get",
        "upload": false,
        "swaggerDoc": "",
        "x": 360,
        "y": 100,
        "wires": [
            [
                "dc17ee9e25f0ca23",
                "a33e582b2fd7bdd5"
            ]
        ]
    },
    {
        "id": "c5dd4cbf8b0ecde9",
        "type": "http in",
        "z": "948c48ca73f5065d",
        "name": "",
        "url": "/motion/1/off",
        "method": "get",
        "upload": false,
        "swaggerDoc": "",
        "x": 360,
        "y": 180,
        "wires": [
            [
                "fc29b24763469e63",
                "a33e582b2fd7bdd5"
            ]
        ]
    },
    {
        "id": "dc17ee9e25f0ca23",
        "type": "delay",
        "z": "948c48ca73f5065d",
        "name": "",
        "pauseType": "rate",
        "timeout": "1000",
        "timeoutUnits": "milliseconds",
        "rate": "1",
        "nbRateUnits": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": false,
        "allowrate": false,
        "outputs": 1,
        "x": 730,
        "y": 100,
        "wires": [
            [
                "73c8475e16c7367d"
            ]
        ]
    },
    {
        "id": "fc29b24763469e63",
        "type": "change",
        "z": "948c48ca73f5065d",
        "name": "Reset",
        "rules": [
            {
                "t": "set",
                "p": "reset",
                "pt": "msg",
                "to": "true",
                "tot": "bool"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 530,
        "y": 180,
        "wires": [
            [
                "dc17ee9e25f0ca23"
            ]
        ]
    },
    {
        "id": "73c8475e16c7367d",
        "type": "link out",
        "z": "948c48ca73f5065d",
        "name": "",
        "mode": "link",
        "links": [
            "c2142aeec86fe8da",
            "df6679c2f4b9d408"
        ],
        "x": 865,
        "y": 100,
        "wires": []
    },
    {
        "id": "c2142aeec86fe8da",
        "type": "link in",
        "z": "948c48ca73f5065d",
        "name": "",
        "links": [
            "73c8475e16c7367d",
            "5a836a6db8d7aa01",
            "4722d084c89bf256"
        ],
        "x": 565,
        "y": 60,
        "wires": [
            [
                "dc17ee9e25f0ca23"
            ]
        ]
    },
    {
        "id": "a33e582b2fd7bdd5",
        "type": "http response",
        "z": "948c48ca73f5065d",
        "name": "",
        "statusCode": "200",
        "headers": {},
        "x": 540,
        "y": 140,
        "wires": []
    },
    {
        "id": "28f0239494f9b89f",
        "type": "inject",
        "z": "948c48ca73f5065d",
        "name": "Start",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 130,
        "y": 100,
        "wires": [
            [
                "5a836a6db8d7aa01"
            ]
        ]
    },
    {
        "id": "5a836a6db8d7aa01",
        "type": "link out",
        "z": "948c48ca73f5065d",
        "name": "",
        "mode": "link",
        "links": [
            "c2142aeec86fe8da"
        ],
        "x": 215,
        "y": 100,
        "wires": []
    },
    {
        "id": "cb648ae2317ac619",
        "type": "inject",
        "z": "948c48ca73f5065d",
        "name": "Stop",
        "props": [
            {
                "p": "reset",
                "v": "true",
                "vt": "bool"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "x": 130,
        "y": 180,
        "wires": [
            [
                "4722d084c89bf256"
            ]
        ]
    },
    {
        "id": "4722d084c89bf256",
        "type": "link out",
        "z": "948c48ca73f5065d",
        "name": "",
        "mode": "link",
        "links": [
            "6cb24101a27343b6",
            "c2142aeec86fe8da"
        ],
        "x": 215,
        "y": 180,
        "wires": []
    },
    {
        "id": "38cb4924ad7307ec",
        "type": "comment",
        "z": "948c48ca73f5065d",
        "name": "Start Loop",
        "info": "",
        "x": 120,
        "y": 60,
        "wires": []
    },
    {
        "id": "83236e8ecdaf3ef1",
        "type": "comment",
        "z": "948c48ca73f5065d",
        "name": "Stop Loop",
        "info": "",
        "x": 120,
        "y": 140,
        "wires": []
    },
    {
        "id": "9821b8430a1ff713",
        "type": "file in",
        "z": "948c48ca73f5065d",
        "name": "Load Image",
        "filename": "/tmp/cameras/lastsnap.jpg",
        "format": "",
        "chunk": false,
        "sendError": false,
        "encoding": "binary",
        "allProps": false,
        "x": 210,
        "y": 320,
        "wires": [
            [
                "87a08e71ff80198b"
            ]
        ]
    },
    {
        "id": "9d202b32f1ed69d2",
        "type": "change",
        "z": "948c48ca73f5065d",
        "name": "Set filename",
        "rules": [
            {
                "t": "move",
                "p": "dated_filename",
                "pt": "msg",
                "to": "filename",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 570,
        "y": 440,
        "wires": [
            [
                "ebc3d0719cfb1403"
            ]
        ]
    },
    {
        "id": "f81455b05c7ef915",
        "type": "debug",
        "z": "948c48ca73f5065d",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 330,
        "y": 600,
        "wires": []
    },
    {
        "id": "4a8cb383ee6e1a9c",
        "type": "comment",
        "z": "948c48ca73f5065d",
        "name": "Save File",
        "info": "",
        "x": 120,
        "y": 560,
        "wires": []
    },
    {
        "id": "fe0875afd5ec3338",
        "type": "link in",
        "z": "948c48ca73f5065d",
        "name": "",
        "links": [
            "ebc3d0719cfb1403"
        ],
        "x": 75,
        "y": 600,
        "wires": [
            [
                "ad59f18620261980"
            ]
        ]
    },
    {
        "id": "ebc3d0719cfb1403",
        "type": "link out",
        "z": "948c48ca73f5065d",
        "name": "",
        "mode": "link",
        "links": [
            "fe0875afd5ec3338"
        ],
        "x": 715,
        "y": 440,
        "wires": []
    },
    {
        "id": "ad59f18620261980",
        "type": "jimp-image",
        "z": "948c48ca73f5065d",
        "name": "",
        "data": "outlinedImage",
        "dataType": "msg",
        "ret": "img",
        "parameter1": "filename",
        "parameter1Type": "msg",
        "parameter2": "",
        "parameter2Type": "msg",
        "parameter3": "",
        "parameter3Type": "msg",
        "parameter4": "",
        "parameter4Type": "msg",
        "parameter5": "",
        "parameter5Type": "msg",
        "parameter6": "",
        "parameter6Type": "msg",
        "parameter7": "",
        "parameter7Type": "msg",
        "parameter8": "",
        "parameter8Type": "msg",
        "sendProperty": "payload",
        "sendPropertyType": "msg",
        "parameterCount": 1,
        "jimpFunction": "write",
        "selectedJimpFunction": {
            "name": "write",
            "fn": "write",
            "description": "Write to file. NOTE: You can specify an alternative file extension type to change the type. Currently support types are jpg, png, bmp.",
            "parameters": [
                {
                    "name": "filename",
                    "type": "str",
                    "required": true,
                    "hint": "Name of the file",
                    "defaultType": "str"
                }
            ]
        },
        "x": 190,
        "y": 600,
        "wires": [
            [
                "f81455b05c7ef915"
            ]
        ]
    },
    {
        "id": "896cd41acb74c5a6",
        "type": "jimp-image",
        "z": "948c48ca73f5065d",
        "name": "",
        "data": "outlinedImage",
        "dataType": "msg",
        "ret": "img",
        "parameter1": "50",
        "parameter1Type": "num",
        "parameter2": "",
        "parameter2Type": "msg",
        "parameter3": "",
        "parameter3Type": "msg",
        "parameter4": "",
        "parameter4Type": "msg",
        "parameter5": "",
        "parameter5Type": "msg",
        "parameter6": "",
        "parameter6Type": "msg",
        "parameter7": "",
        "parameter7Type": "msg",
        "parameter8": "",
        "parameter8Type": "msg",
        "sendProperty": "payload",
        "sendPropertyType": "msg",
        "parameterCount": 1,
        "jimpFunction": "quality",
        "selectedJimpFunction": {
            "name": "quality",
            "fn": "quality",
            "description": "Set the quality of the image. Useful for reducing size of image before calling the write function.",
            "parameters": [
                {
                    "name": "quality",
                    "type": "num",
                    "required": true,
                    "hint": "Quality value 1 ~ 100"
                }
            ]
        },
        "x": 330,
        "y": 440,
        "wires": [
            [
                "9d202b32f1ed69d2",
                "7878167172d9a67a"
            ]
        ]
    },
    {
        "id": "02ee2a12bd79fd30",
        "type": "deepstack-server",
        "proto": "http",
        "host": "172.31.1.246",
        "port": "5000",
        "version": "v1",
        "rejectUnauthorized": true
    }
]

I'm triggering this when my CCTV stuff detects motion - and it starts an event. The NodeRed flow will then trigger once every second, load a file from disk, throw it against Deepstack, and then tag / write the file to disk.

When looping, this seems to take up between 50-150% CPU usage on a Ryzen 7 3700X 8-Core Processor.

How would I be able to find out what is taking so much CPU usage - as this really doesn't seem like its very much work compared to the CPU utilisation that I'm seeing...

Hi @CRCinAU - welcome to the forum.

Firstly: What size are the original images /tmp/cameras/lastsnap.jpg (both image dimensions size and size on disk)?

There are quick & easy and more involved methods. I would start by adding some of these flow-timer nodes in-line with various parts of the flow (especially image processing and deepstack nodes)

Other considerations...

  1. Consider changing the start/stop loop for a simple inject (followed by a switch node to block/permit messages)
  2. Dont loop - use split and join instead
  3. Reduce branching since this will clone (potentially large objects)
  4. Consider interlocking to prevent the start loop catching up with an cycles that take more than 1 sec

The input image is:
JPEG image data, JFIF standard 1.01, aspect ratio, density 1x1, segment length 16, Exif Standard: [TIFF image data, big-endian, direntries=3, datetime=2022:06:07 18:15:29], baseline, precision 8, 2560x1920, components 3

They're about 430-500Kb in size for each file.

Output image size varies from ~350Kb to ~760Kb - depending on if the image is a night vision, or daytime image. I'm not sure why this is - and why it differs so much from the input.

The objects that come back from the Deepstack component are..... strange... and I haven't been able to fully understand it yet.

Interesting. What would this do? As the current loop I have (using the rate limit to 1/s), that should be before any real information gets into the msg packet - hence I would think rather minimal overhead? Am I missing something on this?

I'm guessing you're meaning something like this:
image

That sets / compares flow.loop_enabled and then passes it on if that value is true.

I'm confused - would this be where I split off after the 'quality' node? I've been unsure on how to write to different filenames otherwise :frowning: Essentially, this just replaces the value in msg.filename.

An image of that size will expand in memory to something like 16MB so any time there are 2 or more wires coming out of a node, it has to be cloned.

Yes, exactly. But also, you can also inhibit the inject node until the other part of your flow completes (imagine for a moment, all Deepstack & image nodes take 1.5s - eventually the looping will be flooded with messages)

Kind of. I think actually you would be far better off batching the image operations into one to avoid multiple passes. Something like...

[{"id":"38fa0fd501d4be02","type":"link in","z":"cd9631e07a7cb243","name":"Object Flow","links":["0efcd91ce5a34d88","f357dd794b4c7f3d","b0f493e52b54d1a2"],"x":205,"y":480,"wires":[["bd60cdfa85a3df7e"]]},{"id":"bc5025dc4fbbf62b","type":"comment","z":"cd9631e07a7cb243","name":"Object Flow","info":"","x":260,"y":440,"wires":[]},{"id":"bd60cdfa85a3df7e","type":"function","z":"cd9631e07a7cb243","name":"generate batch instructions","func":"\nconst detections = msg.payload\nconst batchInstructions = []\n\n//Add batch operation \"quality to 50%\"\"\nbatchInstructions.push({ \"name\": \"quality\", \"parameters\": [50] })\n\n//loop through detections and add \"print\" operations\nfor (let index = 0; index < detections.length; index++) {\n    const det = detections[index];\n    const text = det.label + \": \" + det.confidence;\n    const printInstruction = {\n        \"name\": \"print\",\n        \"parameters\": [\n            \"FONT_SANS_16_WHITE\",\n            5,\n            det.y_min - 18,\n            text,\n            null,\n            null\n        ]\n    }\n    batchInstructions.push(printInstruction)\n}\nmsg.batchInstructions = batchInstructions\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":370,"y":480,"wires":[["0396dbd6456358ea"]]},{"id":"0396dbd6456358ea","type":"jimp-image","z":"cd9631e07a7cb243","name":"","data":"outlinedImage","dataType":"msg","ret":"img","parameter1":"batchInstructions","parameter1Type":"msg","parameter2":"payload.x_min","parameter2Type":"msg","parameter3":"payload.text_y","parameter3Type":"msg","parameter4":"payload.text","parameter4Type":"msg","parameter5":"","parameter5Type":"none","parameter6":"","parameter6Type":"none","parameter7":"","parameter7Type":"msg","parameter8":"","parameter8Type":"msg","sendProperty":"outlinedImage","sendPropertyType":"msg","parameterCount":1,"jimpFunction":"batch","selectedJimpFunction":{"name":"batch","fn":"batch","description":"apply one or more functions","parameters":[{"name":"options","type":"json","required":true,"hint":"an object or an array of objects containing {\"name\" : \"function_name\", \"parameters\" : [x,y,z]}.  Refer to info on side panel}"}]},"x":580,"y":480,"wires":[["9d202b32f1ed69d2"]]},{"id":"9d202b32f1ed69d2","type":"change","z":"cd9631e07a7cb243","name":"Set filename and image","rules":[{"t":"move","p":"dated_filename","pt":"msg","to":"filename","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"outlinedImage","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":800,"y":480,"wires":[["ebc3d0719cfb1403"]]},{"id":"ebc3d0719cfb1403","type":"link out","z":"cd9631e07a7cb243","name":"","mode":"link","links":["fe0875afd5ec3338"],"x":1005,"y":480,"wires":[]}]

↑ untested - you might have to adjust the function code

EDIT: Updated flow for stoopid mistake (still untested)

Hmmmm - interesting... I was trying to figure out how to do the batch parts for image - but I didn't have any success. I see that replaces the Iterate loop....

I'm going to have to tinker with that now :slight_smile:

So, when it comes to saving what is essentially the same image at two different locations - one being a "this was the latest detection" and an archived datestamped filename, is that possible without duplicating the msg packet?

I mean, I guess I could just put a write after a write - one using msg.dated_filename (the macro that comes out to: [/images/objects/front_door/]YYYY-MM-DD[/]HH-mm-ss[.jpg]

But I guess given the other is static, it wouldn't need anything additional - that way the msg doesn't split and need to be duplicated...

In fact, would be it even easier to do it in the one function - as it really would just be two extra commands in the batch....

Hmmmmm.

On another thought - changing the loop with rate limit to the timed inject + switch, I haven't seen the node-red process take more than ~30% CPU.... I have no idea how that works - but it certainly did :slight_smile:

So, in the function, I now have:

const detections = msg.payload
const batchInstructions = []

//loop through detections and add "print" operations
for (let index = 0; index < detections.length; index++) {
    const det = detections[index];
    const text = det.label + ": " + det.confidence;
    const printInstruction = {
        "name": "print",
        "parameters": [
            "FONT_SANS_16_WHITE",
            det.x_min,
            det.y_min - 18,
            text,
            null,
            null
        ]
    }
    batchInstructions.push(printInstruction)
}

//Add batch operation "quality to 50%""
batchInstructions.push({ "name": "quality", "parameters": [50] })

// Save as latest detection
batchInstructions.push({ "name": "write", "parameters": [ "/images/objects/front_door-object-latest.jpg" ] })

// Save in the archive as well
batchInstructions.push({ "name": "write", "parameters": [ msg.dated_filename ] })

msg.batchInstructions = batchInstructions
return msg;

However, I'm getting an error of:

"TypeError: Cannot destructure property 'x' of 'undefined' as it is undefined."

The stack is:

TypeError: Cannot destructure property 'x' of 'undefined' as it is undefined.
    at Jimp.<anonymous> (/data/node_modules/node-red-contrib-image-tools/jimp.js:321:90)
    at Jimp.throwError (/data/node_modules/@jimp/utils/dist/index.js:37:15)
    at Jimp.print (/data/node_modules/@jimp/plugin-print/dist/index.js:202:36)
    at doProcess (/data/node_modules/node-red-contrib-image-tools/jimp.js:321:63)
    at imageProcessor (/data/node_modules/node-red-contrib-image-tools/jimp.js:440:57)
    at jimpNode._inputCallback (/data/node_modules/node-red-contrib-image-tools/jimp.js:584:35)

I can see the batchInstructions expands to:
image

So the x_min and y_min are being put where they are supposed to....

The batch node has an image set to msg.outlinedImage - which exists and has content in the msg - and is 326,507 in length.

Is there a trick in debugging this that would give more info as to what its actually complaining about?

Ah!! I got it! :slight_smile:

const detections = msg.payload
const batchInstructions = []

//loop through detections and add "print" operations
for (let index = 0; index < detections.length; index++) {
    const det = detections[index];
    const text = det.label + ": " + det.confidence;
    const printInstruction = {
        "name": "print",
        "parameters": [
            "FONT_SANS_16_WHITE",
            det.x_min,
            det.y_min - 18,
            text
        ]
    }
    batchInstructions.push(printInstruction)
}

//Add batch operation "quality to 50%""
batchInstructions.push({ "name": "quality", "parameters": [50] })

// Save as latest detection
batchInstructions.push({ "name": "write", "parameters": [ "/images/objects/front_door-object-latest.jpg" ] })

// Save in the archive as well
batchInstructions.push({ "name": "write", "parameters": [ msg.dated_filename ] })

msg.batchInstructions = batchInstructions
return msg;

That saves the file in both locations as well - which replaces the split and msg duplication.

When the loop is running now, I see the node-red process now only consume a maximum of 51% CPU of a single core. When its just doing the normal loop and blocking, its almost zero CPU, and when its looping - but no detections in Deepstack - then its normally low single digit CPU usage.

Compare that to the previous 50-150% of a single core and its a MASSIVE improvement.

I have to say I don't quite understand why - but I'll take it :smiley:

Use node.warn to see what values contain - one of them will be undefined

node.warn(["det.x_min", det.x_min])
node.warn(["det.y_min", det.y_min])
node.warn(["msg.dated_filename",msg.dated_filename])

It seems like it was the additional null, null on the end of the options. I did a quick look at the JIMP syntax, and most seem to call it as image.print(font, x, y, message) - so I just updated that to suit - no more error.

I also rolled in the writes to a file too - and that seems to be fine as well...

Thanks for your insight - as its certainly MUCH less CPU intensive now - I'm watching it to do a loop with no detections now in deepstak, and its using ~4-8% of a single core now.... 1/5th of what it was.

1 Like

@Steve-Mcl. Wow. I was impressed before you solved the problem. When will discourse let us +1 helpful and respectful people?

2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.