用39块钱的V851se视觉开发板做了个小相机。
可以进行物品识别、自动追焦!
这个超低成本的小相机是在V851se上移植使用全志在线开源版本的Tina Linux与OpenCV框架开启摄像头拍照捕获视频,并结合NPU实现Mobilenet v2目标分类识别以及运动追踪等功能......并最终实现功能完整的智能小相机。
ISP适配
可以适配V851se的Tina5.0升级到了21.05版本的OpenWrt,相较于商业量产版本的Tina Linux 支持更多新的软件包,不过可惜的是MPP包没有移植到Tina5.0,所以想使用摄像头就需要另辟蹊径。
虽然Tina5.0并没有移植MPP包,但也内置了一个libAWispApi包,支持在用户层对接 ISP,但是很可惜这个包也没有适配V85x系列,这里就需要自行适配。
其实适配很简单,SDK 已经提供了lib只是没提供编译支持,我们需要前往以下文件夹中新建一个v851se文件夹:
openwrt/package/allwinner/vision/libAWIspApi/machinfo
然后再新建文件build.mk写入如下配置:
ISP_DIR:=isp600
然后在menuconfig中勾选上这个包,并进行如下配置:
Allwinner ---> Vision ---> <*> camerademo........................................ camerademo test sensor --->
- Enabel vin isp support
编译系统然后烧录系统,运行命令 camerademo ,可以看到是正常拍摄照片的OpenCV在打包好的固件中已经默认适配好了,如果不想了解如何适配OpenCV可以直接前往点击链接获取资料并跳过这部分OpenCV默认不支持开启RAW Sensor,不过现在需要配置为OpenCV开启RAW Sensor抓图,然后通过OpenCV送图到之前适配的libAWispApi库进行 ISP 处理。在这里增加一个函数作为 RAW Sensor 抓图的处理。#ifdef __USE_VIN_ISP__bool CvCaptureCAM_V4L::RAWSensor(){ struct v4l2_control ctrl; struct v4l2_queryctrl qc_ctrl; memset(&ctrl, 0, sizeof(struct v4l2_control)); memset(&qc_ctrl, 0, sizeof(struct v4l2_queryctrl)); ctrl.id = V4L2_CID_SENSOR_TYPE; qc_ctrl.id = V4L2_CID_SENSOR_TYPE; if (-1 == ioctl (deviceHandle, VIDIOC_QUERYCTRL, &qc_ctrl)){ fprintf(stderr, "V4L2: %s QUERY V4L2_CID_SENSOR_TYPE failed\n", deviceName.c_str()); return false; } if (-1 == ioctl(deviceHandle, VIDIOC_G_CTRL, &ctrl)) { fprintf(stderr, "V4L2: %s G_CTRL V4L2_CID_SENSOR_TYPE failed\n", deviceName.c_str()); return false; } return ctrl.value == V4L2_SENSOR_TYPE_RAW;}#endif这段代码的功能是检查V4L2摄像头设备的传感器类型是否为RAW格式。它使用了V4L2的ioctl函数来查询和获取传感器类型信息。然后在OpenCV的捕获流函数:bool CvCaptureCAM_V4L::streaming(bool startStream)添加 ISP 处理#ifdef __USE_VIN_ISP__ RawSensor = RAWSensor(); if (startStream && RawSensor) { int VideoIndex = -1; sscanf(deviceName.c_str(), "/dev/video%d", &VideoIndex); IspPort = CreateAWIspApi(); IspId = -1; IspId = IspPort->ispGetIspId(VideoIndex); if (IspId >= 0) IspPort->ispStart(IspId); } else if (RawSensor && IspId >= 0 && IspPort) { IspPort->ispStop(IspId); DestroyAWIspApi(IspPort); IspPort = NULL; IspId = -1; }#endif这段代码主要用于控制图像信号处理(ISP)的启动和停止。根据条件的不同,可以选择在开始视频流捕获时启动ISP流处理,或者在停止视频流捕获时停止ISP流处理,以便对视频数据进行处理和增强。至于其他包括编译脚本的修改,全局变量定义等操作,可以参考原文链接中的补丁文件。在执行完以上步骤后,可以快速测试摄像头输出demo:OpenCV ---> <*> opencv....................................................... opencv libs
- Enabel sunxi vin isp support <*> opencv_camera.............................opencv_camera and display image
MobileNet V2是一种轻量级的卷积神经网络,它专为移动设备和嵌入式设备上的实时图像分类和目标检测任务设计。MobileNet V2的关键特点包括使用深度可分离卷积来减少计算量和参数数量,引入带线性瓶颈的倒残差结构以增加非线性表示能力,以及提供宽度乘数参数以适应不同计算资源限制。这些特点使得MobileNet V2成为资源受限的移动设备上的理想选择。首先对输入图像进行预处理,以适应MobileNet V2 SSD模型的输入要求。通过通道格式转换、图像大小调整和数据填充等操作,将输入图像转换为适合模型输入的格式。void get_input_data(const cv::Mat& sample, uint8_t* input_data, int input_h, int input_w, const float* mean, const float* scale){ cv::Mat img; if (sample.channels() == 1) cv::cvtColor(sample, img, cv::COLOR_GRAY2RGB); else cv::cvtColor(sample, img, cv::COLOR_BGR2RGB); cv::resize(img, img, cv::Size(input_h, input_w)); uint8_t* img_data = img.data; /* nhwc to nchw */ for (int h = 0; h < input_h; h++) { for (int w = 0; w < input_w; w++) { for (int c = 0; c < 3; c++) { int in_index = h * input_w * 3 + w * 3 + c; int out_index = c * input_h * input_w + h * input_w + w; input_data[out_index] = (uint8_t)(img_data[in_index]); //uint8关键步骤是要实现非极大值抑制算法(NMS),用于去除高度重叠的框,只保留得分最高的那个框。算法通过计算框之间的交集面积和设置的阈值来进行筛