
Чего уже только не сделали на малыше TP-LINK TL-MR3020!
Ведь, это действительно доступный крохотный одноплатник на базе Linux с Wi-Fi, Ethernet, USB и UART-ом на борту (и несколькими GPIO).
Простой робот телеприсутствия, система для умного дома и многое-многое другое.
Как помним, в прошивке OR-WRT — уже идёт утилита mjpg_streamer, которая может захватывать кадр с веб-камеры,
сжимать его в JPEG (если камера отдаёт кадры в формате YUYV) и отдавать кадр в сокет.
При подключения веб-камеры, поддерживающей UVC, в каталоге /dev появится видео-устройство /dev/video0,
данные с которого можно считывать.
Ручной запуск mjpg_streamer выглядит так:
# mjpg_streamer -i «input_uvc.so -d /dev/video0 -r 320×240 -f 10» -o «output_http.so -p 8080»
, если же камера выдаёт данные в формате YUYV, то необходимо просто указать параметр -y и всё заработает.
# mjpg_streamer -i «input_uvc.so -d /dev/video0 -y -r 320×240 -f 10» -o «output_http.so -p 8080»
— при таком режиме работы, нагрузка на процессор роутера будет составлять более 90%
Получается, что использовать камеры, выдающие данные в формате YUYV — не очень выгодно, но зато это может быть удобно если мы хотим организовать систему компьютерного зрения прямо на роутере!
Действительно, раз mjpg_streamer может считывать картинку с камеры через свой плагин input_uvc.so,
то почему бы не реализовать свой видеозахват самостоятельно?
Сказано — сделано!
Так на свет появилась tinycv — крохотная библиотечка компьютерного зрения на C под ОС Linux.
Библиотечка состоит всего из нескольких C-ных файлов и позволяет считывать bmp-картинки, работать с камерой и
осуществлять некоторые базовые операции над изображением.
Скачать библиотечку можно с google code — tinycv
Для работы с картинкой используется следующая структура:
typedef struct image {
int width;
int height;
int type;
int n_channels;
int size;
int step;
char* data;
} image;
возможные типы данных картинок:
enum {CV_DEPTH_8S=0, CV_DEPTH_8U, CV_DEPTH_16S, CV_DEPTH_16U, CV_DEPTH_32F};
Простой пример, загружающий картинку из bmp-файла и выполняющий конвертацию цветной картинки в градации серого.
#include <stdio.h>
#include <stdlib.h>
#include "tinycv.h"
int main(int argc, char* argv[])
{
printf("[i] Start...\n");
char file_name[] = "test.bmp";
char* filename=file_name;
if(argc >= 2) {
filename = argv[1];
}
printf("[i] file: %s\n", filename);
// test image loading
image* img2 = image_load(filename);
if(!img2) {
printf("[!] Error: image_load()\n");
return -1;
}
printf("[i] image size: %dx%dx%d (%d)\n", img2->width, img2->height, img2->n_channels, img2->size);
image_save(img2, "test2_load_save.bmp");
// test convert image to grayscale
printf("[i] image_convert_color \n");
image* img_gray = image_create(img2->width, img2->height, 1, CV_DEPTH_8U);
image_convert_color(img2, img_gray, CV_RGB2GRAY);
image_save(img_gray, "test3_gray.bmp");
image_delete(&img2);
image_delete(&img_gray);
printf("[i] End.\n");
return 0;
}
Пример работы с камерой — захват 10 кадров с камеры и конвертация их в градации серого с
сохранением результатов в файл frame_gray.bmp
#include <stdio.h>
#include <stdlib.h>
#include "tinycv.h"
#define VIDEO_WIDTH 160 //320
#define VIDEO_HEIGHT 120 //240
int main(int argc, char* argv[])
{
printf("[i] Start...\n");
image* img = image_create(VIDEO_WIDTH, VIDEO_HEIGHT, 3, CV_DEPTH_8U);
image* img_gray = image_create(VIDEO_WIDTH, VIDEO_HEIGHT, 1, CV_DEPTH_8U);
if(!img) {
printf("[!] Error: image_create()\n");
}
int res = 0;
videocapture_dev dev;
memset(&dev, 0, sizeof(dev));
dev.width = VIDEO_WIDTH;
dev.height = VIDEO_HEIGHT;
dev.fps = 10;
videocapture_init("/dev/video0", &dev);
res = videocapture_open(&dev);
if(res != 0)
return -1;
int counter=0;
while(1) {
image* frame = videocapture_update(&dev);
image_copy(frame, img);
image_save(img, "frame.bmp");
image_convert_color(img, img_gray, CV_RGB2GRAY);
image_save(img_gray, "frame_gray.bmp");
if(counter++>10) {
break;
}
}
videocapture_close(&dev);
image_delete(&img);
image_delete(&img_gray);
printf("[i] End.\n");
return 0;
}
Работа с BMP-файлами проверялась только на картинках 320х240 и 160×120 — на других возможны проблемы.
Работа всех доступных методов библиотечки tinycv, приводятся в двух тестовых файлах:
test/test.c — методы обработки изображения
test/video.c — видеозахват
В состав библиотечки, так же, добавлены методы для определения доминирующих цветов на изображении
(см. dominatecolors.c) — которые являются простым переносом OpenCV-ой версии.
Сборка tinycv для TP-LINK TL-MR3020
Для сборки под TP-LINK TL-MR3020
нужно выполнить
export PATH=»$HOME/dev/toolchains/tplink/toolchain-mips_r2_gcc-4.3.3+cs_uClibc-0.9.30.1/usr/bin:$PATH»
и сделать
make CC=mips-openwrt-linux-gcc AR=mips-openwrt-linux-ar
собралось!
проверяем:
scp test root@192.168.217.1:/tmp
scp cat.bmp root@192.168.217.1:/tmp
scp video root@192.168.217.1:/tmp
# ./test cat.bmp [i] Start... [i] file: cat.bmp [i] image size: 320x240x3 (230400) [i] BmpHeader: 14 BmpImageInfo: 40 [i] BMP header: [i] signature: BM [i] fileSize: 914621184 [i] reserved: 0 offset: 905969664 [i] BMP Info: [i] headerSize: 671088640 [i] size: 1073807360x-268435456 [i] planeCount: 256 [i] bitDepth: 6144 [i] compression: 0 [i] compressedImageSize: 8651520 [i] horizontalResolution: 319488000 [i] verticalResolution: 319488000 [i] numColors: 0 [i] importantColors: 0 [i] End.
root@OpenWrt:/tmp# ls -asl
0 drwxrwxrwt 10 root root 400 Jan 1 00:02 .
0 drwxr-xr-x 1 root root 0 Jan 1 00:00 ..
0 drwx------ 2 root root 40 Jan 1 00:00 .uci
4 -rw-r--r-- 1 root root 4 Jan 1 00:00 TZ
228 -rw-r--r-- 1 root root 230454 Jan 1 00:01 cat.bmp
0 -rw-r--r-- 1 root root 0 Jan 1 00:00 dhcp.leases
0 drwxr-xr-x 2 root root 80 Jan 1 00:00 etc
4 -rw-r--r-- 1 root root 85 Jan 1 00:00 fstab
0 drwxr-xr-x 2 root root 60 Jan 1 00:00 lock
0 drwxr-xr-x 2 root root 80 Jan 1 00:00 log
0 drwxr-xr-x 2 root root 40 Jan 1 00:00 overlay
4 -rw-r--r-- 1 root root 32 Jan 1 00:00 resolv.conf
0 -rw-r--r-- 1 root root 0 Jan 1 00:00 resolv.conf.auto
0 drwxr-xr-x 2 root root 220 Jan 1 00:00 run
0 drwxr-xr-x 2 root root 60 Jan 1 00:00 state
0 drwxr-xr-x 2 root root 80 Jan 1 00:00 sysinfo
32 -rwxr-xr-x 1 root root 30066 Jan 1 00:01 test
4 -rw-r--r-- 1 root root 54 Jan 1 00:03 test2.bmp
228 -rw-r--r-- 1 root root 230454 Jan 1 00:03 test3.bmp
64 -rwxr-xr-x 1 root root 62354 Jan 1 00:02 video
посмотрим:
scp root@192.168.217.1:/tmp/test2.bmp ./
scp root@192.168.217.1:/tmp/test3.bmp ./
тээкс — файлы не алё, да и по данным загрузки BMP видно, что что-то не так.
посмотрим размер файла (230454), а нам показано:
[i] fileSize: 914621184
914621184 = 0x36840300
нужный размер получается при перевороте:
0x00038436 = 230454
напишем пару макросов:
#ifdef MIPS #define to_mips2(x) ( ((x) >> 8) | (((x) & 0xFF) << 8) ) #define to_mips4(x) ( ((x) >> 24) | ((((x)>>16) & 0xFF) << 8) | ((((x)>>8) & 0xFF) << 16) | (((x) & 0xFF)<<24) ) #endif
и прогоним через них все параметры BMP-файла
# ./test cat.bmp
[i] Start...
[i] file: cat.bmp
[i] image size: 320x240x3 (230400)
[i] BmpHeader: 14 BmpImageInfo: 40
[i] BMP header:
[i] signature: BM
[i] fileSize: 230454
[i] reserved: 0 offset: 54
[i] BMP Info:
[i] headerSize: 40
[i] size: 320x240
[i] planeCount: 1
[i] bitDepth: 24
[i] compression: 0
[i] compressedImageSize: 230400
[i] horizontalResolution: 2835
[i] verticalResolution: 2835
[i] numColors: 0
[i] importantColors: 0
[i] End.
root@OpenWrt:/tmp#
# ls -asl | grep test
32 -rwxr-xr-x 1 root root 32658 Jan 1 01:02 test
228 -rw-r--r-- 1 root root 230454 Jan 1 01:02 test2.bmp
228 -rw-r--r-- 1 root root 230454 Jan 1 01:02 test3.bmp
скачиваем:
scp root@192.168.217.1:/tmp/test2.bmp ./
scp root@192.168.217.1:/tmp/test3.bmp ./
заработало!
подключим камеру
# ls -asl /dev
0 drwxr-xr-x 5 root root 1080 Jan 1 00:06 .
0 drwxr-xr-x 1 root root 0 Jan 1 00:00 ..
...
0 crw-r--r-- 1 root root 81, 0 Jan 1 00:06 video0
...
# ./video
[i] Start...
[i] file: test.bmp
[!] Error: VIDIOC_S_FMT errno: 16, Device or resource busy
прибьём mjpg_streamer
# ps | grep mjpg 1341 root 6428 S /usr/bin/mjpg_streamer --input input_uvc.so --device 1402 root 1492 S grep mjpg
# killall mjpg_streamer
# ./video [i] Start... [i] file: test.bmp capture: size: 320 x 240 format: VYUY framesize: 153600 [i] End.
забираем файлы
scp root@192.168.217.1:/tmp/frame.bmp ./
scp root@192.168.217.1:/tmp/frame_gray.bmp ./
ураааааааааааа! получилось 🙂 правда, картинка перевёрнута, ну так это ерунда 🙂
Добавим в Makefile соответствующую цель и теперь, чтобы собрать библиотечку для роутера TP-LINK TL-MR3020
остаётся просто выполнить
make mips
Быстродействие tinycv
на TL-MR3020:
[i] == Performance == [t] image_convert_color: 0.320251 s [t] image_thin_borders: 2.708240 s [t] image_min_max_loc: 0.099041 s [t] image_threshold: 0.075435 s [t] image_resize: 0.372802 s [t] image_kmeans_colorer: 22.603177 s [t] image_rgb2hsv: 2.389729 s [t] image_hsv_colorer: 3.882528 s ./video [i] Start... capture: size: 320 x 240 format: VYUY framesize: 153600 [t] videocapture_update: 0.990277 s
на Raspberry Pi:
[i] == Performance == [t] image_convert_color: 0.018003 s [t] image_thin_borders: 0.154594 s [t] image_min_max_loc: 0.011518 s [t] image_threshold: 0.010576 s [t] image_resize: 0.070244 s [t] image_kmeans_colorer: 9.684125 s [t] image_rgb2hsv: 0.075674 s [t] image_hsv_colorer: 0.219964 s # ./video [i] Start... capture: size: 320 x 240 format: YUYV framesize: 153600 [t] videocapture_update: 0.077876 s [t] image_hsv_colorer: 0.295682 s
Поэтому, видеозахват на роутере TL-MR3020 лучше вести с разрешением поменьше- например, 160x120 😉
Работа библиотеки tinycv проверялась на x86 (Debian 6 и Ubuntu), на TP-LINK TL-MR3020 (OR-WRT) и на Raspberry Pi (raspbian wheezy).
Вот, собственно и всё! Используя эту библиотечку, которую можно легко дополнить требуемым функционалом,
очень просто наделить своего робота или автомат настоящим зрением!
Ссылки
http://code.google.com/p/robocraft/
По теме
Использование Lua в робототехнике
Исследование Wi-Fi-роутера TP-LINK TL-MR3020
Кросс-компиляция Lua для TP-LINK TL-MR3020
Lua - модуль для работы с последовательным портом
