Personal tools

OpenVPN and VisionSOM-6ULL

From SomLabs Wiki

Revision as of 10:18, 1 July 2018 by Pawelzbysinski (talk | contribs) (Created page with "{{PageHeader|OpenVPN and VisionSOM-6ULL)}} == Prerequisites == This tutorial based on Debian 9.2 image for VisionSOM-6ULL module. Please visit How to prepare SD Card with D...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

OpenVPN and VisionSOM-6ULL)


Prerequisites

This tutorial based on Debian 9.2 image for VisionSOM-6ULL module. Please visit How to prepare SD Card with Debian 9.2 for VisionSOM-6ULL on Linux or How to prepare SD Card with Debian 9.2 for VisionSOM-6ULL on Windows for more detailed instruction how to create a bootable microSD card.

To enable support for LCD-TFT display, please download and apply enable-tft-lcd.patch for somlabs-visionsom-6ull.dts device tree file:

wget http://wiki.somlabs.com/images/c/cd/Enable-tft-lcd.zip
unzip Enable-tft-lcd.zip
patch /home/developer/source/somlabs-dts-1.0/somlabs-visionsom-6ull.dts ./enable-tft-lcd.patch

For more info how to customize, build and upload Device Tree file, please visit How to customize Debian 9.2 device tree.

Enabling support for USB Video Class

Most of USB webcams are working on Linux with standard UVC driver. UVC driver is a USB device class that describes devices capable of streaming video like webcams, digital camcorders and television tuners. The source of this driver is already included in the Linux kernel for SoMLabs module, but driver is not selected by default. To enable support for UVC driver, configure kernel with menuconfig tool:


cd linux-sources make ARCH=arm menuconfig

and choose the right driver:


Device Drivers ---> <*> Multimedia Support --->

   [*] Cameras/video grabbers support
   [*] Media USB Adapters  --->
       <*> USB Video Class (UVC)


File:Image1.png

After all these options have been selected, save your configuration, exit the menuconfig tool and build a new kernel image:


make ARCH=arm zImage


In last steps, transfer the new kernel images to a microSD:


sudo mount /dev/sdbX /mnt/sdcard cd /mnt/sdcard sudo cp <linuxsources>/arch/arm/boot/zImage boot/


connect Webcam to USB port and boot SoMLabs module form SD card.





Example 1: OpenCV – first program


OpenCV [1] is a computer vision library released under a BSD license and hence it is free for both academic and commercial use. It has C++, C, Python and Java interfaces and supports Windows, Linux, Mac OS, iOS and Android. OpenCV was designed for computational efficiency and with a strong focus on real-time applications.


To install OpenCV library:


apt-get install libopencv-dev


Let's take a look at an example (opencv-ex1.c) to capture an image from a webcam:


#include <cv.h> #include <highgui.h>

void main (int argc,char *argv[]) {

 IplImage *color_img;
 int c;
 /* open /dev/video0 device */
 CvCapture *cv_cap = cvCaptureFromCAM(0); //(A)
 /* create window */
 cvNamedWindow ("Video", 0);
 /* main loop */
 for(;;)
   {
     /* get and show frame */
     color_img = cvQueryFrame (cv_cap);
     if (color_img != 0)
       cvShowImage ("Video", color_img);
     c = cvWaitKey (10);
     if (c == 27)
       break;
   }
 /* clean up */
 cvReleaseCapture (&cv_cap);
 cvDestroyWindow ("Video");

}


In line (A), we are passing a device index, which is 0. If our device has two or more cameras, then we can pass the appropriate device index based on what camera to choose. You can find out the number of cameras and associated device indexes using the following command:


ls -l /dev/video*


To compile and run app:


gcc -o opencv-ex1 opencv-ex1.c `pkg-config --cflags --libs opencv`

./opencv-ex1.c



Example 2: Tracking colored objects in OpenCV


Example 2 shows how to detect the presence of a colored object using OpenCV API and computer vision techniques.


The end product of Example 2 should look similar to the photo above (in comparison to Example 1, image from camera and image after transformation will be written directly to framebuffer – there is no need to install X Window Server):


File:Image2.png

Source code of opencv-ex2.c:


#include <iostream> #include <fstream> #include <stdint.h> #include <sys/ioctl.h> #include <linux/fb.h> #include <fcntl.h>

#include "cv.h" #include "highgui.h"

#define IMG_1_X_OFFSET 60 #define IMG_1_Y_OFFSET 140

#define IMG_2_X_OFFSET 420 #define IMG_2_Y_OFFSET 140

#define PRINT_COORD_TO_STDOUT 0 #define LINE_WIDTH 4 #define MAX_LINE_NUMS 200

