{"id":3217,"date":"2021-05-24T11:33:26","date_gmt":"2021-05-24T03:33:26","guid":{"rendered":"http:\/\/www.magicandlove.com\/blog\/?p=3217"},"modified":"2021-05-24T12:12:40","modified_gmt":"2021-05-24T04:12:40","slug":"script-top-in-touchdesigner","status":"publish","type":"post","link":"http:\/\/www.magicandlove.com\/blog\/2021\/05\/24\/script-top-in-touchdesigner\/","title":{"rendered":"Script TOP in TouchDesigner"},"content":{"rendered":"\n<p>Before we start using MediaPipe in TouchDesigner, we need to be familiar with the use of the <a rel=\"noreferrer noopener\" href=\"https:\/\/docs.derivative.ca\/Script_TOP\" target=\"_blank\">Script TOP<\/a> and <a rel=\"noreferrer noopener\" href=\"https:\/\/docs.derivative.ca\/Script_CHOP\" target=\"_blank\">Script CHOP<\/a> first. For the Script TOP, we can generate the image (TOP) directly from Python code. In the following example, we are going to pass through the incoming image from <a rel=\"noreferrer noopener\" href=\"https:\/\/docs.derivative.ca\/Video_Device_In_TOP\" target=\"_blank\">Video Device In TOP<\/a> to the output window with minimal manipulation in Python inside the Script TOP. The <a rel=\"noreferrer noopener\" href=\"https:\/\/docs.derivative.ca\/OpenCV\" target=\"_blank\">OpenCV in TouchDesigner<\/a> reference page in the Derivative website is a good starting point.<\/p>\n\n\n\n<p>We create a very simple TouchDesigner project, connecting the Video Device In to the Script TOP and then to the Output window. Note that the Script TOP comes with an associated Script Text DAT. We are going to modify the default Python code inside this text area with the name <em>script1_callbacks<\/em>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"567\" src=\"http:\/\/www.magicandlove.com\/blog\/wp-content\/uploads\/2021\/05\/ScriptTOP1-1024x567.png\" alt=\"\" class=\"wp-image-3221\" srcset=\"http:\/\/www.magicandlove.com\/blog\/wp-content\/uploads\/2021\/05\/ScriptTOP1-1024x567.png 1024w, http:\/\/www.magicandlove.com\/blog\/wp-content\/uploads\/2021\/05\/ScriptTOP1-300x166.png 300w, http:\/\/www.magicandlove.com\/blog\/wp-content\/uploads\/2021\/05\/ScriptTOP1-768x425.png 768w, http:\/\/www.magicandlove.com\/blog\/wp-content\/uploads\/2021\/05\/ScriptTOP1-1536x850.png 1536w, http:\/\/www.magicandlove.com\/blog\/wp-content\/uploads\/2021\/05\/ScriptTOP1-2048x1133.png 2048w, http:\/\/www.magicandlove.com\/blog\/wp-content\/uploads\/2021\/05\/ScriptTOP1-690x382.png 690w, http:\/\/www.magicandlove.com\/blog\/wp-content\/uploads\/2021\/05\/ScriptTOP1-980x542.png 980w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p> We can directly edit the Python code inside the <a href=\"https:\/\/docs.derivative.ca\/Text_DAT\" target=\"_blank\" rel=\"noreferrer noopener\">Text DAT<\/a> by turning on the <a href=\"https:\/\/docs.derivative.ca\/Viewer_Active\" target=\"_blank\" rel=\"noreferrer noopener\">Viewer Active<\/a> button in the bottom right corner. Alternately, we can click the Edit button in the parameter window to open the code in your default code editor, <a href=\"https:\/\/developer.apple.com\/xcode\/\" target=\"_blank\" rel=\"noreferrer noopener\">XCode<\/a> in my case.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"575\" src=\"http:\/\/www.magicandlove.com\/blog\/wp-content\/uploads\/2021\/05\/ScriptTOP2-1024x575.png\" alt=\"\" class=\"wp-image-3223\" srcset=\"http:\/\/www.magicandlove.com\/blog\/wp-content\/uploads\/2021\/05\/ScriptTOP2-1024x575.png 1024w, http:\/\/www.magicandlove.com\/blog\/wp-content\/uploads\/2021\/05\/ScriptTOP2-300x169.png 300w, http:\/\/www.magicandlove.com\/blog\/wp-content\/uploads\/2021\/05\/ScriptTOP2-768x432.png 768w, http:\/\/www.magicandlove.com\/blog\/wp-content\/uploads\/2021\/05\/ScriptTOP2-1536x863.png 1536w, http:\/\/www.magicandlove.com\/blog\/wp-content\/uploads\/2021\/05\/ScriptTOP2-2048x1151.png 2048w, http:\/\/www.magicandlove.com\/blog\/wp-content\/uploads\/2021\/05\/ScriptTOP2-690x388.png 690w, http:\/\/www.magicandlove.com\/blog\/wp-content\/uploads\/2021\/05\/ScriptTOP2-980x551.png 980w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<pre class=\"wp-block-preformatted\"># me - this DAT\n# scriptOp - the OP which is cooking\nimport numpy as np\n# press 'Setup Parameters' in the OP to call this function to re-create the parameters.\ndef onSetupParameters(scriptOp):\n     page = scriptOp.appendCustomPage('Custom')\n     p = page.appendFloat('Valuea', label='Value A')\n     p = page.appendFloat('Valueb', label='Value B')\n     return\n\n# called whenever custom pulse parameter is pushed\ndef onPulse(par):\n    return\n\ndef onCook(scriptOp):\n    image = scriptOp.inputs[0].numpyArray(delayed=True, writable=True)\n    image *= 255\n    image = image.astype('uint8')\n    scriptOp.copyNumpyArray(image)\n    return\n<\/pre>\n\n\n\n<p>The code has 3 functions, <em>onSetupParameters<\/em>, <em>onPulse<\/em> and <em>onCook<\/em>. We only use the <em>onCook<\/em> for this example. Cooking is the update of a node when necessary for very frame. The detailed explanation can be found from the <a rel=\"noreferrer noopener\" href=\"https:\/\/docs.derivative.ca\/Cook\" target=\"_blank\">TouchDesigner Cook page<\/a>. Essentially, we can consider it as frame by frame update of the node we are working on. The first function, <em>onSetupParameters<\/em> is triggered by a button in the parameter window under the Setup tab. We can consider it the initialisation of the process. The second function, <em>onPulse<\/em>, will not be used here since we do not have any Pulse button or Pulse parameters defined here. We are going to walk through the simple <em>onCook<\/em> function.<\/p>\n\n\n\n<p>In the first line, <em>scriptOp<\/em> (the current node), will retrieve its first input, 0, (the Video Device In) and convert the current video frame in a NumPy array. The format of the array is Height x Width x RGBA. Each colour pixel is a 32 bit floating point number within the range of 0 to 1. In our case, the video size is 1280 x 720. The 2 optional parameters, delayed=True and writable=True will be explained in the <a rel=\"noreferrer noopener\" href=\"https:\/\/docs.derivative.ca\/TOP_Class\" target=\"_blank\">TOP class reference<\/a>. In this example, we aim to convert the 32 bit floating point colour format to 8 bit unsigned integer for output.<\/p>\n\n\n\n<p>In the second line, each colour pixel will multiply 255 by itself to convert the colour range between 0 to 255.<\/p>\n\n\n\n<p>The third line, the NumPy array is modified into 8 bit unsigned integer format, <em>uint8<\/em>.<\/p>\n\n\n\n<p>The last line will copy back the NumPy array, with the function <a rel=\"noreferrer noopener\" href=\"https:\/\/docs.derivative.ca\/ScriptTOP_Class\" target=\"_blank\">copyNumpyArray<\/a>, into the Script TOP texture for output.<\/p>\n\n\n\n<p>The final TouchDesigner project can be downloaded from this <a href=\"https:\/\/github.com\/chungbwc\/TouchDesigner\/tree\/main\/TestScriptTOP\" target=\"_blank\" rel=\"noreferrer noopener\">GitHub repository<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Before we start using MediaPipe in TouchDesigner, we need to be familiar with the use of the Script TOP and Script CHOP first. For the Script TOP, we can generate the image (TOP) directly from Python code. In the following example, we are going to pass through the incoming image from Video Device In TOP [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[179],"tags":[182,181,84],"class_list":["post-3217","post","type-post","status-publish","format-standard","hentry","category-tutorials","tag-python","tag-script-top","tag-touchdesigner"],"_links":{"self":[{"href":"http:\/\/www.magicandlove.com\/blog\/wp-json\/wp\/v2\/posts\/3217","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.magicandlove.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.magicandlove.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.magicandlove.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.magicandlove.com\/blog\/wp-json\/wp\/v2\/comments?post=3217"}],"version-history":[{"count":10,"href":"http:\/\/www.magicandlove.com\/blog\/wp-json\/wp\/v2\/posts\/3217\/revisions"}],"predecessor-version":[{"id":3231,"href":"http:\/\/www.magicandlove.com\/blog\/wp-json\/wp\/v2\/posts\/3217\/revisions\/3231"}],"wp:attachment":[{"href":"http:\/\/www.magicandlove.com\/blog\/wp-json\/wp\/v2\/media?parent=3217"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.magicandlove.com\/blog\/wp-json\/wp\/v2\/categories?post=3217"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.magicandlove.com\/blog\/wp-json\/wp\/v2\/tags?post=3217"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}