-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path[IMG] Annotate [TF].json
1 lines (1 loc) · 8 KB
/
[IMG] Annotate [TF].json
1
[{"id":"4e11b7ba67d55a6b","type":"subflow","name":"[IMG] Annotate [TF]","info":"","category":"Tequ-API Client","in":[{"x":140,"y":140,"wires":[{"id":"d7a726cdc1ba008c"}]}],"out":[{"x":800,"y":140,"wires":[{"id":"9071309af7a7291a","port":0}]}],"env":[{"name":"box_colors","type":"json","value":"{\"fish\":\"#FFFFFF\",\"pike\":\"#006400\",\"perch\":\"#008000\",\"smolt\":\"#ADD8E6\",\"salmon\":\"#0000FF\",\"trout\":\"#0000FF\",\"cyprinidae\":\"#808080\",\"zander\":\"#009000\",\"bream\":\"#008800\"}","ui":{"type":"input","opts":{"types":["json"]}}},{"name":"image_settings","type":"json","value":"{\"quality\":0.8}","ui":{"type":"input","opts":{"types":["json"]}}},{"name":"image_type","type":"str","value":"image/jpeg","ui":{"type":"select","opts":{"opts":[{"l":{"en-US":"JPG"},"v":"image/jpeg"},{"l":{"en-US":"PNG"},"v":"image/png"}]}}},{"name":"bbox_lineWidth","type":"num","value":"5","ui":{"type":"spinner","opts":{"min":0,"max":10}}},{"name":"bbox_text_color","type":"str","value":"white","ui":{"type":"select","opts":{"opts":[{"l":{"en-US":"white"},"v":"white"},{"l":{"en-US":"black"},"v":"black"},{"l":{"en-US":"blue"},"v":"blue"},{"l":{"en-US":"green"},"v":"green"},{"l":{"en-US":"yellow"},"v":"yellow"},{"l":{"en-US":"red"},"v":"red"},{"l":{"en-US":"orange"},"v":"orange"}]}}},{"name":"bbox_font","type":"str","value":"30px Arial","ui":{"type":"select","opts":{"opts":[{"l":{"en-US":"5px Arial"},"v":"5 px Arial"},{"l":{"en-US":"10px Arial"},"v":"10px Arial"},{"l":{"en-US":"15px Arial"},"v":"15px Arial"},{"l":{"en-US":"20px Arial"},"v":"20px Arial"},{"l":{"en-US":"25px Arial"},"v":"25px Arial"},{"l":{"en-US":"30px Arial"},"v":"30px Arial"},{"l":{"en-US":"35px Arial"},"v":"35px Arial"},{"l":{"en-US":"40px Arial"},"v":"40px Arial"},{"l":{"en-US":"45px Arial"},"v":"45px Arial"},{"l":{"en-US":"50px Arial"},"v":"50px Arial"}]}}},{"name":"label_offset_x","type":"num","value":"0","ui":{"type":"input","opts":{"types":["num"]}}},{"name":"label_offset_y","type":"num","value":"30","ui":{"type":"input","opts":{"types":["num"]}}},{"name":"threshold","type":"num","value":"0.75","ui":{"type":"spinner","opts":{"min":0,"max":1}}},{"name":"width","type":"num","value":"50","ui":{"type":"input","opts":{"types":["num","env"]}}},{"name":"height","type":"num","value":"50","ui":{"type":"input","opts":{"types":["num","env"]}}}],"meta":{"module":"[IMG] Annotate [TF]","version":"0.0.1","author":"[email protected]","desc":"Annotates prediction results from [AI] Detect subflows.","license":"MIT"},"color":"#87A980","icon":"font-awesome/fa-pencil-square-o","status":{"x":800,"y":200,"wires":[{"id":"1267cc4998d8726c","port":0}]}},{"id":"d7a726cdc1ba008c","type":"function","z":"4e11b7ba67d55a6b","name":"Annotate with canvas","func":"const start_ms = Date.now();\nconst img = msg.payload;\nconst objects = msg.data.properties.computer_vision.result\nconst labels = msg.data.properties.computer_vision.labels\nconst image_type = env.get(\"image_type\");\nconst image_settings = env.get(\"image_settings\");\nconst bbox_lineWidth = env.get(\"bbox_lineWidth\");\nconst bbox_text_color = env.get(\"bbox_text_color\");\nconst label_offset_x = env.get(\"label_offset_x\");\nconst label_offset_y = env.get(\"label_offset_y\");\nconst bbox_font = env.get(\"bbox_font\");\nconst COLORS = env.get(\"box_colors\");\n\n//Define threshold\nlet threshold = 0;\nlet diff_ms = 0;\nlet do_annotate = false;\n\nconst global_settings = global.get(\"settings\") || undefined\nlet thresholdType = \"\"\n\nif (global_settings !== undefined) {\n if (\"threshold\" in global_settings) {\n threshold = global_settings[\"threshold\"]\n thresholdType = \"global\";\n }\n}\n\nelse if (\"threshold\" in msg) {\n threshold = msg.threshold;\n thresholdType = \"msg\";\n if (threshold < 0) {\n threshold = 0\n }\n else if (threshold > 1) {\n threshold = 1\n }\n}\n\nelse {\n threshold = env.get(\"threshold\");\n thresholdType = \"env\";\n}\n\nmsg.thresholdUsed = threshold;\nmsg.thresholdTypeUsed = thresholdType;\n\nasync function annotateImage(image) {\n const localImage = await canvas.loadImage(image);\n const cvs = canvas.createCanvas(localImage.width, localImage.height);\n const ctx = cvs.getContext('2d');\n ctx.drawImage(localImage, 0, 0);\n\n objects.forEach((obj) => {\n if (labels.includes(obj.class) && obj.score >= threshold) {\n let [x, y, w, h] = obj.bbox;\n ctx.lineWidth = bbox_lineWidth;\n ctx.strokeStyle = COLORS[obj.class];\n ctx.strokeRect(x, y, w, h);\n ctx.fillStyle = bbox_text_color;\n ctx.font = bbox_font;\n ctx.fillText(obj.class + \" \" + Math.round(obj.score * 100) + \" %\", x + label_offset_x, y + label_offset_y);\n }\n });\n\n return cvs.toBuffer(image_type, image_settings);\n}\n\nif (objects.length > 0) {\n\n for (let i = 0; i < objects.length; i++) {\n if (objects[i].score >= threshold) {\n do_annotate = true;\n }\n }\n\n if (do_annotate) {\n msg.data.properties.object.data.annotated.image = await annotateImage(img)\n msg.objects_found = true\n diff_ms = Date.now() - start_ms\n msg.annotated_image = msg.data.properties.object.data.annotated.image;\n node.status({ fill: \"green\", shape: \"dot\", text: diff_ms + \" ms\" });\n }\n else {\n diff_ms = Date.now() - start_ms\n msg.annotated_image = img;\n node.status({ fill: \"red\", shape: \"dot\", text: \"No objects over threshold\" });\n }\n}\nelse {\n msg.objects_found = false\n diff_ms = Date.now() - start_ms\n msg.annotated_image = img;\n node.status({ fill: \"red\", shape: \"dot\", text: \"No objects to annotate\" });\n}\n\nmsg.data.properties.object.data.annotated.annotation_ms = diff_ms\ndelete msg.thresholdUsed;\ndelete msg.start;\ndelete msg.thresholdTypeUsed;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[{"var":"canvas","module":"canvas"}],"x":300,"y":140,"wires":[["9071309af7a7291a"]]},{"id":"1267cc4998d8726c","type":"status","z":"4e11b7ba67d55a6b","name":"","scope":null,"x":620,"y":200,"wires":[[]]},{"id":"9071309af7a7291a","type":"function","z":"4e11b7ba67d55a6b","name":"Create thumbnail","func":"async function resize(inputTensor, width, height) {\n return tf.tidy(() => {\n let resized = tf.image.resizeBilinear(inputTensor, [height, width])\n resized = tf.reshape(resized, [height, width, 3])\n return Promise.resolve(tf.node.encodeJpeg(resized));\n });\n}\n\nasync function convert(input) {\n return tf.tidy(() => {\n const tensor = tf.node.decodeJpeg(input, 3).expandDims(0);\n const shape = tensor.shape;\n return tensor\n });\n}\n\ntry{ \n if(msg.objects_found){\n let thumbnail_time_ms;\n const image = msg.data.properties.object.data.annotated.image;\n const start = Date.now();\n const width = env.get(\"width\")\n const height = env.get(\"height\")\n const tensor = await convert(image)\n const thumbnail = Buffer.from(await resize(tensor, width, height))\n msg.data.properties.object.data.annotated.thumbnail = thumbnail\n thumbnail_time_ms = Date.now() - start;\n msg.data.properties.object.data.annotated.thumbnail_ms = thumbnail_time_ms;\n node.status({ fill: \"green\", shape: \"dot\", text: thumbnail_time_ms + \" ms\" });\n }\n return msg;\n}\ncatch (e) {\n node.warn(e)\n node.status({ fill: \"red\", shape: \"dot\", text: \"Convert failed...\" });\n node.error(\"Resizing failed. Probably input is not an image buffer.\", msg);\n}","outputs":1,"noerr":0,"initialize":"","finalize":"// Code added here will be run when the\n// node is being stopped or re-deployed.\nconst model = context.get(\"savedmodel\")\ntf.dispose(model)\ncontext.set(\"model\", undefined)\ncontext.set(\"modelInfo\", undefined)","libs":[{"var":"tf","module":"@tensorflow/tfjs-node-gpu"}],"x":590,"y":140,"wires":[[]]},{"id":"f887275f3b1bdd7c","type":"subflow:4e11b7ba67d55a6b","z":"7b248573a2bd55b0","name":"","x":230,"y":520,"wires":[[]]}]