#define HSV_COLOR_MIN cvScalar (0, 100, 100) /* cvScalar (H,S,V); */ #define HSV_COLOR_MAX cvScalar (2, 255, 255) /* cvScalar (H,S,V); */

using namespace cv; using namespace std;

static ofstream ofs;

static IplImage* convert_image (IplImage* img) {

 IplImage *imgHSV = cvCreateImage (cvGetSize(img), 8, 3);
 IplImage *imgTHR = cvCreateImage (cvGetSize(img), 8, 1);
 cvCvtColor (img, imgHSV, CV_BGR2HSV);
 cvInRangeS (imgHSV, HSV_COLOR_MIN, HSV_COLOR_MAX, imgTHR);
 cvReleaseImage (&imgHSV);
 return imgTHR;

}

static void fb_show_image (IplImage *img, int x_off, int y_off) {

 Mat frame = cvarrToMat (img);
 if (frame.channels() == 1)
 {
   Mat in[] = {frame, frame, frame};
   merge (in, 3, frame);
 }
 if (frame.depth() != CV_8U)
   {
     cout << "[error ] img: not 8 bits per pixel and channel" << endl;
     return;
   }
 else if (frame.channels() != 3)
   {
     cout << "[error ] img: not 3 channels" << endl;
     return;
   }
 else
   {
     Size2f frame_size = frame.size();
     Mat frame_compat;
     cvtColor(frame, frame_compat, cv::COLOR_BGR2BGR565);
     for (int y = y_off; y < frame_size.height + y_off; y++)
       {
         ofs.seekp ((y * 800 * 2) + x_off * 2);
         ofs.write (reinterpret_cast<char*>(frame_compat.ptr(y-y_off)), frame_size.width*2);
       }
   }

}

int main (int, char**) {

 CvCapture    *cam = NULL;
 IplImage     *frame = NULL;
 unsigned int  num_of_lines = 0;
 /* threshold */
 IplImage *frame_thr = NULL;
 /* trajectory */
 IplImage *frame_trj = NULL;
 /* moments */
 CvMoments *moments = (CvMoments*)malloc(sizeof(CvMoments));
 double moment_10;
 double moment_01;
 double central;
 /* coordinates */
 int posX = 0, posY = 0;
 int lastX, lastY;
 /* [1] open /dev/video1 - 320x240 */
 cam = cvCaptureFromCAM(1);
 cvSetCaptureProperty (cam, CV_CAP_PROP_FRAME_WIDTH, 320);
 cvSetCaptureProperty (cam, CV_CAP_PROP_FRAME_HEIGHT, 240);
 if (!cam)
   {
     cout << "[error ] cannot open the video cam" << endl;
     return -1;
   }
 /* [2] open framebuffer */
 ofs.open ("/dev/fb0");
 /* [3] enter to mainloop */
 while(1)
   {
     /* grab frame */
     frame = cvQueryFrame (cam);
     /* thresholding */
     frame_thr = convert_image (frame);
     /* moments */
     cvMoments (frame_thr, moments, 1);
     moment_10 = cvGetSpatialMoment (moments, 1, 0);
     moment_01 = cvGetSpatialMoment (moments, 0, 1);
     central = cvGetCentralMoment (moments, 0, 0);
     /* coordinates */
     lastX = posX;
     lastY = posY;
     posX = moment_10/central;
     posY = moment_01/central;

#if PRINT_SYMBOL_TO_STDOUT

     cout << " X: " << posX << " Y: " << posY << endl;

#endif

     /* trajectory */
     if (!frame_trj)
       frame_trj = cvCreateImage (cvGetSize(frame), 8, 3);
     if (lastX>0 && lastY>0 && posX>0 && posY>0)
       {
         cvLine (frame_trj, cvPoint(posX, posY), cvPoint(lastX, lastY), cvScalar(255,255,0), LINE_WIDTH);
     num_of_lines++;
     if (num_of_lines == MAX_LINE_NUMS)
           {
             cvZero (frame_trj);
             num_of_lines=0;
           }
       }
     /* combine trajectory with captured frame */
     cvAdd (frame, frame_trj, frame);
     /* show images */
     fb_show_image (frame, IMG_1_X_OFFSET, IMG_1_Y_OFFSET);
     fb_show_image (frame_thr, IMG_2_X_OFFSET, IMG_2_Y_OFFSET);
     cvReleaseImage (&frame_thr);
   }

error:

 cvReleaseImage (&frame);
 cvReleaseImage (&frame_thr);
 cvReleaseImage (&frame_trj);
 delete moments;
 cvReleaseCapture (&cam);
 cout << "[status] exiting..." << endl;
 return 0;

}


To compile and run app:


