{"id":15393,"date":"2019-03-23T16:38:00","date_gmt":"2019-03-23T20:38:00","guid":{"rendered":"http:\/\/scruss.com\/blog\/?p=15393"},"modified":"2020-05-11T21:48:50","modified_gmt":"2020-05-12T01:48:50","slug":"hsvish-colour-wheel-in-python","status":"publish","type":"post","link":"https:\/\/scruss.com\/blog\/2019\/03\/23\/hsvish-colour-wheel-in-python\/","title":{"rendered":"HSV(ish) Colour Wheel in Python"},"content":{"rendered":"\n<p>Years back I wrote something about <a href=\"https:\/\/scruss.com\/blog\/2010\/09\/19\/much-improved-hsv-colour-cycling-led-on-arduino\/\">HSV colour cycling<\/a> for Arduino. Things have moved on: we&#8217;re all writing code in MicroPython\/CircuitPython now and 8-bit micro-controllers are looking decidedly quaint. Yes, yes; some of you must still write code in PIC assembly language and I&#8217;m sure that&#8217;s <em>very<\/em> lovely for you indeed don&#8217;t @ me.<\/p>\n\n\n\n<p>If you look at the output of a typical HSV to RGB algorithm, the components map something like this:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"848\" height=\"455\" src=\"https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2019\/03\/hsv_to_rgb.jpg\" alt=\"\" class=\"wp-image-15394\" srcset=\"https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2019\/03\/hsv_to_rgb.jpg 848w, https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2019\/03\/hsv_to_rgb-160x86.jpg 160w, https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2019\/03\/hsv_to_rgb-320x172.jpg 320w, https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2019\/03\/hsv_to_rgb-768x412.jpg 768w\" sizes=\"auto, (max-width: 848px) 100vw, 848px\" \/><figcaption>Hue between 0-1, with saturation and value set to 1. Output range 0-1 for each component<\/figcaption><\/figure>\n\n\n\n<p>These lines remind me so much of sine waves, if very blocky ones. The red trace in particular is just the <strong>cosine<\/strong> function, with the input range of 0..2\u00cf\u20ac and the output range of -1..1 both mapped to 0..1. The green and blue traces are just the red trace shifted horizontally by \u00e2\u2026\u201c and \u00e2\u2026\u201d respectively.<\/p>\n\n\n\n<p>Since we have transcendental functions in MicroPython, we don&#8217;t have to fossick about with linear approximations. The common RGB LED function <a href=\"https:\/\/github.com\/adafruit\/Adafruit_Learning_System_Guides\/blob\/master\/Introducing_CircuitPlaygroundExpress\/CircuitPlaygroundExpress_NeoPixel.py#L20\">wheel()<\/a> uses similar linear interpolation as the graph above. Why make do with blocky cogwheels when you can have a smooth colour wheel?<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\ndef cos_wheel(pos):\n     # Input a value 0 to 255 to get a colour value.\n     # scruss (Stewart Russell) - 2019-03 - CC-BY-SA\n     from math import cos, pi\n     if pos &lt; 0:\n         return (0, 0, 0)\n     pos %= 256\n     pos \/= 255.0\n     return (int(255 * (1 + cos( pos            * 2 * pi)) \/ 2),\n             int(255 * (1 + cos((pos - 1 \/ 3.0) * 2 * pi)) \/ 2),\n             int(255 * (1 + cos((pos - 2 \/ 3.0) * 2 * pi)) \/ 2))\n<\/pre><\/div>\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"584\" src=\"https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2019\/03\/Screenshot-from-2019-03-23-21-02-03-1024x584.png\" alt=\"\" class=\"wp-image-15398\" srcset=\"https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2019\/03\/Screenshot-from-2019-03-23-21-02-03-1024x584.png 1024w, https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2019\/03\/Screenshot-from-2019-03-23-21-02-03-160x91.png 160w, https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2019\/03\/Screenshot-from-2019-03-23-21-02-03-320x183.png 320w, https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2019\/03\/Screenshot-from-2019-03-23-21-02-03-768x438.png 768w, https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2019\/03\/Screenshot-from-2019-03-23-21-02-03.png 1122w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>Though you never quite get a pure red, green or blue, the results are pleasing<\/figcaption><\/figure>\n\n\n\n<p>Quite elegant, I thought. Yeah, it may be computationally expensive, but check next year when we&#8217;ll all be running even faster \u00c2\u00b5cs. Certainly none of the mystery switch statements or nested conditionals you&#8217;ll see in other code. Just maths, doing its thing.<\/p>\n\n\n\n<figure class=\"wp-block-video\"><video height=\"360\" style=\"aspect-ratio: 640 \/ 360;\" width=\"640\" controls src=\"https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2019\/03\/cpx_cosine.mp4\"><\/video><figcaption>First half is cosine wheel, second half (after red flash) is linear<\/figcaption><\/figure>\n","protected":false},"excerpt":{"rendered":"<p>Years back I wrote something about HSV colour cycling for Arduino. Things have moved on: we&#8217;re all writing code in MicroPython\/CircuitPython now and 8-bit micro-controllers are looking decidedly quaint. Yes, yes; some of you must still write code in PIC assembly language and I&#8217;m sure that&#8217;s very lovely for you indeed don&#8217;t @ me. If [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[7],"tags":[2213],"class_list":["post-15393","post","type-post","status-publish","format-standard","hentry","category-computers-suck","tag-hsv"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/pQNZZ-40h","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/posts\/15393","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/comments?post=15393"}],"version-history":[{"count":8,"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/posts\/15393\/revisions"}],"predecessor-version":[{"id":16256,"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/posts\/15393\/revisions\/16256"}],"wp:attachment":[{"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/media?parent=15393"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/categories?post=15393"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/tags?post=15393"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}