{"id":547,"date":"2014-08-20T11:51:37","date_gmt":"2014-08-20T10:51:37","guid":{"rendered":"http:\/\/ofalcao.pt\/blog\/?p=547"},"modified":"2014-08-20T11:51:37","modified_gmt":"2014-08-20T10:51:37","slug":"ev3dev-webcam","status":"publish","type":"post","link":"https:\/\/ofalcao.pt\/blog\/2014\/ev3dev-webcam","title":{"rendered":"ev3dev &#8211; webcam"},"content":{"rendered":"<div class=\"seriesmeta\">This post is part 2 of 9 of \u00a0<a href=\"https:\/\/ofalcao.pt\/blog\/series\/ad4m4st0r-um-rover-lego\" class=\"series-122\" title=\"AD4M4ST0R - um rover LEGO\">AD4M4ST0R - um rover LEGO<\/a><\/div><p>A webcam USB utilizada no <a title=\"AD4M4ST0R \u2013 um rover LEGO\" href=\"http:\/\/ofalcao.pt\/blog\/2014\/ad4m4st0r-um-rover-lego\">AD4M4ST0R<\/a> \u00e9 uma Logitech C170.<\/p>\n<p>Depois de ligada s\u00e3o reconhecidos dois devices: uma webcam propriamente dita do tipo UVC (USB Video Class) gerida pelo v4l2 e um microfone gerido como uma placa de som pelo ALSA:<\/p>\n<pre>root@ev3dev:~# dmesg\n(...)\nusb 1-1.3: new full-speed USB device number 5 using ohci\nLinux video capture interface: v2.00\nuvcvideo: Found UVC 1.00 device Webcam C170 (046d:082b)\ninput: Webcam C170 as \/devices\/platform\/ohci.0\/usb1\/1-1\/1-1.3\/1-1.3:1.0\/input\/input3\nusbcore: registered new interface driver uvcvideo\nUSB Video Class driver (1.1.1)\nusbcore: registered new interface driver snd-usb-audio<\/pre>\n<p>O microfone n\u00e3o aparece como dispositivo USB, apenas a webcam:<\/p>\n<pre>root@ev3dev:~# lsusb\nBus 001 Device 005: ID 046d:082b Logitech, Inc.\n(...)<\/pre>\n<p>mas se formos ver ao alsamixer\u00a0 temos l\u00e1 uma nova placa de som: &#8220;Webcam C170&#8221;.<\/p>\n<p>A parte mais cr\u00edtica, a cria\u00e7\u00e3o de um dispositivo video, tamb\u00e9m funcionou:<\/p>\n<pre>root@ev3dev:~# ls \/dev<\/pre>\n<p>mostra entre outros &#8220;video0&#8221;.<\/p>\n<p>Como a webcam foi tamb\u00e9m reconhecida como um dispositivo OHCI temos ainda:<\/p>\n<pre>root@ev3dev:~# ls \/dev\/input\/by-id\/ -la\n(...)\nlrwxrwxrwx 1 root root\u00a0\u00a0 9 Aug 18 12:13 usb-_Webcam_C170-event-if00 -&gt; ..\/event3\n(...)<\/pre>\n<p>&nbsp;<\/p>\n<p>Para capturar imagens da webcam optei pelo fswebcam<\/p>\n<pre>apt-get install fswebcam<\/pre>\n<p>Como j\u00e1 o tinha experimentado com esta mesma webcam no meu Ubuntu, avan\u00e7o para um comando que sei que funciona:<\/p>\n<pre>fswebcam -d \/dev\/video0 -p YUYV -r 640x480 teste.jpg<\/pre>\n<p>E efectivamente funciona s\u00f3 que quando fui ver a imagem esta tinha apenas 176&#215;144 e n\u00e3o 640&#215;480 (e o pr\u00f3prio comando devolve isso: &#8220;Adjusting resolution from 640&#215;480 to 176&#215;144&#8221;). Mas que raio&#8230;?<\/p>\n<p>Perdi algum tempo nisto por isso vou alongar-me um pouco mais para que outros que passem pelo mesmo possam beneficiar tamb\u00e9m.<\/p>\n<p>Descobri que a c\u00e2mara permite despejar video em dois formatos diferentes: YUYV e MJPG:<\/p>\n<pre>root@ev3dev:~# v4l2-ctl --list-formats\nioctl: VIDIOC_ENUM_FMT\n\u00a0\u00a0 \u00a0Index\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : 0\n\u00a0\u00a0 \u00a0Type\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : Video Capture\n\u00a0\u00a0 \u00a0Pixel Format: 'YUYV'\n\u00a0\u00a0 \u00a0Name\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : YUV 4:2:2 (YUYV)\n\n\u00a0\u00a0 \u00a0Index\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : 1\n\u00a0\u00a0 \u00a0Type\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : Video Capture\n\u00a0\u00a0 \u00a0Pixel Format: 'MJPG' (compressed)\n\u00a0\u00a0 \u00a0Name\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : MJPEG<\/pre>\n<p>MJPG (Motion JPEG) \u00e9 um formato com compress\u00e3o (e alguma perda tamb\u00e9m) e por isso consome menos largura de banda que o YUYV. A minha teoria \u00e9 de que sendo o bus USB do EV3 apenas 1.1 (11 Mbps) em vez de USB 2.0 (480 Mbps) como no meu Ubuntu a webcam de algum modo se autoconfigura para a largura de banda dispon\u00edvel. Por isso no Ubuntu ao pedir com o fswebcam uma foto 640&#215;480 extra\u00edda de video gerado em formato YUV ele consiga mas no EV3 seja obrigado a reduzir para 176&#215;144.<\/p>\n<p>A solu\u00e7\u00e3o foi indicar ao fswebcam para lidar com MJPG:<\/p>\n<pre>fswebcam -d \/dev\/video0 -p MJPEG -r 640x480 teste.jpg<\/pre>\n<p>Agora j\u00e1 funciona, excepto que nalgumas situa\u00e7\u00f5es ocorre um erro semelhante a este (os dois n\u00fameros hexadecimais do final variam):<\/p>\n<pre>GD Error: gd-jpeg: JPEG library reports unrecoverable error: Not a JPEG file: starts with 0x92 0x7<\/pre>\n<p>Aparentemente algumas webcams (e pelos vistos a maioria s\u00e3o da Logitech?) demora a estabilizar a captura e por isso produz lixo nas primeiras frames. As solu\u00e7\u00f5es passam invariavelmente por descartar umas quantas frames inicais&#8230; s\u00f3 ainda n\u00e3o encontrem o n\u00famero m\u00e1gico:<\/p>\n<pre>fswebcam -d \/dev\/video0 -p MJPEG -r 640x480 -S 20 teste.jpg<\/pre>\n<p>Descartar 20 frames funciona sempre mas parece-me um exagero. Al\u00e9m disso descobri que \u00e0 medida que se vai utilizando podemos baixar o n\u00famero, at\u00e9 mesmo deixar de descartar qualquer frame&#8230; Parece que a c\u00e2mara &#8220;aquece&#8221; ou se vai auto-ajustando, ser\u00e1?<\/p>\n<p>Para facilitar a utiliza\u00e7\u00e3o a partir de outros programas criei um script &#8216;saycheese.sh&#8217; que ao ser invocado tira uma fotografia e guarda-a com um nome correspondendo \u00e0 data:<\/p>\n<pre>#!\/bin\/sh\n filename=$(date +\"%d-%m-%y_%Hh%Mm%Ss\")\n fswebcam -d \/dev\/video0 -p MJPEG -r 640x480 -q -D 1 -S 10 -s brightness=8 -s contrast=10\u00a0 $filename.jpg<\/pre>\n<p>Utilizo alguns outros par\u00e2metros:<\/p>\n<ul>\n<li>&#8220;-D 1&#8221; for\u00e7a um atraso de 1 segundo entre a activa\u00e7\u00e3o da c\u00e2mara e o \u00edncio da captura<\/li>\n<li>-s brightness=8 aumenta ligeiramente o brilho<\/li>\n<li>-s contrast=10 diminui ligeiramente o contraste<\/li>\n<\/ul>\n<p>Os valores de brightness e contrast, bem como outros aceites pela webcam, podem ser questionados \u00e0 pr\u00f3pria c\u00e2mara:<\/p>\n<pre>root@ev3dev:~# v4l2-ctl --all\nDriver Info (not using libv4l2):\n\u00a0\u00a0 \u00a0Driver name\u00a0\u00a0 : uvcvideo\n\u00a0\u00a0 \u00a0Card type\u00a0\u00a0\u00a0\u00a0 : Webcam C170\n\u00a0\u00a0 \u00a0Bus info\u00a0\u00a0\u00a0\u00a0\u00a0 : usb-ohci.0-1.3\n\u00a0\u00a0 \u00a0Driver version: 3.14.7\n\u00a0\u00a0 \u00a0Capabilities\u00a0 : 0x84000001\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0Video Capture\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0Streaming\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0Device Capabilities\n\u00a0\u00a0 \u00a0Device Caps\u00a0\u00a0 : 0x04000001\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0Video Capture\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0Streaming\nPriority: 2\nVideo input : 0 (Camera 1: ok)\nFormat Video Capture:\n\u00a0\u00a0 \u00a0Width\/Height\u00a0 : 640\/480\n\u00a0\u00a0 \u00a0Pixel Format\u00a0 : 'MJPG'\n\u00a0\u00a0 \u00a0Field\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : None\n\u00a0\u00a0 \u00a0Bytes per Line: 0\n\u00a0\u00a0 \u00a0Size Image\u00a0\u00a0\u00a0 : 921600\n\u00a0\u00a0 \u00a0Colorspace\u00a0\u00a0\u00a0 : SRGB\nCrop Capability Video Capture:\n\u00a0\u00a0 \u00a0Bounds\u00a0\u00a0\u00a0\u00a0\u00a0 : Left 0, Top 0, Width 640, Height 480\n\u00a0\u00a0 \u00a0Default\u00a0\u00a0\u00a0\u00a0 : Left 0, Top 0, Width 640, Height 480\n\u00a0\u00a0 \u00a0Pixel Aspect: 1\/1\nStreaming Parameters Video Capture:\n\u00a0\u00a0 \u00a0Capabilities\u00a0\u00a0\u00a0\u00a0 : timeperframe\n\u00a0\u00a0 \u00a0Frames per second: 30.000 (30\/1)\n\u00a0\u00a0 \u00a0Read buffers\u00a0\u00a0\u00a0\u00a0 : 0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 brightness (int)\u00a0\u00a0\u00a0 : min=-64 max=64 step=1 default=0 value=0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 contrast (int)\u00a0\u00a0\u00a0 : min=0 max=30 step=1 default=13 value=13\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 saturation (int)\u00a0\u00a0\u00a0 : min=0 max=127 step=1 default=38 value=38\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 hue (int)\u00a0\u00a0\u00a0 : min=-16000 max=16000 step=1 default=0 value=0\n\u00a0white_balance_temperature_auto (bool)\u00a0\u00a0 : default=1 value=1\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 gamma (int)\u00a0\u00a0\u00a0 : min=20 max=250 step=1 default=100 value=100\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 power_line_frequency (menu)\u00a0\u00a0 : min=0 max=2 default=1 value=1\n\u00a0\u00a0\u00a0\u00a0\u00a0 white_balance_temperature (int)\u00a0\u00a0\u00a0 : min=2800 max=6500 step=1 default=5000 value=5000 flags=inactive\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 sharpness (int)\u00a0\u00a0\u00a0 : min=0 max=100 step=1 default=35 value=35\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 backlight_compensation (int)\u00a0\u00a0\u00a0 : min=0 max=1 step=1 default=0 value=0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 exposure_auto (menu)\u00a0\u00a0 : min=0 max=3 default=3 value=3\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 exposure_absolute (int)\u00a0\u00a0\u00a0 : min=2 max=5000 step=1 default=312 value=10000 flags=inactive\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 exposure_auto_priority (bool)\u00a0\u00a0 : default=0 value=1\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 pan_absolute (int)\u00a0\u00a0\u00a0 : min=-72000 max=72000 step=3600 default=0 value=0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 tilt_absolute (int)\u00a0\u00a0\u00a0 : min=-54000 max=54000 step=3600 default=0 value=0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 zoom_absolute (int)\u00a0\u00a0\u00a0 : min=1 max=2 step=1 default=1 value=1<\/pre>\n<p>(embora nem todos os comandos aceites pela c\u00e2mara sejam percept\u00edveis, s\u00f3 experimentando v\u00e1rios valores para ver a diferen\u00e7a)<\/p>\n","protected":false},"excerpt":{"rendered":"<div class=\"seriesmeta\">This post is part 2  of 9 of \u00a0<a href=\"https:\/\/ofalcao.pt\/blog\/series\/ad4m4st0r-um-rover-lego\" class=\"series-122\" title=\"AD4M4ST0R - um rover LEGO\">AD4M4ST0R - um rover LEGO<\/a><\/div><p>A webcam USB utilizada no AD4M4ST0R \u00e9 uma Logitech C170. Depois de ligada s\u00e3o reconhecidos dois devices: uma webcam propriamente dita do tipo UVC (USB Video Class) gerida pelo v4l2 e um microfone gerido como uma placa de som pelo ALSA: root@ev3dev:~# dmesg (&#8230;) usb 1-1.3: new full-speed USB device number 5 using ohci Linux &hellip; <a href=\"https:\/\/ofalcao.pt\/blog\/2014\/ev3dev-webcam\" class=\"more-link\">Continuar a ler<span class=\"screen-reader-text\"> &#8220;ev3dev &#8211; webcam&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"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":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false},"version":2}},"categories":[13,18,19,20],"tags":[62,76,115,116,117],"series":[122],"class_list":["post-547","post","type-post","status-publish","format-standard","hentry","category-ev3dev","category-lego","category-lego-mindstorms","category-linux","tag-fswebcam","tag-logitech-c170","tag-uvcvideo","tag-v4l2","tag-webcam","series-ad4m4st0r-um-rover-lego"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p2Mhyv-8P","_links":{"self":[{"href":"https:\/\/ofalcao.pt\/blog\/wp-json\/wp\/v2\/posts\/547","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ofalcao.pt\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ofalcao.pt\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ofalcao.pt\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ofalcao.pt\/blog\/wp-json\/wp\/v2\/comments?post=547"}],"version-history":[{"count":0,"href":"https:\/\/ofalcao.pt\/blog\/wp-json\/wp\/v2\/posts\/547\/revisions"}],"wp:attachment":[{"href":"https:\/\/ofalcao.pt\/blog\/wp-json\/wp\/v2\/media?parent=547"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ofalcao.pt\/blog\/wp-json\/wp\/v2\/categories?post=547"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ofalcao.pt\/blog\/wp-json\/wp\/v2\/tags?post=547"},{"taxonomy":"series","embeddable":true,"href":"https:\/\/ofalcao.pt\/blog\/wp-json\/wp\/v2\/series?post=547"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}