gcc -o opencv-ex2 opencv-ex2.c `pkg-config --cflags --libs opencv` ./opencv-ex2


If you want to try some different color, you'll have to figure out it's HSV [2] (Hue, Saturation and Value) and edit HSV_COLOR_MIN and HSV_COLOR_MAX thresholds. Please remember that different applications use different scales for HSV. For example GIMP uses H=0-360, S=0-100 and V=0-100. But OpenCV uses H=0-180, S=0-255, V=0-255.



Example 3: QR code scanner using OpenCV and ZBar


OpenCV can be easily combined with other libraries, like for example ZBar [3]. ZBar is an open source software suite for reading bar codes from various sources, such as video streams, image files and raw intensity sensors. It supports many popular types of bar codes including EAN-13/UPC-A, UPC-E, EAN-8, Code 128, Code 39, Interleaved 2 of 5 and QR Code.


To install ZBar library:


apt-get install libzbar-dev


Sample usage of OpenCV and ZBar libraries (like in previous example, results will be written directly to framebuffer):


#include <iostream> #include <fstream> #include <stdint.h> #include <sys/ioctl.h> #include <linux/fb.h> #include <fcntl.h> #include <zbar.h>

#include <opencv2/imgproc/imgproc.hpp> #include <opencv2/highgui/highgui.hpp>

#define CAM_X_OFFSET 60 #define CAM_Y_OFFSET 140

#define PRINT_SYMBOL_TO_STDOUT 0 #define SHOW_SYMBOL_FRAME 1

using namespace cv; using namespace std; using namespace zbar;

static ofstream ofs;

int main (int, char**) {

 ImageScanner scanner;
 Mat frame;
 /* [1] open /dev/video1 - 320x240 */
 VideoCapture cap(1);
 cap.set (CV_CAP_PROP_FRAME_WIDTH, 320);
 cap.set (CV_CAP_PROP_FRAME_HEIGHT, 240);
 if (!cap.isOpened())
   {
     cout << "[error ] cannot open the video cam" << endl;
     return -1;
   }
 /* [2] init zbar */
 scanner.set_config (ZBAR_NONE, ZBAR_CFG_ENABLE, 1);
 /* [3] open framebuffer */
 ofs.open ("/dev/fb0");
 /* [4] enter to mainloop */
 while (true)
   {
     Mat grey;
     /* grab frame */
     cap >> frame;
     /* BGR->GREY conversion */
     cvtColor (frame, grey, CV_BGR2GRAY);
     Image image (frame.cols, frame.rows, "Y800", (uchar*) grey.data, frame.cols * frame.rows);
     /* scan the image for barcodes */
     scanner.scan (image);
     /* get and process result - only one code */
     Image::SymbolIterator symbol = image.symbol_begin();
     if (symbol != image.symbol_end())
       {
         string code_type = symbol->get_type_name();
         string code_data = symbol->get_data();

#if PRINT_SYMBOL_TO_STDOUT

         cout << "[" << code_type << "] " << code_data << " " << endl;

#endif

#if SHOW_SYMBOL_FRAME

         {
           RotatedRect rect;
           Point2f points[4];
           vector<Point> vector;
           int n = symbol->get_location_size();
           for (int i=0; i<n; i++)
             vector.push_back (Point (symbol->get_location_x(i), symbol->get_location_y(i)));
           rect = minAreaRect (vector);
           rect.points (points);
           for (int i=0; i<4; i++)
             line(frame, points[i], points[(i+1)%4], Scalar(255,0,0),3);
         }

#endif

       }
     /* write data to framebuffer */
     if (frame.depth() != CV_8U)
       {
         cout << "[error ] cam: not 8 bits per pixel and channel" << endl;
         goto error;
       }
     else if (frame.channels() != 3)
       {
         cout << "[error ] cam: not 3 channels" << endl;
         goto error;
       }
     else
       {
         Size2f frame_size = frame.size();
         Mat frame_compat;
         cvtColor (frame, frame_compat, COLOR_BGR2BGR565);
         for (int y = CAM_Y_OFFSET; y < frame_size.height + CAM_Y_OFFSET; y++)
           {
             ofs.seekp ((y * 800 * 2) + CAM_X_OFFSET * 2);
             ofs.write (reinterpret_cast<char*>(frame_compat.ptr(y-CAM_Y_OFFSET)), frame_size.width*2);
           }
       }
   } /* while */

error:

 cout << "[status] exiting..." << endl;

}


To compile and run app:


gcc -o opencv-ex3 opencv-ex3.c `pkg-config --cflags --libs opencv zbar`

./opencv-ex3

File:Image3.png

[1] https://opencv.org/

[2] https://en.wikipedia.org/wiki/HSL_and_HSV

[3] http://zbar.sourceforge.net/