{"id":558,"date":"2011-03-20T15:02:14","date_gmt":"2011-03-20T20:02:14","guid":{"rendered":"http:\/\/nootropicdesign.com\/projectlab\/?p=558"},"modified":"2017-12-28T11:17:34","modified_gmt":"2017-12-28T17:17:34","slug":"arduino-computer-vision","status":"publish","type":"post","link":"https:\/\/nootropicdesign.com\/projectlab\/2011\/03\/20\/arduino-computer-vision\/","title":{"rendered":"Arduino Computer Vision"},"content":{"rendered":"<p><strong><em>Difficulty Level = 5<\/em><\/strong>  <a href=\"\/projectlab\/difficulty-levels\/\">[What&#8217;s this?]<\/a><\/p>\n<p>The <a href=\"\/ve\">Video Experimenter<\/a> shield can give your Arduino the gift of sight.  In the <a href=\"\/projectlab\/2011\/03\/20\/video-frame-capture\/\"> Video Frame Capture<\/a> project, I showed how to capture images from a composite video source and display them on a TV.  We can take this concept further by processing the contents of the captured image to implement object tracking and edge detection.<\/p>\n<p>The setup is the same as when capturing video frames: a video source like a camera is connected to the video input.  The output select switch is set to &#8220;overlay&#8221;, and sync select jumper set to &#8220;video input&#8221;.  Set the analog threshold potentiometer to the lowest setting.<\/p>\n<h3>Object Tracking<\/h3>\n<p>Here is an Arduino sketch that captures a video frame and then computes the bounding box of the brightest region in the image.  <\/p>\n<p><iframe loading=\"lazy\" width=\"560\" height=\"349\" src=\"https:\/\/www.youtube.com\/embed\/DIGZXcg0NIA?rel=0\" frameborder=\"0\" allowfullscreen><\/iframe><br \/>\n<br clear=\"all\"\/><br \/>\nThis project is the example &#8220;ObjectTracking&#8221; in the <a target=\"_blank\" href=\"https:\/\/github.com\/nootropicdesign\/arduino-tvout-ve\">TVout library for Video Experimenter<\/a>.  The code first calls <span class=\"code\">tv.capture()<\/span> to capture a frame.  Then it computes a simple bounding box for the brightest spot in the image.  After computing the location of the brightest area, a box is drawn and the coordinates of the box are printed to the TVout frame buffer.  Finally, <span class=\"code\">tv.resume()<\/span> is called to resume the output and display the box and coordinates on the screen.  <\/p>\n<p>Keep in mind that there is no need to display any output at all &#8212; we just do this so we can see what&#8217;s going on.  If you have a robot with a camera on it, you can detect\/track objects with Arduino code, and the output of the Video Experimenter doesn&#8217;t need to be connected to anything (although the analog threshold potentiometer would probably need some adjustment).<\/p>\n<p>If you use a television with the PAL standard (that is, you are not in North America), change <span class=\"code\">tv.begin(NTSC, W, H)<\/span> to <span class=\"code\">tv.begin(PAL, W, H)<\/span>.<\/p>\n<pre class=\"codeblockscroll\">\r\n#include &lt;TVout.h&gt;\r\n#include &lt;fontALL.h&gt;\r\n#define W 128\r\n#define H 96\r\n\r\nTVout tv;\r\nunsigned char x, y;\r\nunsigned char c;\r\nunsigned char minX, minY, maxX, maxY;\r\nchar s[32];\r\n\r\n\r\nvoid setup()  {\r\n  tv.begin(NTSC, W, H);\r\n  initOverlay();\r\n  initInputProcessing();\r\n\r\n  tv.select_font(font4x6);\r\n  tv.fill(0);\r\n}\r\n\r\n\r\nvoid initOverlay() {\r\n  TCCR1A = 0;\r\n  \/\/ Enable timer1.  ICES0 is set to 0 for falling edge detection on input capture pin.\r\n  TCCR1B = _BV(CS10);\r\n\r\n  \/\/ Enable input capture interrupt\r\n  TIMSK1 |= _BV(ICIE1);\r\n\r\n  \/\/ Enable external interrupt INT0 on pin 2 with falling edge.\r\n  EIMSK = _BV(INT0);\r\n  EICRA = _BV(ISC01);\r\n}\r\n\r\nvoid initInputProcessing() {\r\n  \/\/ Analog Comparator setup\r\n  ADCSRA &= ~_BV(ADEN); \/\/ disable ADC\r\n  ADCSRB |= _BV(ACME); \/\/ enable ADC multiplexer\r\n  ADMUX &= ~_BV(MUX0);  \/\/ select A2 for use as AIN1 (negative voltage of comparator)\r\n  ADMUX |= _BV(MUX1);\r\n  ADMUX &= ~_BV(MUX2);\r\n  ACSR &= ~_BV(ACIE);  \/\/ disable analog comparator interrupts\r\n  ACSR &= ~_BV(ACIC);  \/\/ disable analog comparator input capture\r\n}\r\n\r\n\/\/ Required\r\nISR(INT0_vect) {\r\n  display.scanLine = 0;\r\n}\r\n\r\n\r\nvoid loop() {\r\n  tv.capture();\r\n\r\n  \/\/ uncomment if tracking dark objects\r\n  \/\/tv.fill(INVERT);\r\n\r\n  \/\/ compute bounding box\r\n  minX = W;\r\n  minY = H;\r\n  maxX = 0;\r\n  maxY = 0;\r\n  boolean found = 0;\r\n  for (int y = 0; y < H; y++) {\r\n    for (int x = 0; x < W; x++) {\r\n      c = tv.get_pixel(x, y);\r\n      if (c == 1) {\r\n        found = true;\r\n        if (x < minX) {\r\n          minX = x;\r\n        }\r\n        if (x > maxX) {\r\n          maxX = x;\r\n        }\r\n        if (y < minY) {\r\n          minY = y;\r\n        }\r\n        if (y > maxY) {\r\n          maxY = y;\r\n        }\r\n      }\r\n    }\r\n  }\r\n\r\n  \/\/ draw bounding box\r\n  tv.fill(0);\r\n  if (found) {\r\n    tv.draw_line(minX, minY, maxX, minY, 1);\r\n    tv.draw_line(minX, minY, minX, maxY, 1);\r\n    tv.draw_line(maxX, minY, maxX, maxY, 1);\r\n    tv.draw_line(minX, maxY, maxX, maxY, 1);\r\n    sprintf(s, \"%d, %d\", ((maxX + minX) \/ 2), ((maxY + minY) \/ 2));\r\n    tv.print(0, 0, s);\r\n  } else {\r\n    tv.print(0, 0, \"not found\");\r\n  }\r\n\r\n\r\n  tv.resume();\r\n  tv.delay_frame(5);\r\n}\r\n<\/pre>\n<p>What if you want to find the darkest area in an image instead of the brightest?  That&#8217;s easy &#8212; just invert the captured image before processing it.  Simply call <span class=\"code\">tv.fill(INVERT)<\/span>.<\/p>\n<h3>Edge Detection<\/h3>\n<p>The Arduino is powerful enough to do more sophisticated image processing.  The following sketch captures a frame then performs an edge detection algorithm on the image.  The result is the outline of the brightest (or darkest) parts of the image.  This could be useful in object recognition applications or<br \/>\nrobotics.  The algorithm is quite simple, especially with a monochrome image, and is described in <a target=\"_blank\" href=\"http:\/\/www.m-hikari.com\/ams\/ams-password-2008\/ams-password29-32-2008\/nadernejadAMS29-32-2008.pdf\">this survey of edge detection algorithms<\/a> as &#8220;Local Threshold and Boolean Function Based Edge Detection&#8221;.<\/p>\n<p>This project is the example &#8220;EdgeDetection&#8221; in the <a target=\"_blank\" href=\"https:\/\/github.com\/nootropicdesign\/arduino-tvout-ve\">TVout library for Video Experimenter<\/a>. <\/p>\n<p><iframe loading=\"lazy\" width=\"560\" height=\"349\" src=\"https:\/\/www.youtube.com\/embed\/TJnwLFqflBo?rel=0\" frameborder=\"0\" allowfullscreen><\/iframe><br \/>\n<br clear=\"all\"\/><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Difficulty Level = 5 [What&#8217;s this?] The Video Experimenter shield can give your Arduino the gift of sight. In the Video Frame Capture project, I showed how to capture images from a composite video source and display them on a TV. We can take this concept further by processing the contents of the captured image [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_et_pb_use_builder":"","_et_pb_old_content":"","_et_gb_content_width":"","footnotes":""},"categories":[3,26],"tags":[],"class_list":["post-558","post","type-post","status-publish","format-standard","hentry","category-arduino","category-video"],"_links":{"self":[{"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/posts\/558","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/comments?post=558"}],"version-history":[{"count":23,"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/posts\/558\/revisions"}],"predecessor-version":[{"id":1765,"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/posts\/558\/revisions\/1765"}],"wp:attachment":[{"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/media?parent=558"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/categories?post=558"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/tags?post=558"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}