[Smart-Parking || Loitering-Detection] Grafana Table Data || Local Time Zone || Pipeline Resolution#2238
[Smart-Parking || Loitering-Detection] Grafana Table Data || Local Time Zone || Pipeline Resolution#2238
Conversation
… || Pipeline Resolution
|
|
||
| This page provides troubleshooting steps, FAQs, and resources to help you resolve common issues. | ||
|
|
||
| ## Resolving Time Sync Issues in Prometheus |
There was a problem hiding this comment.
I don't think we should add these details in support page
| https://<HOST_IP>/mediamtx/ | ||
| ``` | ||
|
|
||
| 5. **Resolving Time Sync Issues in Prometheus** |
There was a problem hiding this comment.
There is no prometheus in this app. Pls modify the instructions accordingly.
| @@ -1350,7 +1350,7 @@ | |||
| "type": "euclidean and ior", | |||
| "z": "2720733497fe05f3", | |||
| "name": "euclidean and ior 1", | |||
| "func": "let region_name = \"predefined_regions_1\";\nlet detection_name = \"object_detection_1\";\nlet previous_data_name = \"previous_data_1\";\nlet occupancy_check_duration = 60;\nlet video_id = 1;\nlet region_id = -1; //Recommend to set this only when there is 1 predefined region in the video\n\nvar payload = msg.payload;\nvar previous_data = flow.get(previous_data_name);\nvar stop_duration = flow.get(\"stop_duration\");\n\n// preparing bboxes\nfunction preprocess_bboxes(payload) {\n function getObjectData(object_data) {\n var current_object_data = {};\n if (object_data.hasOwnProperty(\"type\")) {\n current_object_data[\"type\"] = object_data[\"type\"];\n }\n if (object_data.hasOwnProperty(\"color\")) {\n current_object_data[\"color\"] = object_data[\"color\"];\n }\n if (object_data.hasOwnProperty(\"license_plate\")) {\n current_object_data[\"license_plate\"] = object_data[\"license_plate\"];\n }\n if (object_data.hasOwnProperty(\"id\")) {\n current_object_data[\"id\"] = object_data[\"id\"];\n }\n if (object_data.hasOwnProperty(\"roi_type\")) {\n current_object_data[\"roi_type\"] = object_data[\"roi_type\"];\n }\n return current_object_data;\n }\n function getLotBbox(lot_data) {\n return { \"vertex1\": lot_data.vertex1, \"vertex2\": lot_data.vertex2, \"vertex3\": lot_data.vertex3, \"vertex4\": lot_data.vertex4, \"vertex_0\": lot_data.vertex1 };\n }\n\n var results = {};\n var objects = [];\n var objects_extra = [];\n var lots = [];\n // get all objects bboxes\n for (let key in payload) {\n if (payload.hasOwnProperty(key)) {\n var objectData = getObjectData(payload[key]);\n if (objectData !== null) {\n objects_extra.push(\n objectData\n );\n objects.push(\n payload[key][\"bbox\"]\n );\n }\n }\n }\n // get all lots bboxes\n var predefined_regions = flow.get(region_name);\n var keys = Object.keys(predefined_regions);\n\n for (let i = 0; i < keys.length; i++) {\n if (predefined_regions.hasOwnProperty(keys[i]) && keys[i] != \"_msgid\") {\n lots.push(\n getLotBbox(predefined_regions[keys[i]])\n );\n }\n }\n\n results[\"objects\"] = objects;\n results[\"objects_extra\"] = objects_extra;\n results[\"lots\"] = lots;\n return results;\n}\n\n// euclidean distance and iou check\nfunction euclidean_iou_function(payload, distance_threshold = 100, intersection_type = \"region\", intersection_threshold = 0.5, object_counter = false) {\n function getBboxCentroid(bbox) {\n var centroid_x = (bbox[\"vertex1\"].x + bbox[\"vertex2\"].x + bbox[\"vertex3\"].x + bbox[\"vertex4\"].x) / 4;\n var centroid_y = (bbox[\"vertex1\"].y + bbox[\"vertex2\"].y + bbox[\"vertex3\"].y + bbox[\"vertex4\"].y) / 4;\n return [centroid_x, centroid_y];\n }\n function calculateEuclideanDistance(centroid1, centroid2) {\n return Math.sqrt((centroid2[0] - centroid1[0]) ** 2 + (centroid2[1] - centroid1[1]) ** 2);\n }\n function calculateIntersectArea(bbox1, bbox2) { // objects, lots\n var bbox1_key = Object.keys(bbox1)\n var bbox2_key = Object.keys(bbox2)\n var intersection = [];\n\n for (let i = 0; i < bbox1_key.length - 1; i++) {\n for (let j = 0; j < bbox2_key.length - 1; j++) {\n var A1 = bbox1[bbox1_key[i + 1]].y - bbox1[bbox1_key[i]].y; // Ax + By + C = 0\n var B1 = bbox1[bbox1_key[i]].x - bbox1[bbox1_key[i + 1]].x;\n var C1 = - A1 * bbox1[bbox1_key[i]].x - B1 * bbox1[bbox1_key[i]].y;\n\n var A2 = bbox2[bbox2_key[j + 1]].y - bbox2[bbox2_key[j]].y;\n var B2 = bbox2[bbox2_key[j]].x - bbox2[bbox2_key[j + 1]].x;\n var C2 = - A2 * bbox2[bbox2_key[j]].x - B2 * bbox2[bbox2_key[j]].y;\n\n // parallel lines case\n if (A1 * B2 == A2 * B1) {\n // coincide case\n if ((A1 * C2 == A2 * C1) && (B1 * C2 == B2 * C1)) {\n if (B1 == 0 && A1 == 0) { // one point bbox case\n intersection.push([bbox1[bbox1_key[i]].x.toFixed(6), bbox1[bbox1_key[i]].y.toFixed(6)]);\n }\n else if (B2 == 0 && A2 == 0) { // one point bbox case\n intersection.push([bbox2[bbox2_key[i]].x.toFixed(6), bbox2[bbox2_key[i]].y.toFixed(6)]);\n }\n else if (B1 == 0) { // vertical lines case\n var y_min1 = (bbox1[bbox1_key[i]].y < bbox1[bbox1_key[i + 1]].y) ? bbox1[bbox1_key[i]].y : bbox1[bbox1_key[i + 1]].y;\n var y_max1 = (bbox1[bbox1_key[i]].y < bbox1[bbox1_key[i + 1]].y) ? bbox1[bbox1_key[i + 1]].y : bbox1[bbox1_key[i]].y;\n var y_min2 = (bbox2[bbox2_key[i]].y < bbox2[bbox2_key[i + 1]].y) ? bbox2[bbox2_key[i]].y : bbox2[bbox2_key[i + 1]].y;\n var y_max2 = (bbox2[bbox2_key[i]].y < bbox2[bbox2_key[i + 1]].y) ? bbox2[bbox2_key[i + 1]].y : bbox2[bbox2_key[i]].y;\n if ((y_min1 < y_max2) && (y_min2 < y_max1)) {\n var y_min = (y_min1 < y_min2) ? y_min2 : y_min1;\n var y_max = (y_max1 < y_max2) ? y_max1 : y_max2;\n intersection.push([bbox1[bbox1_key[i]].x.toFixed(6), y_min.toFixed(6)]);\n intersection.push([bbox1[bbox1_key[i]].x.toFixed(6), y_max.toFixed(6)]);\n }\n }\n else if (A1 == 0) { // horizontal lines case\n var x_min1 = (bbox1[bbox1_key[i]].x < bbox1[bbox1_key[i + 1]].x) ? bbox1[bbox1_key[i]].x : bbox1[bbox1_key[i + 1]].x;\n var x_max1 = (bbox1[bbox1_key[i]].x < bbox1[bbox1_key[i + 1]].x) ? bbox1[bbox1_key[i + 1]].x : bbox1[bbox1_key[i]].x;\n var x_min2 = (bbox2[bbox2_key[i]].x < bbox2[bbox2_key[i + 1]].x) ? bbox2[bbox2_key[i]].x : bbox2[bbox2_key[i + 1]].x;\n var x_max2 = (bbox2[bbox2_key[i]].x < bbox2[bbox2_key[i + 1]].x) ? bbox2[bbox2_key[i + 1]].x : bbox2[bbox2_key[i]].x;\n if ((x_min1 < x_max2) && (x_min2 < x_max1)) {\n var x_min = (x_min1 < x_min2) ? x_min2 : x_min1;\n var x_max = (x_max1 < x_max2) ? x_max1 : x_max2;\n intersection.push([x_min.toFixed(6), bbox1[bbox1_key[i]].y.toFixed(6)]);\n intersection.push([x_max.toFixed(6), bbox1[bbox1_key[i]].y.toFixed(6)]);\n }\n }\n else {\n var x_min1 = (bbox1[bbox1_key[i]].x < bbox1[bbox1_key[i + 1]].x) ? bbox1[bbox1_key[i]].x : bbox1[bbox1_key[i + 1]].x;\n var x_max1 = (bbox1[bbox1_key[i]].x < bbox1[bbox1_key[i + 1]].x) ? bbox1[bbox1_key[i + 1]].x : bbox1[bbox1_key[i]].x;\n var x_min2 = (bbox2[bbox2_key[i]].x < bbox2[bbox2_key[i + 1]].x) ? bbox2[bbox2_key[i]].x : bbox2[bbox2_key[i + 1]].x;\n var x_max2 = (bbox2[bbox2_key[i]].x < bbox2[bbox2_key[i + 1]].x) ? bbox2[bbox2_key[i + 1]].x : bbox2[bbox2_key[i]].x;\n if ((x_min1 < x_max2) && (x_min2 < x_max1) && (y_min1 < y_max2) && (y_min2 < y_max1)) {\n var x_min = (x_min1 < x_min2) ? x_min2 : x_min1;\n var x_max = (x_max1 < x_max2) ? x_max1 : x_max2;\n var xY_min = (-A1 * x_min - C1) / B1\n var xY_max = (-A1 * x_max - C1) / B1\n intersection.push([x_min.toFixed(6), xY_min.toFixed(6)]);\n intersection.push([x_max.toFixed(6), xY_max.toFixed(6)]);\n }\n }\n }\n }\n else {\n // get intersection coordinates\n var x1 = bbox1[bbox1_key[i]].x;\n var x2 = bbox1[bbox1_key[i + 1]].x;\n var x3 = bbox2[bbox2_key[j]].x;\n var x4 = bbox2[bbox2_key[j + 1]].x;\n var y1 = bbox1[bbox1_key[i]].y;\n var y2 = bbox1[bbox1_key[i + 1]].y;\n var y3 = bbox2[bbox2_key[j]].y;\n var y4 = bbox2[bbox2_key[j + 1]].y;\n\n var den = (x2 - x1) * (y3 - y4) - (y2 - y1) * (x3 - x4);\n var t = ((x3 - x1) * (y3 - y4) - (y3 - y1) * (x3 - x4)) / den;\n var u = ((x3 - x1) * (y1 - y2) - (y3 - y1) * (x1 - x2)) / den;\n if ((t >= 0) && (t <= 1) && (u >= 0) && (u <= 1)) { // intersect happens if this condition is fulfilled\n var ix = x1 + t * (x2 - x1);\n var iy = y1 + t * (y2 - y1);\n intersection.push([ix.toFixed(6), iy.toFixed(6)]);\n }\n }\n }\n }\n // get clipped coordinates\n var specialcase1 = true;\n var specialcase2 = false;\n var temp1 = bbox1[bbox1_key[0]];\n var temp2 = bbox2[bbox2_key[0]];\n for (let i = 1; i < bbox1_key.length - 1; i++) { // special case\n if (temp1 !== bbox1[bbox1_key[i]]) {\n specialcase1 = false;\n break;\n }\n }\n for (let i = 1; i < bbox2_key.length - 1; i++) {\n if (temp2 !== bbox2[bbox2_key[i]]) {\n specialcase2 = false;\n break;\n }\n }\n if (!(specialcase2)) {\n for (let i = 0; i < bbox1_key.length - 1; i++) {\n var sign_check = [];\n for (let j = 0; j < bbox2_key.length - 1; j++) {\n var x1 = bbox2[bbox2_key[j]].x\n var x2 = bbox2[bbox2_key[j + 1]].x\n var y1 = bbox2[bbox2_key[j]].y\n var y2 = bbox2[bbox2_key[j + 1]].y\n var cross_prod = (bbox1[bbox1_key[i]].x - x1) * (y2 - y1) - (bbox1[bbox1_key[i]].y - y1) * (x2 - x1);\n var sign = (cross_prod >= 0) ? true : false;\n sign_check.push(sign);\n }\n if (sign_check.length === 4 && (sign_check.every((val, index) => val === [true, true, true, true][index]) ||\n sign_check.every((val, index) => val === [false, false, false, false][index]))) { // similar signs indicate the coordinate is within another bbox\n intersection.push([bbox1[bbox1_key[i]].x.toFixed(6), bbox1[bbox1_key[i]].y.toFixed(6)]);\n //intersection.push([bbox1[bbox1_key[i]].x, bbox1[bbox1_key[i]].y]);\n }\n }\n }\n if (!(specialcase1)) {\n for (let i = 0; i < bbox2_key.length - 1; i++) { // similar purpose but for second bbox\n var sign_check = [];\n for (let j = 0; j < bbox1_key.length - 1; j++) {\n var x1 = bbox1[bbox1_key[j]].x\n var x2 = bbox1[bbox1_key[j + 1]].x\n var y1 = bbox1[bbox1_key[j]].y\n var y2 = bbox1[bbox1_key[j + 1]].y\n var cross_prod = (bbox2[bbox2_key[i]].x - x1) * (y2 - y1) - (bbox2[bbox2_key[i]].y - y1) * (x2 - x1);\n var sign = (cross_prod >= 0) ? true : false;\n sign_check.push(sign);\n }\n if (sign_check.length === 4 && (sign_check.every((val, index) => val === [true, true, true, true][index]) ||\n sign_check.every((val, index) => val === [false, false, false, false][index]))) {\n intersection.push([bbox2[bbox2_key[i]].x.toFixed(6), bbox2[bbox2_key[i]].y.toFixed(6)]);\n //intersection.push([bbox2[bbox2_key[i]].x, bbox2[bbox2_key[i]].y]);\n }\n }\n }\n intersection = intersection.filter((item, index, self) =>\n index === self.findIndex((t) => JSON.stringify(t) === JSON.stringify(item))\n );\n // sort intersection points\n if (intersection.length > 2) {\n var intersection_angle = [];\n var intersection_distance = [];\n\n let minIndex = intersection.reduce((minIdx, currentValue, currentIndex, array) => {\n if (currentValue[0] < array[minIdx][0]) {\n return currentIndex;\n } else if (currentValue[0] === array[minIdx][0]) {\n return currentValue[1] < array[minIdx][1] ? currentIndex : minIdx;\n } else {\n return minIdx;\n }\n }, 0);\n var temp_intersection = intersection.filter((_, index) => index !== minIndex);\n for (let i = 0; i < temp_intersection.length; i++) {\n intersection_angle.push(Math.atan2(temp_intersection[i][1] - intersection[minIndex][1], temp_intersection[i][0] - intersection[minIndex][0]));\n intersection_distance.push((temp_intersection[i][1] - intersection[minIndex][1]) ** 2 + (temp_intersection[i][0] - intersection[minIndex][0]) ** 2);\n }\n let combined = temp_intersection.map((point, index) => ({ // sort intersect coordinates based on angle and then distance\n point: point,\n angle: intersection_angle[index],\n distance: intersection_distance[index]\n }));\n combined.sort((a, b) => a.angle - b.angle || a.distance - b.distance);\n let sorted_intersection = combined.map(item => item.point);\n sorted_intersection.unshift(intersection[minIndex]);\n sorted_intersection.push(intersection[minIndex]);\n // shoelace algorithm to calculate the intersect area\n var area = 0;\n for (let i = 0; i < sorted_intersection.length - 1; i++) {\n area += ((sorted_intersection[i][0] * sorted_intersection[i + 1][1])\n - (sorted_intersection[i + 1][0] * sorted_intersection[i][1]))\n }\n return area;\n }\n return 0;\n }\n function calculateIOU(bbox1, bbox2, intersectArea) {\n if (intersectArea !== 0) {\n var lot_area1 = (bbox1[\"vertex1\"].x * bbox1[\"vertex2\"].y) + (bbox1[\"vertex2\"].x * bbox1[\"vertex3\"].y)\n + (bbox1[\"vertex3\"].x * bbox1[\"vertex4\"].y) + (bbox1[\"vertex4\"].x * bbox1[\"vertex_0\"].y)\n - ((bbox1[\"vertex2\"].x * bbox1[\"vertex1\"].y) + (bbox1[\"vertex3\"].x * bbox1[\"vertex2\"].y)\n + (bbox1[\"vertex4\"].x * bbox1[\"vertex3\"].y) + (bbox1[\"vertex_0\"].x * bbox1[\"vertex4\"].y));\n\n var lot_area2 = (bbox2[\"vertex1\"].x * bbox2[\"vertex2\"].y) + (bbox2[\"vertex2\"].x * bbox2[\"vertex3\"].y)\n + (bbox2[\"vertex3\"].x * bbox2[\"vertex4\"].y) + (bbox2[\"vertex4\"].x * bbox2[\"vertex_0\"].y)\n - ((bbox2[\"vertex2\"].x * bbox2[\"vertex1\"].y) + (bbox2[\"vertex3\"].x * bbox2[\"vertex2\"].y)\n + (bbox2[\"vertex4\"].x * bbox2[\"vertex3\"].y) + (bbox2[\"vertex_0\"].x * bbox2[\"vertex4\"].y));\n return intersectArea / (lot_area1 + lot_area2 - intersectArea)\n }\n return 0;\n }\n function calculateIOR(bbox1, intersectArea) {\n if (intersectArea !== 0) {\n var lot_area = (bbox1[\"vertex1\"].x * bbox1[\"vertex2\"].y) + (bbox1[\"vertex2\"].x * bbox1[\"vertex3\"].y)\n + (bbox1[\"vertex3\"].x * bbox1[\"vertex4\"].y) + (bbox1[\"vertex4\"].x * bbox1[\"vertex_0\"].y)\n - ((bbox1[\"vertex2\"].x * bbox1[\"vertex1\"].y) + (bbox1[\"vertex3\"].x * bbox1[\"vertex2\"].y)\n + (bbox1[\"vertex4\"].x * bbox1[\"vertex3\"].y) + (bbox1[\"vertex_0\"].x * bbox1[\"vertex4\"].y));\n return intersectArea / lot_area;\n }\n return 0;\n }\n\n var occupied = [];\n var current_index = -1;\n // initialize lots to no object\n for (let key1 in payload[\"lots\"]) {\n if (payload[\"lots\"].hasOwnProperty(key1)) {\n occupied.push({ \"occupied\": 0 });\n }\n }\n for (let key1 in payload[\"objects\"]) {\n current_index++;\n if (payload[\"objects\"].hasOwnProperty(key1)) { // find all lots within the object centroid distance threshold\n var objectCentroid = getBboxCentroid(payload[\"objects\"][key1]);\n var potential_region = [];\n for (let key2 in payload[\"lots\"]) {\n if (payload[\"lots\"].hasOwnProperty(key2)) {\n var regionCentroid = getBboxCentroid(payload[\"lots\"][key2]);\n var euclideanDistance = calculateEuclideanDistance(objectCentroid, regionCentroid);\n potential_region.push(euclideanDistance);\n }\n }\n // calculate IOU or IOR\n if (object_counter) {\n for (let i = 0; i < potential_region.length; i++) {\n if (potential_region[i] < distance_threshold) {\n var intersectRegion = calculateIntersectArea(payload[\"objects\"][key1], payload[\"lots\"][i]);\n var IOR = 0;\n if (intersection_type == \"region\") {\n IOR = calculateIOR(payload[\"lots\"][i], intersectRegion)\n }\n else if (intersection_type == \"object\") {\n IOR = calculateIOR(payload[\"objects\"][key1], intersectRegion)\n }\n if (IOR > intersection_threshold) {\n occupied[i][\"occupied\"] += 1;\n var keyData = Object.keys(payload[\"objects_extra\"][current_index]);\n var numberData = keyData.length;\n for (let j = 0; j < numberData; j++) {\n if (!occupied[i][\"extra\"]) {\n occupied[i][\"extra\"] = {};\n }\n if (!occupied[i][\"extra\"][keyData[j]]) {\n occupied[i][\"extra\"][keyData[j]] = [];\n }\n occupied[i][\"extra\"][keyData[j]].push(payload[\"objects_extra\"][current_index][keyData[j]]);\n }\n }\n }\n }\n }\n else { // consider the best lot only\n var best_region_index = potential_region.reduce((minIndex, currentValue, currentIndex, array) =>\n currentValue < array[minIndex] ? currentIndex : minIndex, 0);\n if (potential_region[best_region_index] < distance_threshold) {\n var intersectRegion = calculateIntersectArea(payload[\"objects\"][key1], payload[\"lots\"][best_region_index]);\n var IOR = 0;\n if (intersection_type == \"region\") {\n IOR = calculateIOR(payload[\"lots\"][best_region_index], intersectRegion)\n }\n else if (intersection_type == \"object\") {\n IOR = calculateIOR(payload[\"objects\"][key1], intersectRegion)\n }\n if (IOR > intersection_threshold) {\n occupied[best_region_index][\"occupied\"] += 1;\n var keyData = Object.keys(payload[\"objects_extra\"][current_index]);\n var numberData = keyData.length;\n for (let i = 0; i < numberData; i++) {\n if (!occupied[best_region_index][\"extra\"]) {\n occupied[best_region_index][\"extra\"] = {};\n }\n if (!occupied[best_region_index][\"extra\"][keyData[i]]) {\n occupied[best_region_index][\"extra\"][keyData[i]] = [];\n }\n occupied[best_region_index][\"extra\"][keyData[i]].push(payload[\"objects_extra\"][current_index][keyData[i]]);\n }\n }\n }\n }\n }\n }\n return occupied;\n}\n\n// turn into correct format\nfunction postprocess_output(occupied) {\n var results = {};\n\n for (let i = 0; i < occupied.length; i++) {\n results = initializeResults(results, occupied, i);\n previous_data = initializePreviousData(results, i);\n if (results[\"Region \" + (i + 1)].hasOwnProperty(\"id\") || previous_data[\"Region \" + (i + 1)].hasOwnProperty(\"id\")) {\n results = handleObjectWithID(results, i);\n }\n else if (results[\"Region \" + (i + 1)][\"occupied\"] > 0) {\n results = handleOccupiedRegion(results, i);\n }\n else if (previous_data[\"Region \" + (i + 1)][\"entry_time\"]) {\n results = handleNotOccupiedRegion(results, i);\n }\n }\n return results;\n}\n\nfunction initializeResults(results, occupied, i) {\n const regionKey = \"Region \" + (i + 1);\n\n if (!results[regionKey]) {\n results[regionKey] = {};\n }\n results[regionKey][\"video_id\"] = video_id;\n results[regionKey][\"region_id\"] = (region_id != -1) ? region_id : i + 1;\n\n if (occupied[i].hasOwnProperty(\"occupied\")) {\n results[regionKey][\"occupied\"] = occupied[i].occupied;\n }\n\n if (occupied[i].hasOwnProperty(\"extra\")) {\n for (let key in occupied[i].extra) {\n results[regionKey][key] = occupied[i].extra[key];\n }\n }\n if (results[regionKey].hasOwnProperty(\"id\") || (previous_data && previous_data.hasOwnProperty(regionKey) && previous_data[regionKey].hasOwnProperty(\"id\"))) {\n results[regionKey][\"actual_entry_time\"] = [];\n results[regionKey][\"actual_dwell_time\"] = [];\n results[regionKey][\"entry_time\"] = [];\n results[regionKey][\"dwell_time\"] = [];\n results[regionKey][\"exit_time\"] = [];\n }\n else {\n results[\"Region \" + (i + 1)][\"actual_entry_time\"] = \"\";\n results[\"Region \" + (i + 1)][\"actual_dwell_time\"] = \"\";\n results[\"Region \" + (i + 1)][\"entry_time\"] = \"\";\n results[\"Region \" + (i + 1)][\"dwell_time\"] = \"\";\n results[\"Region \" + (i + 1)][\"exit_time\"] = \"\";\n results[\"Region \" + (i + 1)][\"occupancy_check\"] = 0;\n }\n return results;\n}\n\nfunction initializePreviousData(results, i) {\n const regionKey = \"Region \" + (i + 1);\n\n // Ensure previous_data is set up for this region.\n if (!previous_data) {\n previous_data = {};\n }\n if (results[regionKey].hasOwnProperty(\"id\")) {\n if (!previous_data[regionKey]) {\n previous_data[regionKey] = {};\n previous_data[regionKey][\"id\"] = [];\n previous_data[regionKey][\"actual_entry_time\"] = [];\n previous_data[regionKey][\"actual_dwell_time\"] = [];\n previous_data[regionKey][\"entry_time\"] = [];\n previous_data[regionKey][\"dwell_time\"] = [];\n previous_data[regionKey][\"exit_time\"] = [];\n }\n }\n else {\n if (!previous_data.hasOwnProperty(regionKey)) {\n previous_data[regionKey] = results[regionKey];\n previous_data[regionKey][\"actual_entry_time\"] = \"\";\n previous_data[regionKey][\"actual_dwell_time\"] = \"\";\n previous_data[regionKey][\"entry_time\"] = \"\";\n previous_data[regionKey][\"dwell_time\"] = \"\";\n previous_data[regionKey][\"exit_time\"] = \"\";\n previous_data[regionKey][\"occupancy_check\"] = 0;\n }\n }\n\n return previous_data;\n}\n\nfunction handleObjectWithID(results, i) {\n const regionKey = \"Region \" + (i + 1);\n const resultIds = results[regionKey][\"id\"];\n const previousDataIds = previous_data[regionKey][\"id\"];\n\n if (!resultIds && !previousDataIds) {\n return results;\n }\n\n if (resultIds) {\n for (let j = 0; j < resultIds.length; j++) {\n // Check existing id data\n let prevIndex = -1;\n\n if (previous_data[regionKey][\"id\"] && previous_data[regionKey][\"id\"].length > 0) {\n prevIndex = previous_data[regionKey][\"id\"].indexOf(resultIds[j]);\n }\n\n if (prevIndex === -1) {\n results[regionKey][\"actual_entry_time\"].push(msg.nodered_timestamp);\n results[regionKey][\"entry_time\"].push(msg.object_timestamp);\n results[regionKey][\"actual_dwell_time\"].push(\"00:00:00\");\n results[regionKey][\"dwell_time\"].push(0);\n results[regionKey][\"exit_time\"].push(\"\");\n } else {\n results[regionKey][\"actual_entry_time\"].push(previous_data[regionKey][\"actual_entry_time\"][prevIndex]);\n results[regionKey][\"entry_time\"].push(previous_data[regionKey][\"entry_time\"][prevIndex]);\n\n // Calculate dwell time.\n const dwell_timestamp = (msg.object_timestamp - results[regionKey][\"entry_time\"][j]);\n const dwell_hours = Math.floor(dwell_timestamp / 3600).toString().padStart(2, \"0\");\n const dwell_mins = Math.floor((dwell_timestamp / 60) % 60).toString().padStart(2, \"0\");\n const dwell_seconds = Math.floor(dwell_timestamp % 60).toString().padStart(2, \"0\");\n results[regionKey][\"dwell_time\"].push(dwell_timestamp);\n results[regionKey][\"actual_dwell_time\"].push(dwell_hours + \":\" + dwell_mins + \":\" + dwell_seconds);\n results[regionKey][\"exit_time\"].push(\"\");\n }\n }\n }\n\n if (previousDataIds) {\n for (let j = 0; j < previousDataIds.length; j++) {\n let prevIndex = -1;\n\n if (!results[regionKey][\"id\"]) {\n results[regionKey] = previous_data[regionKey];\n results[regionKey][\"occupied\"] = 0;\n break;\n }\n else {\n if (!results[regionKey][\"dwell_time\"].some(val => val >= stop_duration)) {\n results[regionKey][\"occupied\"] = 0;\n }\n\n prevIndex = results[regionKey][\"id\"].indexOf(previousDataIds[j]);\n if (prevIndex === -1) {\n let keyList = Object.keys(previous_data[regionKey]);\n for (let k = 0; k < keyList.length; k++) {\n if (keyList[k] == \"video_id\" || keyList[k] == \"region_id\" || keyList[k] == \"occupied\") {\n continue;\n }\n results[regionKey][keyList[k]].push(previous_data[regionKey][keyList[k]][j]);\n }\n }\n }\n }\n }\n return results;\n}\n\nfunction handleOccupiedRegion(results, i) {\n const regionKey = \"Region \" + (i + 1);\n if (previous_data[regionKey][\"entry_time\"] == \"\") {\n results[regionKey][\"actual_entry_time\"] = msg.nodered_timestamp;\n results[regionKey][\"entry_time\"] = msg.object_timestamp;\n }\n else {\n if (previous_data[regionKey][\"occupancy_check\"] >= occupancy_check_duration) {\n results[regionKey][\"actual_dwell_time\"] = \"00:00:00\";\n results[regionKey][\"dwell_time\"] = 0;\n results[regionKey][\"actual_entry_time\"] = msg.nodered_timestamp;\n results[regionKey][\"entry_time\"] = msg.object_timestamp;\n }\n else {\n results[regionKey][\"actual_entry_time\"] = previous_data[regionKey][\"actual_entry_time\"];\n results[regionKey][\"entry_time\"] = previous_data[regionKey][\"entry_time\"];\n }\n\n var dwell_timestamp = msg.object_timestamp - results[regionKey][\"entry_time\"];\n var dwell_hours = Math.floor(dwell_timestamp / 3600).toString();\n dwell_hours = dwell_hours.toString().length == 1 ? dwell_hours.toString().padStart(2, \"0\") : dwell_hours.toString();\n var dwell_mins = Math.floor((dwell_timestamp / 60) % 60).toString().padStart(2, \"0\");\n var dwell_seconds = Math.floor(dwell_timestamp % 60).toString().padStart(2, \"0\");\n\n results[regionKey][\"dwell_time\"] = dwell_timestamp;\n results[regionKey][\"actual_dwell_time\"] = dwell_hours + \":\" + dwell_mins + \":\" + dwell_seconds;\n results[regionKey][\"occupancy_check\"] = 0;\n }\n\n return results;\n}\n\nfunction handleNotOccupiedRegion(results, i) {\n const regionKey = \"Region \" + (i + 1);\n\n results[regionKey][\"actual_entry_time\"] = previous_data[regionKey][\"actual_entry_time\"];\n results[regionKey][\"entry_time\"] = previous_data[regionKey][\"entry_time\"];\n results[regionKey][\"actual_dwell_time\"] = previous_data[regionKey][\"actual_dwell_time\"];\n results[regionKey][\"dwell_time\"] = previous_data[regionKey][\"dwell_time\"];\n results[regionKey][\"occupancy_check\"] = previous_data[regionKey][\"occupancy_check\"] + 1;\n\n if (previous_data[regionKey][\"exit_time\"]) {\n results[regionKey][\"exit_time\"] = previous_data[regionKey][\"exit_time\"];\n }\n else {\n results[regionKey][\"exit_time\"] = msg.nodered_timestamp;\n }\n return results;\n}\n\nfunction main(payload, distance_threshold = 100, intersection_type = \"region\", intersection_threshold = 0.5, object_counter = false) {\n var results = preprocess_bboxes(payload);\n var occupied = euclidean_iou_function(results, distance_threshold, intersection_type, intersection_threshold, object_counter);\n var out = postprocess_output(occupied);\n flow.set(previous_data_name, out);\n return out;\n}\n\n// user-defined parameters\nvar distance_threshold = flow.get(\"distance_threshold\");\nvar intersection_type = flow.get(\"intersection_type\");\nvar intersection_threshold = flow.get(\"intersection_threshold\");\nvar object_counter = flow.get(\"object_counter\");\n\nmsg.payload = main(payload, distance_threshold, intersection_type, intersection_threshold, object_counter);\nflow.set(detection_name, msg);\nreturn msg;", | |||
| "func": "let region_name = \"predefined_regions_1\";\nlet detection_name = \"object_detection_1\";\nlet previous_data_name = \"previous_data_1\";\nlet occupancy_check_duration = 60;\nlet min_entry_frames = 30;\nlet video_id = 1;\nlet region_id = -1; //Recommend to set this only when there is 1 predefined region in the video\n\nvar payload = msg.payload;\nvar previous_data = flow.get(previous_data_name);\nvar stop_duration = flow.get(\"stop_duration\");\n\n// preparing bboxes\nfunction preprocess_bboxes(payload) {\n function getObjectData(object_data) {\n var current_object_data = {};\n if (object_data.hasOwnProperty(\"type\")) {\n current_object_data[\"type\"] = object_data[\"type\"];\n }\n if (object_data.hasOwnProperty(\"color\")) {\n current_object_data[\"color\"] = object_data[\"color\"];\n }\n if (object_data.hasOwnProperty(\"license_plate\")) {\n current_object_data[\"license_plate\"] = object_data[\"license_plate\"];\n }\n if (object_data.hasOwnProperty(\"id\")) {\n current_object_data[\"id\"] = object_data[\"id\"];\n }\n if (object_data.hasOwnProperty(\"roi_type\")) {\n current_object_data[\"roi_type\"] = object_data[\"roi_type\"];\n }\n return current_object_data;\n }\n function getLotBbox(lot_data) {\n return { \"vertex1\": lot_data.vertex1, \"vertex2\": lot_data.vertex2, \"vertex3\": lot_data.vertex3, \"vertex4\": lot_data.vertex4, \"vertex_0\": lot_data.vertex1 };\n }\n\n var results = {};\n var objects = [];\n var objects_extra = [];\n var lots = [];\n // get all objects bboxes\n for (let key in payload) {\n if (payload.hasOwnProperty(key)) {\n var objectData = getObjectData(payload[key]);\n if (objectData !== null) {\n objects_extra.push(\n objectData\n );\n objects.push(\n payload[key][\"bbox\"]\n );\n }\n }\n }\n // get all lots bboxes\n var predefined_regions = flow.get(region_name);\n var keys = Object.keys(predefined_regions);\n\n for (let i = 0; i < keys.length; i++) {\n if (predefined_regions.hasOwnProperty(keys[i]) && keys[i] != \"_msgid\") {\n lots.push(\n getLotBbox(predefined_regions[keys[i]])\n );\n }\n }\n\n results[\"objects\"] = objects;\n results[\"objects_extra\"] = objects_extra;\n results[\"lots\"] = lots;\n return results;\n}\n\n// euclidean distance and iou check\nfunction euclidean_iou_function(payload, distance_threshold = 100, intersection_type = \"region\", intersection_threshold = 0.5, object_counter = false) {\n function getBboxCentroid(bbox) {\n var centroid_x = (bbox[\"vertex1\"].x + bbox[\"vertex2\"].x + bbox[\"vertex3\"].x + bbox[\"vertex4\"].x) / 4;\n var centroid_y = (bbox[\"vertex1\"].y + bbox[\"vertex2\"].y + bbox[\"vertex3\"].y + bbox[\"vertex4\"].y) / 4;\n return [centroid_x, centroid_y];\n }\n function calculateEuclideanDistance(centroid1, centroid2) {\n return Math.sqrt((centroid2[0] - centroid1[0]) ** 2 + (centroid2[1] - centroid1[1]) ** 2);\n }\n function calculateIntersectArea(bbox1, bbox2) { // objects, lots\n var bbox1_key = Object.keys(bbox1)\n var bbox2_key = Object.keys(bbox2)\n var intersection = [];\n\n for (let i = 0; i < bbox1_key.length - 1; i++) {\n for (let j = 0; j < bbox2_key.length - 1; j++) {\n var A1 = bbox1[bbox1_key[i + 1]].y - bbox1[bbox1_key[i]].y; // Ax + By + C = 0\n var B1 = bbox1[bbox1_key[i]].x - bbox1[bbox1_key[i + 1]].x;\n var C1 = - A1 * bbox1[bbox1_key[i]].x - B1 * bbox1[bbox1_key[i]].y;\n\n var A2 = bbox2[bbox2_key[j + 1]].y - bbox2[bbox2_key[j]].y;\n var B2 = bbox2[bbox2_key[j]].x - bbox2[bbox2_key[j + 1]].x;\n var C2 = - A2 * bbox2[bbox2_key[j]].x - B2 * bbox2[bbox2_key[j]].y;\n\n // parallel lines case\n if (A1 * B2 == A2 * B1) {\n // coincide case\n if ((A1 * C2 == A2 * C1) && (B1 * C2 == B2 * C1)) {\n if (B1 == 0 && A1 == 0) { // one point bbox case\n intersection.push([bbox1[bbox1_key[i]].x.toFixed(6), bbox1[bbox1_key[i]].y.toFixed(6)]);\n }\n else if (B2 == 0 && A2 == 0) { // one point bbox case\n intersection.push([bbox2[bbox2_key[i]].x.toFixed(6), bbox2[bbox2_key[i]].y.toFixed(6)]);\n }\n else if (B1 == 0) { // vertical lines case\n var y_min1 = (bbox1[bbox1_key[i]].y < bbox1[bbox1_key[i + 1]].y) ? bbox1[bbox1_key[i]].y : bbox1[bbox1_key[i + 1]].y;\n var y_max1 = (bbox1[bbox1_key[i]].y < bbox1[bbox1_key[i + 1]].y) ? bbox1[bbox1_key[i + 1]].y : bbox1[bbox1_key[i]].y;\n var y_min2 = (bbox2[bbox2_key[i]].y < bbox2[bbox2_key[i + 1]].y) ? bbox2[bbox2_key[i]].y : bbox2[bbox2_key[i + 1]].y;\n var y_max2 = (bbox2[bbox2_key[i]].y < bbox2[bbox2_key[i + 1]].y) ? bbox2[bbox2_key[i + 1]].y : bbox2[bbox2_key[i]].y;\n if ((y_min1 < y_max2) && (y_min2 < y_max1)) {\n var y_min = (y_min1 < y_min2) ? y_min2 : y_min1;\n var y_max = (y_max1 < y_max2) ? y_max1 : y_max2;\n intersection.push([bbox1[bbox1_key[i]].x.toFixed(6), y_min.toFixed(6)]);\n intersection.push([bbox1[bbox1_key[i]].x.toFixed(6), y_max.toFixed(6)]);\n }\n }\n else if (A1 == 0) { // horizontal lines case\n var x_min1 = (bbox1[bbox1_key[i]].x < bbox1[bbox1_key[i + 1]].x) ? bbox1[bbox1_key[i]].x : bbox1[bbox1_key[i + 1]].x;\n var x_max1 = (bbox1[bbox1_key[i]].x < bbox1[bbox1_key[i + 1]].x) ? bbox1[bbox1_key[i + 1]].x : bbox1[bbox1_key[i]].x;\n var x_min2 = (bbox2[bbox2_key[i]].x < bbox2[bbox2_key[i + 1]].x) ? bbox2[bbox2_key[i]].x : bbox2[bbox2_key[i + 1]].x;\n var x_max2 = (bbox2[bbox2_key[i]].x < bbox2[bbox2_key[i + 1]].x) ? bbox2[bbox2_key[i + 1]].x : bbox2[bbox2_key[i]].x;\n if ((x_min1 < x_max2) && (x_min2 < x_max1)) {\n var x_min = (x_min1 < x_min2) ? x_min2 : x_min1;\n var x_max = (x_max1 < x_max2) ? x_max1 : x_max2;\n intersection.push([x_min.toFixed(6), bbox1[bbox1_key[i]].y.toFixed(6)]);\n intersection.push([x_max.toFixed(6), bbox1[bbox1_key[i]].y.toFixed(6)]);\n }\n }\n else {\n var x_min1 = (bbox1[bbox1_key[i]].x < bbox1[bbox1_key[i + 1]].x) ? bbox1[bbox1_key[i]].x : bbox1[bbox1_key[i + 1]].x;\n var x_max1 = (bbox1[bbox1_key[i]].x < bbox1[bbox1_key[i + 1]].x) ? bbox1[bbox1_key[i + 1]].x : bbox1[bbox1_key[i]].x;\n var x_min2 = (bbox2[bbox2_key[i]].x < bbox2[bbox2_key[i + 1]].x) ? bbox2[bbox2_key[i]].x : bbox2[bbox2_key[i + 1]].x;\n var x_max2 = (bbox2[bbox2_key[i]].x < bbox2[bbox2_key[i + 1]].x) ? bbox2[bbox2_key[i + 1]].x : bbox2[bbox2_key[i]].x;\n if ((x_min1 < x_max2) && (x_min2 < x_max1) && (y_min1 < y_max2) && (y_min2 < y_max1)) {\n var x_min = (x_min1 < x_min2) ? x_min2 : x_min1;\n var x_max = (x_max1 < x_max2) ? x_max1 : x_max2;\n var xY_min = (-A1 * x_min - C1) / B1\n var xY_max = (-A1 * x_max - C1) / B1\n intersection.push([x_min.toFixed(6), xY_min.toFixed(6)]);\n intersection.push([x_max.toFixed(6), xY_max.toFixed(6)]);\n }\n }\n }\n }\n else {\n // get intersection coordinates\n var x1 = bbox1[bbox1_key[i]].x;\n var x2 = bbox1[bbox1_key[i + 1]].x;\n var x3 = bbox2[bbox2_key[j]].x;\n var x4 = bbox2[bbox2_key[j + 1]].x;\n var y1 = bbox1[bbox1_key[i]].y;\n var y2 = bbox1[bbox1_key[i + 1]].y;\n var y3 = bbox2[bbox2_key[j]].y;\n var y4 = bbox2[bbox2_key[j + 1]].y;\n\n var den = (x2 - x1) * (y3 - y4) - (y2 - y1) * (x3 - x4);\n var t = ((x3 - x1) * (y3 - y4) - (y3 - y1) * (x3 - x4)) / den;\n var u = ((x3 - x1) * (y1 - y2) - (y3 - y1) * (x1 - x2)) / den;\n if ((t >= 0) && (t <= 1) && (u >= 0) && (u <= 1)) { // intersect happens if this condition is fulfilled\n var ix = x1 + t * (x2 - x1);\n var iy = y1 + t * (y2 - y1);\n intersection.push([ix.toFixed(6), iy.toFixed(6)]);\n }\n }\n }\n }\n // get clipped coordinates\n var specialcase1 = true;\n var specialcase2 = false;\n var temp1 = bbox1[bbox1_key[0]];\n var temp2 = bbox2[bbox2_key[0]];\n for (let i = 1; i < bbox1_key.length - 1; i++) { // special case\n if (temp1 !== bbox1[bbox1_key[i]]) {\n specialcase1 = false;\n break;\n }\n }\n for (let i = 1; i < bbox2_key.length - 1; i++) {\n if (temp2 !== bbox2[bbox2_key[i]]) {\n specialcase2 = false;\n break;\n }\n }\n if (!(specialcase2)) {\n for (let i = 0; i < bbox1_key.length - 1; i++) {\n var sign_check = [];\n for (let j = 0; j < bbox2_key.length - 1; j++) {\n var x1 = bbox2[bbox2_key[j]].x\n var x2 = bbox2[bbox2_key[j + 1]].x\n var y1 = bbox2[bbox2_key[j]].y\n var y2 = bbox2[bbox2_key[j + 1]].y\n var cross_prod = (bbox1[bbox1_key[i]].x - x1) * (y2 - y1) - (bbox1[bbox1_key[i]].y - y1) * (x2 - x1);\n var sign = (cross_prod >= 0) ? true : false;\n sign_check.push(sign);\n }\n if (sign_check.length === 4 && (sign_check.every((val, index) => val === [true, true, true, true][index]) ||\n sign_check.every((val, index) => val === [false, false, false, false][index]))) { // similar signs indicate the coordinate is within another bbox\n intersection.push([bbox1[bbox1_key[i]].x.toFixed(6), bbox1[bbox1_key[i]].y.toFixed(6)]);\n //intersection.push([bbox1[bbox1_key[i]].x, bbox1[bbox1_key[i]].y]);\n }\n }\n }\n if (!(specialcase1)) {\n for (let i = 0; i < bbox2_key.length - 1; i++) { // similar purpose but for second bbox\n var sign_check = [];\n for (let j = 0; j < bbox1_key.length - 1; j++) {\n var x1 = bbox1[bbox1_key[j]].x\n var x2 = bbox1[bbox1_key[j + 1]].x\n var y1 = bbox1[bbox1_key[j]].y\n var y2 = bbox1[bbox1_key[j + 1]].y\n var cross_prod = (bbox2[bbox2_key[i]].x - x1) * (y2 - y1) - (bbox2[bbox2_key[i]].y - y1) * (x2 - x1);\n var sign = (cross_prod >= 0) ? true : false;\n sign_check.push(sign);\n }\n if (sign_check.length === 4 && (sign_check.every((val, index) => val === [true, true, true, true][index]) ||\n sign_check.every((val, index) => val === [false, false, false, false][index]))) {\n intersection.push([bbox2[bbox2_key[i]].x.toFixed(6), bbox2[bbox2_key[i]].y.toFixed(6)]);\n //intersection.push([bbox2[bbox2_key[i]].x, bbox2[bbox2_key[i]].y]);\n }\n }\n }\n intersection = intersection.filter((item, index, self) =>\n index === self.findIndex((t) => JSON.stringify(t) === JSON.stringify(item))\n );\n // sort intersection points\n if (intersection.length > 2) {\n var intersection_angle = [];\n var intersection_distance = [];\n\n let minIndex = intersection.reduce((minIdx, currentValue, currentIndex, array) => {\n if (currentValue[0] < array[minIdx][0]) {\n return currentIndex;\n } else if (currentValue[0] === array[minIdx][0]) {\n return currentValue[1] < array[minIdx][1] ? currentIndex : minIdx;\n } else {\n return minIdx;\n }\n }, 0);\n var temp_intersection = intersection.filter((_, index) => index !== minIndex);\n for (let i = 0; i < temp_intersection.length; i++) {\n intersection_angle.push(Math.atan2(temp_intersection[i][1] - intersection[minIndex][1], temp_intersection[i][0] - intersection[minIndex][0]));\n intersection_distance.push((temp_intersection[i][1] - intersection[minIndex][1]) ** 2 + (temp_intersection[i][0] - intersection[minIndex][0]) ** 2);\n }\n let combined = temp_intersection.map((point, index) => ({ // sort intersect coordinates based on angle and then distance\n point: point,\n angle: intersection_angle[index],\n distance: intersection_distance[index]\n }));\n combined.sort((a, b) => a.angle - b.angle || a.distance - b.distance);\n let sorted_intersection = combined.map(item => item.point);\n sorted_intersection.unshift(intersection[minIndex]);\n sorted_intersection.push(intersection[minIndex]);\n // shoelace algorithm to calculate the intersect area\n var area = 0;\n for (let i = 0; i < sorted_intersection.length - 1; i++) {\n area += ((sorted_intersection[i][0] * sorted_intersection[i + 1][1])\n - (sorted_intersection[i + 1][0] * sorted_intersection[i][1]))\n }\n return area;\n }\n return 0;\n }\n function calculateIOU(bbox1, bbox2, intersectArea) {\n if (intersectArea !== 0) {\n var lot_area1 = (bbox1[\"vertex1\"].x * bbox1[\"vertex2\"].y) + (bbox1[\"vertex2\"].x * bbox1[\"vertex3\"].y)\n + (bbox1[\"vertex3\"].x * bbox1[\"vertex4\"].y) + (bbox1[\"vertex4\"].x * bbox1[\"vertex_0\"].y)\n - ((bbox1[\"vertex2\"].x * bbox1[\"vertex1\"].y) + (bbox1[\"vertex3\"].x * bbox1[\"vertex2\"].y)\n + (bbox1[\"vertex4\"].x * bbox1[\"vertex3\"].y) + (bbox1[\"vertex_0\"].x * bbox1[\"vertex4\"].y));\n\n var lot_area2 = (bbox2[\"vertex1\"].x * bbox2[\"vertex2\"].y) + (bbox2[\"vertex2\"].x * bbox2[\"vertex3\"].y)\n + (bbox2[\"vertex3\"].x * bbox2[\"vertex4\"].y) + (bbox2[\"vertex4\"].x * bbox2[\"vertex_0\"].y)\n - ((bbox2[\"vertex2\"].x * bbox2[\"vertex1\"].y) + (bbox2[\"vertex3\"].x * bbox2[\"vertex2\"].y)\n + (bbox2[\"vertex4\"].x * bbox2[\"vertex3\"].y) + (bbox2[\"vertex_0\"].x * bbox2[\"vertex4\"].y));\n return intersectArea / (lot_area1 + lot_area2 - intersectArea)\n }\n return 0;\n }\n function calculateIOR(bbox1, intersectArea) {\n if (intersectArea !== 0) {\n var lot_area = (bbox1[\"vertex1\"].x * bbox1[\"vertex2\"].y) + (bbox1[\"vertex2\"].x * bbox1[\"vertex3\"].y)\n + (bbox1[\"vertex3\"].x * bbox1[\"vertex4\"].y) + (bbox1[\"vertex4\"].x * bbox1[\"vertex_0\"].y)\n - ((bbox1[\"vertex2\"].x * bbox1[\"vertex1\"].y) + (bbox1[\"vertex3\"].x * bbox1[\"vertex2\"].y)\n + (bbox1[\"vertex4\"].x * bbox1[\"vertex3\"].y) + (bbox1[\"vertex_0\"].x * bbox1[\"vertex4\"].y));\n return intersectArea / lot_area;\n }\n return 0;\n }\n\n var occupied = [];\n var current_index = -1;\n // initialize lots to no object\n for (let key1 in payload[\"lots\"]) {\n if (payload[\"lots\"].hasOwnProperty(key1)) {\n occupied.push({ \"occupied\": 0 });\n }\n }\n for (let key1 in payload[\"objects\"]) {\n current_index++;\n if (payload[\"objects\"].hasOwnProperty(key1)) { // find all lots within the object centroid distance threshold\n var objectCentroid = getBboxCentroid(payload[\"objects\"][key1]);\n var potential_region = [];\n for (let key2 in payload[\"lots\"]) {\n if (payload[\"lots\"].hasOwnProperty(key2)) {\n var regionCentroid = getBboxCentroid(payload[\"lots\"][key2]);\n var euclideanDistance = calculateEuclideanDistance(objectCentroid, regionCentroid);\n potential_region.push(euclideanDistance);\n }\n }\n // calculate IOU or IOR\n if (object_counter) {\n for (let i = 0; i < potential_region.length; i++) {\n if (potential_region[i] < distance_threshold) {\n var intersectRegion = calculateIntersectArea(payload[\"objects\"][key1], payload[\"lots\"][i]);\n var IOR = 0;\n if (intersection_type == \"region\") {\n IOR = calculateIOR(payload[\"lots\"][i], intersectRegion)\n }\n else if (intersection_type == \"object\") {\n IOR = calculateIOR(payload[\"objects\"][key1], intersectRegion)\n }\n if (IOR > intersection_threshold) {\n occupied[i][\"occupied\"] += 1;\n var keyData = Object.keys(payload[\"objects_extra\"][current_index]);\n var numberData = keyData.length;\n for (let j = 0; j < numberData; j++) {\n if (!occupied[i][\"extra\"]) {\n occupied[i][\"extra\"] = {};\n }\n if (!occupied[i][\"extra\"][keyData[j]]) {\n occupied[i][\"extra\"][keyData[j]] = [];\n }\n occupied[i][\"extra\"][keyData[j]].push(payload[\"objects_extra\"][current_index][keyData[j]]);\n }\n }\n }\n }\n }\n else { // consider the best lot only\n var best_region_index = potential_region.reduce((minIndex, currentValue, currentIndex, array) =>\n currentValue < array[minIndex] ? currentIndex : minIndex, 0);\n if (potential_region[best_region_index] < distance_threshold) {\n var intersectRegion = calculateIntersectArea(payload[\"objects\"][key1], payload[\"lots\"][best_region_index]);\n var IOR = 0;\n if (intersection_type == \"region\") {\n IOR = calculateIOR(payload[\"lots\"][best_region_index], intersectRegion)\n }\n else if (intersection_type == \"object\") {\n IOR = calculateIOR(payload[\"objects\"][key1], intersectRegion)\n }\n if (IOR > intersection_threshold) {\n occupied[best_region_index][\"occupied\"] += 1;\n var keyData = Object.keys(payload[\"objects_extra\"][current_index]);\n var numberData = keyData.length;\n for (let i = 0; i < numberData; i++) {\n if (!occupied[best_region_index][\"extra\"]) {\n occupied[best_region_index][\"extra\"] = {};\n }\n if (!occupied[best_region_index][\"extra\"][keyData[i]]) {\n occupied[best_region_index][\"extra\"][keyData[i]] = [];\n }\n occupied[best_region_index][\"extra\"][keyData[i]].push(payload[\"objects_extra\"][current_index][keyData[i]]);\n }\n }\n }\n }\n }\n }\n return occupied;\n}\n\n// turn into correct format\nfunction postprocess_output(occupied) {\n var results = {};\n\n for (let i = 0; i < occupied.length; i++) {\n results = initializeResults(results, occupied, i);\n previous_data = initializePreviousData(results, i);\n if (results[\"Region \" + (i + 1)].hasOwnProperty(\"id\") || previous_data[\"Region \" + (i + 1)].hasOwnProperty(\"id\")) {\n results = handleObjectWithID(results, i);\n }\n else if (results[\"Region \" + (i + 1)][\"occupied\"] > 0) {\n results = handleOccupiedRegion(results, i);\n }\n else if (previous_data[\"Region \" + (i + 1)][\"entry_time\"]) {\n results = handleNotOccupiedRegion(results, i);\n }\n }\n return results;\n}\n\nfunction initializeResults(results, occupied, i) {\n const regionKey = \"Region \" + (i + 1);\n\n if (!results[regionKey]) {\n results[regionKey] = {};\n }\n results[regionKey][\"video_id\"] = video_id;\n results[regionKey][\"region_id\"] = (region_id != -1) ? region_id : i + 1;\n\n if (occupied[i].hasOwnProperty(\"occupied\")) {\n results[regionKey][\"occupied\"] = occupied[i].occupied;\n }\n\n if (occupied[i].hasOwnProperty(\"extra\")) {\n for (let key in occupied[i].extra) {\n results[regionKey][key] = occupied[i].extra[key];\n }\n }\n if (results[regionKey].hasOwnProperty(\"id\") || (previous_data && previous_data.hasOwnProperty(regionKey) && previous_data[regionKey].hasOwnProperty(\"id\"))) {\n results[regionKey][\"actual_entry_time\"] = [];\n results[regionKey][\"actual_dwell_time\"] = [];\n results[regionKey][\"entry_time\"] = [];\n results[regionKey][\"dwell_time\"] = [];\n results[regionKey][\"exit_time\"] = [];\n }\n else {\n results[\"Region \" + (i + 1)][\"actual_entry_time\"] = \"\";\n results[\"Region \" + (i + 1)][\"actual_dwell_time\"] = \"\";\n results[\"Region \" + (i + 1)][\"entry_time\"] = \"\";\n results[\"Region \" + (i + 1)][\"dwell_time\"] = \"\";\n results[\"Region \" + (i + 1)][\"exit_time\"] = \"\";\n results[\"Region \" + (i + 1)][\"occupancy_check\"] = 0;\n }\n return results;\n}\n\nfunction initializePreviousData(results, i) {\n const regionKey = \"Region \" + (i + 1);\n\n // Ensure previous_data is set up for this region.\n if (!previous_data) {\n previous_data = {};\n }\n if (results[regionKey].hasOwnProperty(\"id\")) {\n if (!previous_data[regionKey]) {\n previous_data[regionKey] = {};\n previous_data[regionKey][\"id\"] = [];\n previous_data[regionKey][\"actual_entry_time\"] = [];\n previous_data[regionKey][\"actual_dwell_time\"] = [];\n previous_data[regionKey][\"entry_time\"] = [];\n previous_data[regionKey][\"dwell_time\"] = [];\n previous_data[regionKey][\"exit_time\"] = [];\n }\n }\n else {\n if (!previous_data.hasOwnProperty(regionKey)) {\n previous_data[regionKey] = results[regionKey];\n previous_data[regionKey][\"actual_entry_time\"] = \"\";\n previous_data[regionKey][\"actual_dwell_time\"] = \"\";\n previous_data[regionKey][\"entry_time\"] = \"\";\n previous_data[regionKey][\"dwell_time\"] = \"\";\n previous_data[regionKey][\"exit_time\"] = \"\";\n previous_data[regionKey][\"occupancy_check\"] = 0;\n }\n }\n\n return previous_data;\n}\n\nfunction handleObjectWithID(results, i) {\n const regionKey = \"Region \" + (i + 1);\n const resultIds = results[regionKey][\"id\"];\n const previousDataIds = previous_data[regionKey][\"id\"];\n\n if (!resultIds && !previousDataIds) {\n return results;\n }\n\n if (resultIds) {\n for (let j = 0; j < resultIds.length; j++) {\n // Check existing id data\n let prevIndex = -1;\n\n if (previous_data[regionKey][\"id\"] && previous_data[regionKey][\"id\"].length > 0) {\n prevIndex = previous_data[regionKey][\"id\"].indexOf(resultIds[j]);\n }\n\n if (prevIndex === -1) {\n results[regionKey][\"actual_entry_time\"].push(msg.nodered_timestamp);\n results[regionKey][\"entry_time\"].push(msg.object_timestamp);\n results[regionKey][\"actual_dwell_time\"].push(\"00:00:00\");\n results[regionKey][\"dwell_time\"].push(0);\n results[regionKey][\"exit_time\"].push(\"\");\n } else {\n results[regionKey][\"actual_entry_time\"].push(previous_data[regionKey][\"actual_entry_time\"][prevIndex]);\n results[regionKey][\"entry_time\"].push(previous_data[regionKey][\"entry_time\"][prevIndex]);\n\n // Calculate dwell time.\n const dwell_timestamp = (msg.object_timestamp - results[regionKey][\"entry_time\"][j]);\n const dwell_hours = Math.floor(dwell_timestamp / 3600).toString().padStart(2, \"0\");\n const dwell_mins = Math.floor((dwell_timestamp / 60) % 60).toString().padStart(2, \"0\");\n const dwell_seconds = Math.floor(dwell_timestamp % 60).toString().padStart(2, \"0\");\n results[regionKey][\"dwell_time\"].push(dwell_timestamp);\n results[regionKey][\"actual_dwell_time\"].push(dwell_hours + \":\" + dwell_mins + \":\" + dwell_seconds);\n results[regionKey][\"exit_time\"].push(\"\");\n }\n }\n }\n\n if (previousDataIds) {\n for (let j = 0; j < previousDataIds.length; j++) {\n let prevIndex = -1;\n\n if (!results[regionKey][\"id\"]) {\n results[regionKey] = previous_data[regionKey];\n results[regionKey][\"occupied\"] = 0;\n break;\n }\n else {\n if (!results[regionKey][\"dwell_time\"].some(val => val >= stop_duration)) {\n results[regionKey][\"occupied\"] = 0;\n }\n\n prevIndex = results[regionKey][\"id\"].indexOf(previousDataIds[j]);\n if (prevIndex === -1) {\n let keyList = Object.keys(previous_data[regionKey]);\n for (let k = 0; k < keyList.length; k++) {\n if (keyList[k] == \"video_id\" || keyList[k] == \"region_id\" || keyList[k] == \"occupied\") {\n continue;\n }\n results[regionKey][keyList[k]].push(previous_data[regionKey][keyList[k]][j]);\n }\n }\n }\n }\n }\n return results;\n}\n\nfunction handleOccupiedRegion(results, i) {\n const regionKey = \"Region \" + (i + 1);\n var prev_consecutive = (previous_data[regionKey][\"consecutive_occupied\"]) || 0;\n results[regionKey][\"consecutive_occupied\"] = prev_consecutive + 1;\n if (results[regionKey][\"consecutive_occupied\"] < min_entry_frames) {\n results[regionKey][\"occupied\"] = 0;\n results[regionKey][\"occupancy_check\"] = 0;\n return results;\n }\n if (previous_data[regionKey][\"entry_time\"] == \"\") {\n results[regionKey][\"actual_entry_time\"] = msg.nodered_timestamp;\n results[regionKey][\"entry_time\"] = msg.object_timestamp;\n }\n else {\n if (previous_data[regionKey][\"occupancy_check\"] >= occupancy_check_duration) {\n results[regionKey][\"actual_dwell_time\"] = \"00:00:00\";\n results[regionKey][\"dwell_time\"] = 0;\n results[regionKey][\"actual_entry_time\"] = msg.nodered_timestamp;\n results[regionKey][\"entry_time\"] = msg.object_timestamp;\n }\n else {\n results[regionKey][\"actual_entry_time\"] = previous_data[regionKey][\"actual_entry_time\"];\n results[regionKey][\"entry_time\"] = previous_data[regionKey][\"entry_time\"];\n }\n\n var dwell_timestamp = msg.object_timestamp - results[regionKey][\"entry_time\"];\n var dwell_hours = Math.floor(dwell_timestamp / 3600).toString();\n dwell_hours = dwell_hours.toString().length == 1 ? dwell_hours.toString().padStart(2, \"0\") : dwell_hours.toString();\n var dwell_mins = Math.floor((dwell_timestamp / 60) % 60).toString().padStart(2, \"0\");\n var dwell_seconds = Math.floor(dwell_timestamp % 60).toString().padStart(2, \"0\");\n\n results[regionKey][\"dwell_time\"] = dwell_timestamp;\n results[regionKey][\"actual_dwell_time\"] = dwell_hours + \":\" + dwell_mins + \":\" + dwell_seconds;\n results[regionKey][\"occupancy_check\"] = 0;\n }\n\n return results;\n}\n\nfunction handleNotOccupiedRegion(results, i) {\n const regionKey = \"Region \" + (i + 1);\n\n results[regionKey][\"actual_entry_time\"] = previous_data[regionKey][\"actual_entry_time\"];\n results[regionKey][\"entry_time\"] = previous_data[regionKey][\"entry_time\"];\n results[regionKey][\"actual_dwell_time\"] = previous_data[regionKey][\"actual_dwell_time\"];\n results[regionKey][\"dwell_time\"] = previous_data[regionKey][\"dwell_time\"];\n results[regionKey][\"occupancy_check\"] = previous_data[regionKey][\"occupancy_check\"] + 1;\n\n if (previous_data[regionKey][\"exit_time\"]) {\n results[regionKey][\"exit_time\"] = previous_data[regionKey][\"exit_time\"];\n }\n else {\n results[regionKey][\"exit_time\"] = msg.nodered_timestamp;\n }\n return results;\n}\n\nfunction main(payload, distance_threshold = 100, intersection_type = \"region\", intersection_threshold = 0.5, object_counter = false) {\n var results = preprocess_bboxes(payload);\n var occupied = euclidean_iou_function(results, distance_threshold, intersection_type, intersection_threshold, object_counter);\n var out = postprocess_output(occupied);\n flow.set(previous_data_name, out);\n return out;\n}\n\n// user-defined parameters\nvar distance_threshold = flow.get(\"distance_threshold\");\nvar intersection_type = flow.get(\"intersection_type\");\nvar intersection_threshold = flow.get(\"intersection_threshold\");\nvar object_counter = flow.get(\"object_counter\");\n\nmsg.payload = main(payload, distance_threshold, intersection_type, intersection_threshold, object_counter);\nflow.set(detection_name, msg);\nreturn msg;", | |||
There was a problem hiding this comment.
what is min_entry_frames = 30 doing?
| "z": "2720733497fe05f3", | ||
| "name": "data extraction 1", | ||
| "func": "let payload = msg.payload[\"metadata\"][\"objects\"];\nlet result = {};\nlet counter = 1;\n\nvar object_confidence = flow.get(\"object_confidence\");\nvar target_object = flow.get(\"target_object\");\nvar stop_duration = flow.get(\"stop_duration\");\n\nvar date = new Date();\nvar localDate = new Date(date.toLocaleString(\"en-US\", { timeZone: \"Asia/Kuala_Lumpur\" }));\n\nvar years = localDate.getFullYear();\nvar months = (localDate.getMonth() + 1).toString().padStart(2, \"0\");\nvar dates = (localDate.getDate()).toString().padStart(2, \"0\");\nvar hours = localDate.getHours();\nvar minutes = localDate.getMinutes();\nvar seconds = localDate.getSeconds();\n\nhours = (\"0\" + hours).slice(-2);\nminutes = (\"0\" + minutes).slice(-2);\nseconds = (\"0\" + seconds).slice(-2);\n\nmsg.nodered_timestamp = years + \"/\" + months + \"/\" + dates + \" \" + hours + \":\" + minutes + \":\" + seconds;\nmsg.object_timestamp = new Date().getTime() / 1000;\n\nfor (let key in payload) {\n if (payload.hasOwnProperty(key) && payload[key].hasOwnProperty(\"detection\")) {\n if (!(target_object.length == 1 && target_object[0] == \"\")) {\n var skip = true;\n for (let i = 0; i < target_object.length; i++) {\n if (payload[key][\"roi_type\"] == target_object[i]) {\n skip = false;\n break;\n }\n }\n if (skip == true) { continue; }\n }\n if (payload[key][\"detection\"][\"confidence\"] > object_confidence) {\n var current_object_data = {\n \"bbox\": {\n \"vertex1\": { \"x\": payload[key][\"x\"], \"y\": payload[key][\"y\"] },\n \"vertex2\": { \"x\": payload[key][\"x\"] + payload[key][\"w\"], \"y\": payload[key][\"y\"] },\n \"vertex3\": { \"x\": payload[key][\"x\"] + payload[key][\"w\"], \"y\": payload[key][\"y\"] + payload[key][\"h\"] },\n \"vertex4\": { \"x\": payload[key][\"x\"], \"y\": payload[key][\"y\"] + payload[key][\"h\"] },\n \"vertex_0\": { \"x\": payload[key][\"x\"], \"y\": payload[key][\"y\"] }\n }\n }\n if (payload[key].hasOwnProperty(\"type\") && payload[key][\"type\"].hasOwnProperty(\"label\")) {\n current_object_data[\"type\"] = payload[key][\"type\"][\"label\"];\n }\n if (payload[key].hasOwnProperty(\"color\") && payload[key][\"color\"].hasOwnProperty(\"label\")) {\n current_object_data[\"color\"] = payload[key][\"color\"][\"label\"];\n }\n if (payload[key].hasOwnProperty(\"license_plate\") && payload[key][\"license_plate\"].hasOwnProperty(\"label\")) {\n current_object_data[\"license_plate\"] = payload[key][\"license_plate\"][\"label\"];\n }\n if (payload[key].hasOwnProperty(\"id\")) {\n current_object_data[\"id\"] = payload[key][\"id\"];\n }\n if (payload[key].hasOwnProperty(\"roi_type\")) {\n current_object_data[\"roi_type\"] = payload[key][\"roi_type\"];\n }\n result[`object_${counter++}`] = current_object_data;\n }\n }\n}\n\nif (Object.keys(result).length > 0) {\n msg.payload = result;\n return msg;\n}", | ||
| "func": "let payload = msg.payload[\"metadata\"][\"objects\"];\nlet result = {};\nlet counter = 1;\n\nvar object_confidence = flow.get(\"object_confidence\");\nvar target_object = flow.get(\"target_object\");\nvar stop_duration = flow.get(\"stop_duration\");\n\nvar date = new Date();\nvar localDate = new Date();\n\nvar years = localDate.getFullYear();\nvar months = (localDate.getMonth() + 1).toString().padStart(2, \"0\");\nvar dates = (localDate.getDate()).toString().padStart(2, \"0\");\nvar hours = localDate.getHours();\nvar minutes = localDate.getMinutes();\nvar seconds = localDate.getSeconds();\n\nhours = (\"0\" + hours).slice(-2);\nminutes = (\"0\" + minutes).slice(-2);\nseconds = (\"0\" + seconds).slice(-2);\n\nmsg.nodered_timestamp = years + \"/\" + months + \"/\" + dates + \" \" + hours + \":\" + minutes + \":\" + seconds;\nmsg.object_timestamp = new Date().getTime() / 1000;\n\nfor (let key in payload) {\n if (payload.hasOwnProperty(key) && payload[key].hasOwnProperty(\"detection\")) {\n if (!(target_object.length == 1 && target_object[0] == \"\")) {\n var skip = true;\n for (let i = 0; i < target_object.length; i++) {\n if (payload[key][\"roi_type\"] == target_object[i]) {\n skip = false;\n break;\n }\n }\n if (skip == true) { continue; }\n }\n if (payload[key][\"detection\"][\"confidence\"] > object_confidence) {\n var current_object_data = {\n \"bbox\": {\n \"vertex1\": { \"x\": payload[key][\"x\"], \"y\": payload[key][\"y\"] },\n \"vertex2\": { \"x\": payload[key][\"x\"] + payload[key][\"w\"], \"y\": payload[key][\"y\"] },\n \"vertex3\": { \"x\": payload[key][\"x\"] + payload[key][\"w\"], \"y\": payload[key][\"y\"] + payload[key][\"h\"] },\n \"vertex4\": { \"x\": payload[key][\"x\"], \"y\": payload[key][\"y\"] + payload[key][\"h\"] },\n \"vertex_0\": { \"x\": payload[key][\"x\"], \"y\": payload[key][\"y\"] }\n }\n }\n if (payload[key].hasOwnProperty(\"type\") && payload[key][\"type\"].hasOwnProperty(\"label\")) {\n current_object_data[\"type\"] = payload[key][\"type\"][\"label\"];\n }\n if (payload[key].hasOwnProperty(\"color\") && payload[key][\"color\"].hasOwnProperty(\"label\")) {\n current_object_data[\"color\"] = payload[key][\"color\"][\"label\"];\n }\n if (payload[key].hasOwnProperty(\"license_plate\") && payload[key][\"license_plate\"].hasOwnProperty(\"label\")) {\n current_object_data[\"license_plate\"] = payload[key][\"license_plate\"][\"label\"];\n }\n if (payload[key].hasOwnProperty(\"id\")) {\n current_object_data[\"id\"] = payload[key][\"id\"];\n }\n if (payload[key].hasOwnProperty(\"roi_type\")) {\n current_object_data[\"roi_type\"] = payload[key][\"roi_type\"];\n }\n result[`object_${counter++}`] = current_object_data;\n }\n }\n}\n\nif (Object.keys(result).length > 0) {\n msg.payload = result;\n return msg;\n}", |
There was a problem hiding this comment.
I believe similar timezone changes need to be done in metro-ai-suite/metro-vision-ai-app-recipe/loitering-detection/helm-chart/config/node-red/flows.json too.
| @@ -1227,7 +1227,7 @@ | |||
| "type": "data extraction", | |||
| "z": "2720733497fe05f3", | |||
| "name": "data extraction 1", | |||
| "func": "let payload = msg.payload[\"metadata\"][\"objects\"];\nlet result = {};\nlet counter = 1;\n\nvar object_confidence = flow.get(\"object_confidence\");\nvar target_object = flow.get(\"target_object\");\nvar stop_duration = flow.get(\"stop_duration\");\n\nvar date = new Date();\nvar localDate = new Date(date.toLocaleString(\"en-US\", { timeZone: \"Asia/Kuala_Lumpur\" }));\n\nvar years = localDate.getFullYear();\nvar months = (localDate.getMonth() + 1).toString().padStart(2, \"0\");\nvar dates = (localDate.getDate()).toString().padStart(2, \"0\");\nvar hours = localDate.getHours();\nvar minutes = localDate.getMinutes();\nvar seconds = localDate.getSeconds();\n\nhours = (\"0\" + hours).slice(-2);\nminutes = (\"0\" + minutes).slice(-2);\nseconds = (\"0\" + seconds).slice(-2);\n\nmsg.nodered_timestamp = years + \"/\" + months + \"/\" + dates + \" \" + hours + \":\" + minutes + \":\" + seconds;\nmsg.object_timestamp = new Date().getTime() / 1000;\n\nfor (let key in payload) {\n if (payload.hasOwnProperty(key) && payload[key].hasOwnProperty(\"detection\")) {\n if (!(target_object.length == 1 && target_object[0] == \"\")) {\n var skip = true;\n for (let i = 0; i < target_object.length; i++) {\n if (payload[key][\"roi_type\"] == target_object[i]) {\n skip = false;\n break;\n }\n }\n if (skip == true) { continue; }\n }\n if (payload[key][\"detection\"][\"confidence\"] > object_confidence) {\n var current_object_data = {\n \"bbox\": {\n \"vertex1\": { \"x\": payload[key][\"x\"], \"y\": payload[key][\"y\"] },\n \"vertex2\": { \"x\": payload[key][\"x\"] + payload[key][\"w\"], \"y\": payload[key][\"y\"] },\n \"vertex3\": { \"x\": payload[key][\"x\"] + payload[key][\"w\"], \"y\": payload[key][\"y\"] + payload[key][\"h\"] },\n \"vertex4\": { \"x\": payload[key][\"x\"], \"y\": payload[key][\"y\"] + payload[key][\"h\"] },\n \"vertex_0\": { \"x\": payload[key][\"x\"], \"y\": payload[key][\"y\"] }\n }\n }\n // Extract type from detection.label\n if (payload[key].hasOwnProperty(\"detection\") && payload[key][\"detection\"].hasOwnProperty(\"label\")) {\n current_object_data[\"type\"] = payload[key][\"detection\"][\"label\"];\n }\n // Extract color from classification_layer_name:output.label\n if (payload[key].hasOwnProperty(\"classification_layer_name:output\") && payload[key][\"classification_layer_name:output\"].hasOwnProperty(\"label\")) {\n current_object_data[\"color\"] = payload[key][\"classification_layer_name:output\"][\"label\"];\n }\n // Extract license plate (if exists in future)\n if (payload[key].hasOwnProperty(\"license_plate\") && payload[key][\"license_plate\"].hasOwnProperty(\"label\")) {\n current_object_data[\"license_plate\"] = payload[key][\"license_plate\"][\"label\"];\n }\n // Extract tracking ID (if exists)\n if (payload[key].hasOwnProperty(\"id\")) {\n current_object_data[\"id\"] = payload[key][\"id\"];\n }\n // Extract ROI type\n if (payload[key].hasOwnProperty(\"roi_type\")) {\n current_object_data[\"roi_type\"] = payload[key][\"roi_type\"];\n }\n result[`object_${counter++}`] = current_object_data;\n }\n }\n}\n\nif (Object.keys(result).length > 0) {\n msg.payload = result;\n return msg;\n}", | |||
| "func": "let payload = msg.payload[\"metadata\"][\"objects\"];\nlet result = {};\nlet counter = 1;\n\nvar object_confidence = flow.get(\"object_confidence\");\nvar target_object = flow.get(\"target_object\");\nvar stop_duration = flow.get(\"stop_duration\");\n\nvar date = new Date();\nvar localDate = new Date();\n\nvar years = localDate.getFullYear();\nvar months = (localDate.getMonth() + 1).toString().padStart(2, \"0\");\nvar dates = (localDate.getDate()).toString().padStart(2, \"0\");\nvar hours = localDate.getHours();\nvar minutes = localDate.getMinutes();\nvar seconds = localDate.getSeconds();\n\nhours = (\"0\" + hours).slice(-2);\nminutes = (\"0\" + minutes).slice(-2);\nseconds = (\"0\" + seconds).slice(-2);\n\nmsg.nodered_timestamp = years + \"/\" + months + \"/\" + dates + \" \" + hours + \":\" + minutes + \":\" + seconds;\nmsg.object_timestamp = new Date().getTime() / 1000;\n\nfor (let key in payload) {\n if (payload.hasOwnProperty(key) && payload[key].hasOwnProperty(\"detection\")) {\n if (!(target_object.length == 1 && target_object[0] == \"\")) {\n var skip = true;\n for (let i = 0; i < target_object.length; i++) {\n if (payload[key][\"roi_type\"] == target_object[i]) {\n skip = false;\n break;\n }\n }\n if (skip == true) { continue; }\n }\n if (payload[key][\"detection\"][\"confidence\"] > object_confidence) {\n var current_object_data = {\n \"bbox\": {\n \"vertex1\": { \"x\": payload[key][\"x\"], \"y\": payload[key][\"y\"] },\n \"vertex2\": { \"x\": payload[key][\"x\"] + payload[key][\"w\"], \"y\": payload[key][\"y\"] },\n \"vertex3\": { \"x\": payload[key][\"x\"] + payload[key][\"w\"], \"y\": payload[key][\"y\"] + payload[key][\"h\"] },\n \"vertex4\": { \"x\": payload[key][\"x\"], \"y\": payload[key][\"y\"] + payload[key][\"h\"] },\n \"vertex_0\": { \"x\": payload[key][\"x\"], \"y\": payload[key][\"y\"] }\n }\n }\n // Extract type from detection.label\n if (payload[key].hasOwnProperty(\"detection\") && payload[key][\"detection\"].hasOwnProperty(\"label\")) {\n current_object_data[\"type\"] = payload[key][\"detection\"][\"label\"];\n }\n // Extract color from classification_layer_name:output.label\n if (payload[key].hasOwnProperty(\"classification_layer_name:output\") && payload[key][\"classification_layer_name:output\"].hasOwnProperty(\"label\")) {\n current_object_data[\"color\"] = payload[key][\"classification_layer_name:output\"][\"label\"];\n }\n // Extract license plate (if exists in future)\n if (payload[key].hasOwnProperty(\"license_plate\") && payload[key][\"license_plate\"].hasOwnProperty(\"label\")) {\n current_object_data[\"license_plate\"] = payload[key][\"license_plate\"][\"label\"];\n }\n // Extract tracking ID (if exists)\n if (payload[key].hasOwnProperty(\"id\")) {\n current_object_data[\"id\"] = payload[key][\"id\"];\n }\n // Extract ROI type\n if (payload[key].hasOwnProperty(\"roi_type\")) {\n current_object_data[\"roi_type\"] = payload[key][\"roi_type\"];\n }\n result[`object_${counter++}`] = current_object_data;\n }\n }\n}\n\nif (Object.keys(result).length > 0) {\n msg.payload = result;\n return msg;\n}", | |||
There was a problem hiding this comment.
aren't similar timezone changes needed in metro-ai-suite/metro-vision-ai-app-recipe/smart-parking/helm-chart/config/node-red/flows.json?
| @@ -1307,7 +1307,7 @@ | |||
| "type": "configurations", | |||
| "z": "2720733497fe05f3", | |||
| "name": "configurations 1", | |||
| "func": "//Configurations\nlet target_object = [\"car\", \"truck\", \"bus\"];\nlet video_pipeline_width = 1280;\nlet video_pipeline_height = 720;\nlet object_confidence = 0.3;\nlet intersection_type = \"region\"; // \"object\"\nlet intersection_threshold = 0.8;\nlet distance_threshold = 400;\nlet object_counter = true; //true;\n\n// loitering\nlet stop_duration = 5;\n\n/***************************/\n//Don't touch section below//\n/***************************/\nflow.set(\"target_object\", target_object);\nflow.set(\"video_pipeline_width\", video_pipeline_width);\nflow.set(\"video_pipeline_height\", video_pipeline_height);\nflow.set(\"object_confidence\", object_confidence);\nflow.set(\"intersection_type\", intersection_type);\nflow.set(\"intersection_threshold\", intersection_threshold);\nflow.set(\"distance_threshold\", distance_threshold);\nflow.set(\"object_counter\", object_counter);\n\n// loitering\nflow.set(\"stop_duration\", stop_duration);\n\nreturn msg;", | |||
| "func": "//Configurations\nlet target_object = [\"car\", \"truck\", \"bus\"];\nlet video_pipeline_width = 640;\nlet video_pipeline_height = 480;\nlet object_confidence = 0.3;\nlet intersection_type = \"region\"; // \"object\"\nlet intersection_threshold = 0.8;\nlet distance_threshold = 400;\nlet object_counter = true; //true;\n\n// loitering\nlet stop_duration = 5;\n\n/***************************/\n//Don't touch section below//\n/***************************/\nflow.set(\"target_object\", target_object);\nflow.set(\"video_pipeline_width\", video_pipeline_width);\nflow.set(\"video_pipeline_height\", video_pipeline_height);\nflow.set(\"object_confidence\", object_confidence);\nflow.set(\"intersection_type\", intersection_type);\nflow.set(\"intersection_threshold\", intersection_threshold);\nflow.set(\"distance_threshold\", distance_threshold);\nflow.set(\"object_counter\", object_counter);\n\n// loitering\nflow.set(\"stop_duration\", stop_duration);\n\nreturn msg;", | |||
There was a problem hiding this comment.
similar resolution change is perhaps needed in the helm chart too.
| - "./${SAMPLE_APP}/src/node-red:/data" | ||
| - "./${SAMPLE_APP}/src/dlstreamer-pipeline-server/videos:/data/public/videos" | ||
| - node-red-node-modules:/usr/src/node-red/node_modules | ||
| - /etc/localtime:/etc/localtime:ro |
There was a problem hiding this comment.
isn't this change needed in the helm chart?
Description
Grafana Table Inconsistent appearance is fixed by rate limiting the delay nodes in node-red.
Local TZ mismatch is fixed by adding changes to compose file.
Grafana Table data inconsistency is fixed by changing the transformation in Grafana visualizer.
Smart-Parking Videos' resolution mismatch with pipeline resolution is fixed in node-red.
Added support and troubleshooting steps for Time Sync Issues in Prometheus
Fixes # (issue)
Any Newly Introduced Dependencies
Please describe any newly introduced 3rd party dependencies in this change. List their name, license information and how they are used in the project.
How Has This Been Tested?
Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration
Checklist: