Compare to images , get simularity in percentage

Hey Community,

i've to solve a Issue and i want to solve it by using Node Red. I want
to compare static images if they are the same or if they get changed. So i have
researched and found no package for Node Red only for node.js like "pixelmatch" or "looksSame"
is it possible to use to use node.js in nood red and how does it work or is there a package
for this issue i can use ?

Hi, welcome to the forum

You can import npm modules in a function node.

See this for info: Use any npm module in Node-RED • FlowFuse

To simplify image loading and accessing the bitmap data, you might find node-red-contrib-image-tools useful to accompany your solution.

Thank you for the quick response! When I navigate to the “Setup” section, I don’t see an “Add” button as you mentioned

What version of Node-RED are you using?

What version of Node are you using?

How is node-red installed and on what kind of hardware (docker install? preinstalled on a device? etc)

I'am using the Web Based Node Red v1.3.4. About the rest i'am not sure

Sorry, I have no idea what that is.

As for v1.3.4, that is simply too old. Current version is 3.1.9.

If you own a computer or Raspberry PI or similar compute, I recommend you install it yourself. Instructions are here: Running Node-RED locally : Node-RED

If you prefer, you can have FlowFuse host an instance of Node-RED for you, that way it is always up-to-date, fully secured and available to you anywhere on the WWW via HTTPS.

Okay, so I need to update in order to follow the instructions at the top. Thanks for your reply! :blush:

Hey Community,

now i get the new version for Node Red and the feature to import nmp modules. My current Flow does not work and i am not really sure if this caused by the nmp module or an issue by creating my Flow.

Here is my Flow:

[{"id":"9b45551cf8e4940c","type":"tab","label":"Jimp Test","disabled":false,"info":"","env":[]},{"id":"b749c088395cfc6b","type":"inject","z":"9b45551cf8e4940c","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":200,"y":340,"wires":[["d636c0680b0e435b","04af7ada16746f5f"]]},{"id":"5eba8b909ed2b57c","type":"function","z":"9b45551cf8e4940c","name":"","func":"// Vergleiche zwei Bilder in Node-RED mit Jimp\ncompare();\nasync function compare() {\n  const Jimp = require(\"jimp\");\n\n  // Lade die Bilder aus den Base64-Daten\n  let Bild1 = await Jimp.read(Buffer.from(msg.katze1, 'base64'));\n  let Bild2 = await Jimp.read(Buffer.from(msg.katze2, 'base64'));\n\n  var distance = Jimp.distance(Bild1, Bild2);\n  // Berechne den Unterschied\n  var diff = Jimp.diff(Bild1, Bild2);\n  const Prozentsatz = diff.percent;\n\n  // Setze das Ergebnis in die Nachricht\n  msg.payload = Prozentsatz;\n  \n\n}\n\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[{"var":"jimp","module":"jimp"}],"x":600,"y":360,"wires":[["347647cebe97a6e0"]]},{"id":"347647cebe97a6e0","type":"debug","z":"9b45551cf8e4940c","name":"","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"true","targetType":"full","statusVal":"payload","statusType":"auto","x":830,"y":360,"wires":[]},{"id":"84c471c1ac55aefd","type":"comment","z":"9b45551cf8e4940c","name":"Bezugsbild","info":"","x":260,"y":200,"wires":[]},{"id":"16e6b5eeafbfb6ca","type":"comment","z":"9b45551cf8e4940c","name":"aktuelles Bild","info":"","x":270,"y":400,"wires":[]},{"id":"ca4bb3362081ee28","type":"comment","z":"9b45551cf8e4940c","name":"vergleicher","info":"","x":600,"y":300,"wires":[]},{"id":"04af7ada16746f5f","type":"jimp-image","z":"9b45551cf8e4940c","name":"","data":"https://www.bmel.de/SharedDocs/Bilder/DE/_Tiere/Haus-Zootiere/tierschutz-hunde.jpg?__blob=wide&v=3","dataType":"str","ret":"b64","parameter1":"","parameter1Type":"msg","parameter2":"","parameter2Type":"msg","parameter3":"","parameter3Type":"msg","parameter4":"","parameter4Type":"msg","parameter5":"","parameter5Type":"msg","parameter6":"","parameter6Type":"msg","parameter7":"","parameter7Type":"msg","parameter8":"","parameter8Type":"msg","sendProperty":"katze1","sendPropertyType":"msg","parameterCount":0,"jimpFunction":"none","selectedJimpFunction":{"name":"none","fn":"none","description":"Just loads the image.","parameters":[]},"x":250,"y":240,"wires":[["611e9730620a696f"]]},{"id":"d636c0680b0e435b","type":"jimp-image","z":"9b45551cf8e4940c","name":"","data":"https://image.geo.de/34423086/t/u8/v1/w1440/r0/-/katze-as-97589769.jpg","dataType":"str","ret":"b64","parameter1":"","parameter1Type":"msg","parameter2":"","parameter2Type":"msg","parameter3":"","parameter3Type":"msg","parameter4":"","parameter4Type":"msg","parameter5":"","parameter5Type":"msg","parameter6":"","parameter6Type":"msg","parameter7":"","parameter7Type":"msg","parameter8":"","parameter8Type":"msg","sendProperty":"katze2","sendPropertyType":"msg","parameterCount":0,"jimpFunction":"none","selectedJimpFunction":{"name":"none","fn":"none","description":"Just loads the image.","parameters":[]},"x":250,"y":440,"wires":[["074e3afb7cd0e7b2"]]},{"id":"611e9730620a696f","type":"image viewer","z":"9b45551cf8e4940c","name":"","width":160,"data":"katze1","dataType":"msg","active":true,"x":410,"y":240,"wires":[["5eba8b909ed2b57c"]]},{"id":"074e3afb7cd0e7b2","type":"image viewer","z":"9b45551cf8e4940c","name":"","width":160,"data":"katze2","dataType":"msg","active":true,"x":410,"y":440,"wires":[["5eba8b909ed2b57c"]]}]

