本帖最后由 ypw 于 2015-12-21 23:58 编辑
首先你需要配置好WiFi,能上网,然后:
- apt-get update
- apt-get install libcv-dev libopencv-dev libv4l-dev
复制代码
有一点比较特别的是NanoPi2的摄像头插上以后,设备是/dev/video9而不是通常情况下的/dev/video0。
测试代码如下(参考自VideoCapture):
- #include
- #include
- #include
-
- using namespace cv;
-
- int main()
- {
- VideoCapture cap(9);
-
- Mat frame;
- while(1)
- {
- cap.read(frame);
- imshow("test",frame);
- waitKey(30);
- }
- return 0;
- }
复制代码
- g++ opencv.cpp -o testcv -lopencv_core -lopencv_highgui -lopencv_imgproc
- ./testcv
复制代码
这里出现了 HIGHGUI ERROR: V4L: index 9 is not correct! 这样的错误提示,具体原因不明,不过我们想到了一个好的解决方法,那就是直接使用v4l2获取摄像头的数据,然后再转为OpenCV的cv::Mat。 下面的代码就是OpenCV结合V4L2的程序:
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- #include
- #include
- #include
- using namespace cv;
-
- char videodevice[] = "/dev/video9";
- int imageWidth = 320;
- int imageHeight = 240;
-
- #define CLEAR(x) memset(&(x), 0, sizeof(x))
-
- struct buffer {
- void *start;
- size_t length;
- };
-
- static void xioctl(int fh, int request, void *arg)
- {
- int r;
- do {
- r = v4l2_ioctl(fh, request, arg);
- } while (r == -1 && ((errno == EINTR) || (errno == EAGAIN)));
-
- if (r == -1) {
- fprintf(stderr, "error %d, %sn", errno, strerror(errno));
- exit(EXIT_FAILURE);
- }
- }
-
- int main()
- {
- //打开摄像头设备
- int fd = -1;
- //fd = open (videodevice, O_RDWR | O_NONBLOCK, 0);
- fd = open (videodevice, O_RDWR, 0);
- if(fd<0){
- printf("failed to openn");
- exit(EXIT_FAILURE);
- }
- printf("打开摄像头设备成功,%sn", videodevice);
-
- //查询摄像头信息,VIDIOC_QUERYCAP
- printf("------------n");
- struct v4l2_capability cap;
- xioctl (fd, VIDIOC_QUERYCAP, &cap);
- printf("Driver Name:%snCard Name:%snBus info:%snDriver Version:%u.%u.%unn",cap.driver,cap.card,cap.bus_info,(cap.version>>16)&0XFF, (cap.version>>8)&0XFF,cap.version&0XFF);
-
-
- //查询摄像头视频格式,VIDIOC_ENUM_FMT
- printf("------------n");
- struct v4l2_fmtdesc fmtdesc;
- fmtdesc.index=0;
- fmtdesc.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
- printf("Supportformat:n");
- while(ioctl(fd,VIDIOC_ENUM_FMT,&fmtdesc)!=-1)
- {
- printf("t%d.%c%c%c%ct%sn",fmtdesc.index+1,fmtdesc.pixelformat & 0xFF, (fmtdesc.pixelformat >> 8) & 0xFF,(fmtdesc.pixelformat >> 16) & 0xFF, (fmtdesc.pixelformat >> 24) & 0xFF,fmtdesc.description);
- fmtdesc.index++;
- }
-
- struct v4l2_format fmt;
- struct v4l2_buffer buf;
- struct v4l2_requestbuffers req;
-
- CLEAR(fmt);
- CLEAR(buf);
- CLEAR(req);
-
- printf("------------n");
- printf("设置摄像头视频数据格式n");
- //设置摄像头视频数据格式,VIDIOC_S_FMT
- fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- fmt.fmt.pix.width = imageWidth;
- fmt.fmt.pix.height = imageHeight;
- fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
- fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
- //fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
- //fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YVU420;
- //fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG;
- xioctl(fd, VIDIOC_S_FMT, &fmt);
-
- if ((fmt.fmt.pix.width != imageWidth) || (fmt.fmt.pix.height != imageHeight))
- printf("Warning: driver is sending image at %dx%dn", fmt.fmt.pix.width, fmt.fmt.pix.height);
- else {
- printf("fmt.type is %dn",fmt.type);
- printf("Width = %dn",fmt.fmt.pix.width);
- printf("Height= %dn",fmt.fmt.pix.height);
- printf("Sizeimage = %dn",fmt.fmt.pix.sizeimage);
- }
-
- printf("------------n");
- printf("请求分配视频缓冲区n");
- //请求分配视频缓冲区,VIDIOC_REQBUFS
- req.count = 4;
- req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- req.memory = V4L2_MEMORY_MMAP;
- xioctl(fd, VIDIOC_REQBUFS, &req);
-
- printf("------------n");
- printf("查询缓冲信息,将内核空间映射到用户空间n");
- //查询缓冲信息,将内核空间映射到用户空间,VIDIOC_QUERYBUF
- struct buffer *buffers;
- unsigned int i, n_buffers;
-
- buffers = (struct buffer*)calloc(req.count, sizeof(*buffers));
- for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
- CLEAR(buf);
-
- buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- buf.memory = V4L2_MEMORY_MMAP;
- buf.index = n_buffers;
- //把VIDIOC_REQBUFS中分配的数据缓存转换成物理地址
- xioctl(fd, VIDIOC_QUERYBUF, &buf);
-
- buffers[n_buffers].length = buf.length;
- buffers[n_buffers].start = v4l2_mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset);
-
- if (MAP_FAILED == buffers[n_buffers].start) {
- perror("mmap");
- exit(EXIT_FAILURE);
- }
- }
-
- //投放一个空的视频缓冲区到视频缓冲区输入队列中,VIDIOC_QBUF
- printf("------------n");
- printf("投放一个空的视频缓冲区到视频缓冲区输入队列中n");
- for (i = 0; i < n_buffers; ++i) {
- CLEAR(buf);
- buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- buf.memory = V4L2_MEMORY_MMAP;
- buf.index = i;
- xioctl(fd, VIDIOC_QBUF, &buf);
- }
-
- //启动视频采集命令,VIDIOC_STREAMON
- printf("------------n");
- printf("启动视频采集n");
- enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- xioctl(fd, VIDIOC_STREAMON, &type);
-
-
-
- fd_set fds;
- int r;
- struct timeval tv;
-
- do {
- FD_ZERO(&fds);
- FD_SET(fd, &fds);
-
- /* Timeout. */
- tv.tv_sec = 2;
- tv.tv_usec = 0;
-
- r = select(fd + 1, &fds, NULL, NULL, &tv);
- } while ((r == -1 && (errno = EINTR)));
- if (r == -1) {
- perror("select");
- return errno;
- }
- Mat frame;
- while(1)
- {
- CLEAR(buf);
- buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- buf.memory = V4L2_MEMORY_MMAP;
- //从视频缓冲区的输出队列中取得一个已经保存有一帧视频数据的视频缓冲区,VIDIOC_DQBUF
- xioctl(fd, VIDIOC_DQBUF, &buf);
- char * p = (char *)(buffers[buf.index].start);
- printf("------------n");
- printf("取得一帧,%fkbn", buf.bytesused/1024.0);
-
- vector data(p, p + buf.bytesused);
- frame = imdecode(Mat(data), CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_COLOR);
- imshow("test", frame);
- int c = waitKey(10)&0xFF;
- if(c == 27){
- break;
- }
-
- xioctl(fd, VIDIOC_QBUF, &buf);
- }
-
-
- //停止视频采集命令,VIDIOC_STREAMOFF
- printf("------------n");
- printf("停止视频采集n");
- type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- xioctl(fd, VIDIOC_STREAMOFF, &type);
- for (i = 0; i < n_buffers; ++i) {
- v4l2_munmap(buffers[i].start, buffers[i].length);
- }
- v4l2_close(fd);
- exit (EXIT_SUCCESS);
- }
复制代码
- g++ test.cpp -o test -lopencv_core -lopencv_highgui -lopencv_imgproc -lv4l2
复制代码
注意,凡是带imshow的程序都必须到触摸屏上操作,不然就会出现错误,比如
ssh中的: (test:1500): Gtk-WARNING **: cannot open display: ,或者vnc中的: (test:1521): GdkGLExt-WARNING **: Window system doesn't support OpenGL.。注意2,本程序只支持MJPEG摄像头,不支持H264或者YUV格式的摄像头。
如果需要在Python中开发OpenCV,可以执行下面的命令:
- apt-get install libcv-dev libopencv-dev python-dev python-opencv python-imaging python-pip
- pip install -U numpy
复制代码
但是,目前在Python使用OpenCV是不现实的,因为numpy装不上。
|