用树莓派4B+做机器人开发,怎么着也要搞点机器人视觉,那么怎么着也要装个opencv, 装了opencv,怎么着也要写个C++或者是python3的程序,来玩玩看。
1. opencv的安装
用树莓派4B+Ubuntu24.04系统装opencv很简单,我默认大家都会,但是,为了记个笔记,我还是把命令写在这里。
sudo apt install libopencv-dev
pip install opencv-python
装完了之后,可以看看装成功了没有。
可以看到,我不管是C++库还是python库,都是装的Ver.4.6.0
2. 写个程序玩一玩
好了, 上面已经装好opencv了,现在写个程序玩一玩。
不好意思,我不会写opencv的程序,所以,到网上去抄了一个程序。就是下面这样的。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <linux/videodev2.h>
#include <opencv2/opencv.hpp>
using namespace cv;
struct buffer
{
void *start;
size_t length;
};
int main()
{
int fd;
struct v4l2_capability cap;
struct v4l2_format fmt;
struct v4l2_buffer buf;
struct v4l2_requestbuffers req;
enum v4l2_buf_type type;
struct buffer *buffers;
unsigned int i, n_buffers;
// Open the device
fd = open("/dev/video0", O_RDWR);
if(fd==-1)
{
perror("Openning video device");
return 1;
}
// Query the device capabilities
if(ioctl(fd, VIDIOC_QUERYCAP, &cap) == -1)
{
perror("Querying Capabilities");
return 1;
}
// Set the image format
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width=1280;
fmt.fmt.pix.height=720;
fmt.fmt.pix.pixelformat=V4L2_PIX_FMT_MJPEG;
fmt.fmt.pix.field=V4L2_FIELD_NONE;
if(ioctl(fd, VIDIOC_S_FMT, &fmt) == -1)
{
perror("Setting Pixel Format");
return 1;
}
// Request buffers
memset(&req, 0, sizeof(req));
req.count=4; // request 4 buffers
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
if(ioctl(fd, VIDIOC_REQBUFS, &req) == -1)
{
perror("Requesting Buffer");
return 1;
}
buffers = (struct buffer*)calloc(req.count, sizeof(*buffers));
if(!buffers)
{
perror("Out of memory");
return 1;
}
// Map the buffers
for(n_buffers = 0; n_buffers < req.count; ++n_buffers)
{
memset(&buf, 0, sizeof(buf));
buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = n_buffers;
if(ioctl(fd, VIDIOC_QUERYBUF, &buf) == -1)
{
perror("Querying Buffer");
return 1;
}
buffers[n_buffers].length = buf.length;
buffers[n_buffers].start = mmap(NULL, buf.length, PROT_READ|PROT_WRITE, MAP_SHARED, fd, buf.m.offset);
if(MAP_FAILED == buffers[n_buffers].start)
{
perror("mmap");
return 1;
}
}
// Queue the buffers
for(i=0;i<n_buffers;++i)
{
memset(&buf, 0, sizeof(buf));
buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
if(ioctl(fd, VIDIOC_QBUF, &buf) == -1)
{
perror("Queue Buffer");
return 1;
}
}
// Start streaming
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if(ioctl(fd, VIDIOC_STREAMON, &type) == -1)
{
perror("Start Capture");
return 1;
}
// Capture and display frames
while(1)
{
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
//Dequeue a buffer
if(ioctl(fd, VIDIOC_DQBUF, &buf) == -1)
{
perror("Retrieving Frame");
return 1;
}
// Decode the MJPEG dato to a Mat
Mat frame = imdecode(Mat(1, buf.bytesused, CV_8UC1, buffers[buf.index].start), IMREAD_COLOR);
if(!frame.empty())
{
imshow("Frame", frame);
}
if(waitKey(1) == 27) // Press 'ESC' to exit
{
break;
}
// Queue the buffer again
if(ioctl(fd, VIDIOC_QBUF, &buf)==-1)
{
perror("Queue Buffer");
return 1;
}
}
// Stop streaming
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if(ioctl(fd, VIDIOC_STREAMOFF, &type)==-1)
{
perror("Stop Capture");
return 1;
}
//Unmap the buffer
for(i=0;i<n_buffers; ++i)
{
munmap(buffers[i].start, buffers[i].length);
}
// Free the buffer
free(buffers);
// Close the device
close(fd);
return 0;
}
这是一篇抄来的程序,但是我觉得这篇程序简洁干脆明了的将怎么样用opencv进行编程展示给了大家,所以,我就抄来放这里,做个记录,有利于中国计算机视觉编程的发展。
3. 编译
好了,程序写好了,开始编译。
这是我编译的结果
找不到cv::Mat, 找不到std::char等等,总之一堆问题。
这是个C++程序,用gcc编译不对,应该用g++编译。试一下。
这下问题少了很多。
网上找了一下,发现要用下列命令来编译
g++ test_cv.cpp `pkg-config --libs opencv4`
这时的问题是:
找不到 "opencv2/opencv_modules.hpp"
然后,找了半天后,发现,opencv2被装到了 /usr/include/opencv4/下面,我也不知道咋搞,就把opencv2从opencv4下面拷贝到/usr/include下面吧。
再编译
没有任何提示,成功了。
4.结果检验
执行编译生成的a.out,可以看到下列画面。
这是我用树莓派自带相机拍到的动画。(树莓派自带相机怎么装,可以看我前面的文章)
这画面还可以吧。
好了,大功告成,亲个嘴儿 。