First off, your flow can not be imported due to the tab and debug including "env":[x]

Secondly in your function node you are trying to address data from two paths. that data will arrive at two different times. You need to add a join node before the function node to access the combined data.

See this article in the cookbook for an example of how to join messages into one object.

Apologies for the unsuccessful flow. I’ve resolved the flow access issue and made a few changes to the flow. Unfortunately, it still doesn’t work as expected

[{"id":"b49d85e0d81629eb","type":"tab","label":"Jimp Test","disabled":false,"info":"","env":[]},{"id":"0783c6a62c16d275","type":"inject","z":"b49d85e0d81629eb","d":true,"name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":200,"y":340,"wires":[["808dc2eb855ebf72","38c022b02257c376"]]},{"id":"58d41be39510885c","type":"function","z":"b49d85e0d81629eb","d":true,"name":"","func":"// Vergleiche zwei Bilder in Node-RED mit Jimp\nconst test = compare();\nasync function compare() {\n\n\n  // Lade die Bilder aus den Base64-Daten\n  let Bild1 = await jimp.read(Buffer.from(msg.katze1, 'base64'));\n  let Bild2 = await jimp.read(Buffer.from(msg.katze2, 'base64'));\n\n  // Berechne den Unterschied\n  var diff = jimp.diff(Bild1, Bild2);\n  const Prozentsatz = diff.percent;\n\n  // Setze das Ergebnis in die Nachricht\n\n  \n\n}\nmsg.payload = test;\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[{"var":"jimp","module":"jimp"}],"x":820,"y":360,"wires":[["fce2138939e629ab"]]},{"id":"fce2138939e629ab","type":"debug","z":"b49d85e0d81629eb","d":true,"name":"","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"true","targetType":"full","statusVal":"payload","statusType":"auto","x":1030,"y":360,"wires":[]},{"id":"3cb9b3902dfd9169","type":"comment","z":"b49d85e0d81629eb","d":true,"name":"Bezugsbild","info":"","x":260,"y":200,"wires":[]},{"id":"daa04a5959ad38d7","type":"comment","z":"b49d85e0d81629eb","d":true,"name":"aktuelles Bild","info":"","x":270,"y":400,"wires":[]},{"id":"5e40198abd21b82f","type":"comment","z":"b49d85e0d81629eb","d":true,"name":"vergleicher","info":"","x":820,"y":320,"wires":[]},{"id":"38c022b02257c376","type":"jimp-image","z":"b49d85e0d81629eb","d":true,"name":"image1","data":"https://www.bmel.de/SharedDocs/Bilder/DE/_Tiere/Haus-Zootiere/tierschutz-hunde.jpg?__blob=wide&v=3","dataType":"str","ret":"b64","parameter1":"","parameter1Type":"msg","parameter2":"","parameter2Type":"msg","parameter3":"","parameter3Type":"msg","parameter4":"","parameter4Type":"msg","parameter5":"","parameter5Type":"msg","parameter6":"","parameter6Type":"msg","parameter7":"","parameter7Type":"msg","parameter8":"","parameter8Type":"msg","sendProperty":"parts","sendPropertyType":"msg","parameterCount":0,"jimpFunction":"none","selectedJimpFunction":{"name":"none","fn":"none","description":"Just loads the image.","parameters":[]},"x":260,"y":240,"wires":[["a5f8b8a14fc658f5"]]},{"id":"808dc2eb855ebf72","type":"jimp-image","z":"b49d85e0d81629eb","d":true,"name":"image2","data":"https://image.geo.de/34423086/t/u8/v1/w1440/r0/-/katze-as-97589769.jpg","dataType":"str","ret":"b64","parameter1":"","parameter1Type":"msg","parameter2":"","parameter2Type":"msg","parameter3":"","parameter3Type":"msg","parameter4":"","parameter4Type":"msg","parameter5":"","parameter5Type":"msg","parameter6":"","parameter6Type":"msg","parameter7":"","parameter7Type":"msg","parameter8":"","parameter8Type":"msg","sendProperty":"parts","sendPropertyType":"msg","parameterCount":0,"jimpFunction":"none","selectedJimpFunction":{"name":"none","fn":"none","description":"Just loads the image.","parameters":[]},"x":260,"y":440,"wires":[["5b526e874ddc6c7b"]]},{"id":"a5f8b8a14fc658f5","type":"image viewer","z":"b49d85e0d81629eb","d":true,"name":"","width":160,"data":"parts","dataType":"msg","active":true,"x":410,"y":240,"wires":[["d0c7cc0a24d420b0"]]},{"id":"5b526e874ddc6c7b","type":"image viewer","z":"b49d85e0d81629eb","d":true,"name":"","width":160,"data":"parts","dataType":"msg","active":true,"x":410,"y":440,"wires":[["d0c7cc0a24d420b0"]]},{"id":"d0c7cc0a24d420b0","type":"join","z":"b49d85e0d81629eb","d":true,"name":"","mode":"auto","build":"object","property":"payload","propertyType":"msg","key":"keyValue","joiner":"\\n","joinerType":"str","accumulate":true,"timeout":"","count":"2","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":630,"y":360,"wires":[["58d41be39510885c"]]},{"id":"f37cf4c0ef559928","type":"inject","z":"b49d85e0d81629eb","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":180,"y":760,"wires":[["3169ac9110968536"]]},{"id":"3169ac9110968536","type":"function","z":"b49d85e0d81629eb","name":"","func":"// Vergleiche zwei Bilder in Node-RED mit Jimp\nconst test = compare();\nasync function compare() {\n\n\n  // Lade die Bilder aus den Base64-Daten\n  let Bild1 = await jimp.read(Buffer.from(\"https://www.bmel.de/SharedDocs/Bilder/DE/_Tiere/Haus-Zootiere/tierschutz-hunde.jpg?__blob=wide&v=3\"));\n  let Bild2 = await jimp.read(Buffer.from(\"https://image.geo.de/34423086/t/u8/v1/w1440/r0/-/katze-as-97589769.jpg\"));\n\n  // Berechne den Unterschied\n  var diff = jimp.diff(Bild1, Bild2);\n  const Prozentsatz = diff.percent;\n\n  msg.payload = Prozentsatz;\n\n  \n\n}\nmsg.payload = test;\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[{"var":"jimp","module":"jimp"}],"x":480,"y":760,"wires":[["849b526bcc90949e"]]},{"id":"849b526bcc90949e","type":"debug","z":"b49d85e0d81629eb","name":"","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"true","targetType":"full","statusVal":"payload","statusType":"auto","x":690,"y":760,"wires":[]}]

When working with large data (like images) it is wise to keep everything in series (every time a node has more than one wire attached to its output, the msg is cloned. This can be REALLY expensive when working with images).

Next, you dont NEED to join - image tools can output to any msg property you desire. In the example below, i outputed image 1 to msg.image1 and then the 2nd to msg.image2 - this means they are both in the message at the same time and there is no need to fork and join.

Flow...

[{"id":"0783c6a62c16d275","type":"inject","z":"b49d85e0d81629eb","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":120,"y":140,"wires":[["38c022b02257c376"]]},{"id":"58d41be39510885c","type":"function","z":"b49d85e0d81629eb","name":"","func":"msg.payload = Jimp.diff(msg.image1, msg.image2, .1);\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[{"var":"Jimp","module":"jimp"}],"x":780,"y":140,"wires":[["cfd47baf86adbe7d"]]},{"id":"fce2138939e629ab","type":"debug","z":"b49d85e0d81629eb","name":"","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"true","targetType":"full","statusVal":"\"Diff: \" & (msg.payload.percent * 100) & \"%\"","statusType":"jsonata","x":970,"y":220,"wires":[]},{"id":"3cb9b3902dfd9169","type":"comment","z":"b49d85e0d81629eb","name":"Bezugsbild","info":"","x":320,"y":100,"wires":[]},{"id":"daa04a5959ad38d7","type":"comment","z":"b49d85e0d81629eb","name":"aktuelles Bild","info":"","x":550,"y":100,"wires":[]},{"id":"5e40198abd21b82f","type":"comment","z":"b49d85e0d81629eb","name":"vergleicher","info":"","x":780,"y":100,"wires":[]},{"id":"38c022b02257c376","type":"jimp-image","z":"b49d85e0d81629eb","name":"image1","data":"https://www.bmel.de/SharedDocs/Bilder/DE/_Tiere/Haus-Zootiere/tierschutz-hunde.jpg?__blob=wide&v=3","dataType":"str","ret":"img","parameter1":"","parameter1Type":"msg","parameter2":"","parameter2Type":"msg","parameter3":"","parameter3Type":"msg","parameter4":"","parameter4Type":"msg","parameter5":"","parameter5Type":"msg","parameter6":"","parameter6Type":"msg","parameter7":"","parameter7Type":"msg","parameter8":"","parameter8Type":"msg","sendProperty":"image1","sendPropertyType":"msg","parameterCount":0,"jimpFunction":"none","selectedJimpFunction":{"name":"none","fn":"none","description":"Just loads the image.","parameters":[]},"x":300,"y":140,"wires":[["a5f8b8a14fc658f5"]]},{"id":"808dc2eb855ebf72","type":"jimp-image","z":"b49d85e0d81629eb","name":"image2","data":"https://image.geo.de/34423086/t/u8/v1/w1440/r0/-/katze-as-97589769.jpg","dataType":"str","ret":"img","parameter1":"","parameter1Type":"msg","parameter2":"","parameter2Type":"msg","parameter3":"","parameter3Type":"msg","parameter4":"","parameter4Type":"msg","parameter5":"","parameter5Type":"msg","parameter6":"","parameter6Type":"msg","parameter7":"","parameter7Type":"msg","parameter8":"","parameter8Type":"msg","sendProperty":"image2","sendPropertyType":"msg","parameterCount":0,"jimpFunction":"none","selectedJimpFunction":{"name":"none","fn":"none","description":"Just loads the image.","parameters":[]},"x":540,"y":140,"wires":[["5b526e874ddc6c7b"]]},{"id":"a5f8b8a14fc658f5","type":"image viewer","z":"b49d85e0d81629eb","name":"","width":"120","data":"image1","dataType":"msg","active":true,"x":290,"y":220,"wires":[["808dc2eb855ebf72"]]},{"id":"5b526e874ddc6c7b","type":"image viewer","z":"b49d85e0d81629eb","name":"","width":"120","data":"image2","dataType":"msg","active":true,"x":530,"y":220,"wires":[["58d41be39510885c"]]},{"id":"cfd47baf86adbe7d","type":"image viewer","z":"b49d85e0d81629eb","name":"","width":160,"data":"payload.image","dataType":"msg","active":true,"x":770,"y":220,"wires":[["fce2138939e629ab"]]}]
3 Likes

Can we assume this works for you and mark it as a solution?