3合一網(wǎng)站怎么做免費推廣工具有哪些
用39塊錢的V851se視覺開發(fā)板做了個小相機。
可以進行物品識別、自動追焦!
這個超低成本的小相機是在V851se上移植使用全志在線開源版本的Tina Linux與OpenCV框架開啟攝像頭拍照捕獲視頻,并結(jié)合NPU實現(xiàn)Mobilenet v2目標分類識別以及運動追蹤等功能…并最終實現(xiàn)功能完整的智能小相機。
ISP適配
可以適配V851se的Tina5.0升級到了21.05版本的OpenWrt,相較于商業(yè)量產(chǎn)版本的Tina Linux 支持更多新的軟件包,不過可惜的是MPP包沒有移植到Tina5.0,所以想使用攝像頭就需要另辟蹊徑。
雖然Tina5.0并沒有移植MPP包,但也內(nèi)置了一個libAWispApi包,支持在用戶層對接 ISP,但是很可惜這個包也沒有適配V85x系列,這里就需要自行適配。
其實適配很簡單,SDK 已經(jīng)提供了lib只是沒提供編譯支持,我們需要前往以下文件夾中新建一個v851se文件夾:
openwrt/package/allwinner/vision/libAWIspApi/machinfo
然后再新建文件build.mk寫入如下配置:
ISP_DIR:=isp600
然后在menuconfig中勾選上這個包,并進行如下配置:
Allwinner --->Vision ---><*> camerademo........................................ camerademo test sensor --->[*] Enabel vin isp support
編譯系統(tǒng)然后燒錄系統(tǒng),運行命令 camerademo ,可以看到是正常拍攝照片的
OpenCV適配
OpenCV在打包好的固件中已經(jīng)默認適配好了,如果不想了解如何適配OpenCV可以直接前往點擊鏈接獲取資料并跳過這部分
OpenCV默認不支持開啟RAW Sensor,不過現(xiàn)在需要配置為OpenCV開啟RAW Sensor抓圖,然后通過OpenCV送圖到之前適配的libAWispApi庫進行 ISP 處理。
在這里增加一個函數(shù)作為 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攝像頭設(shè)備的傳感器類型是否為RAW格式。它使用了V4L2的ioctl函數(shù)來查詢和獲取傳感器類型信息。
然后在OpenCV的捕獲流函數(shù):
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)的啟動和停止。根據(jù)條件的不同,可以選擇在開始視頻流捕獲時啟動ISP流處理,或者在停止視頻流捕獲時停止ISP流處理,以便對視頻數(shù)據(jù)進行處理和增強。
至于其他包括編譯腳本的修改,全局變量定義等操作,可以參考原文鏈接中的補丁文件。
在執(zhí)行完以上步驟后,可以快速測試攝像頭輸出demo:
OpenCV ---><*> opencv....................................................... opencv libs[*] Enabel sunxi vin isp support<*> opencv_camera.............................opencv_camera and display image
MobileNet V2
MobileNet V2是一種輕量級的卷積神經(jīng)網(wǎng)絡(luò),它專為移動設(shè)備和嵌入式設(shè)備上的實時圖像分類和目標檢測任務(wù)設(shè)計。
MobileNet V2的關(guān)鍵特點包括使用深度可分離卷積來減少計算量和參數(shù)數(shù)量,引入帶線性瓶頸的倒殘差結(jié)構(gòu)以增加非線性表示能力,以及提供寬度乘數(shù)參數(shù)以適應(yīng)不同計算資源限制。這些特點使得MobileNet V2成為資源受限的移動設(shè)備上的理想選擇。
首先對輸入圖像進行預(yù)處理,以適應(yīng)MobileNet V2 SSD模型的輸入要求。通過通道格式轉(zhuǎn)換、圖像大小調(diào)整和數(shù)據(jù)填充等操作,將輸入圖像轉(zhuǎn)換為適合模型輸入的格式。
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);elsecv::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
關(guān)鍵步驟是要實現(xiàn)非極大值抑制算法(NMS),用于去除高度重疊的框,只保留得分最高的那個框。算法通過計算框之間的交集面積和設(shè)置的閾值來進行篩選,并將保留的框的索引存儲在picked向量中。
// 非極大值抑制算法(NMS)
static void nms_sorted_bboxes(const std::vector<Bbox_t>& bboxs, std::vector<int>& picked, float nms_threshold) {picked.clear();const int n = bboxs.size();// 創(chuàng)建存儲每個框面積的向量std::vector<float> areas(n);// 計算每個框的面積并存儲for (int i = 0; i < n; i++){areas[i] = (bboxs[i].xmax - bboxs[i].xmin) * (bboxs[i].ymax - bboxs[i].ymin);
通過一系列操作,包括轉(zhuǎn)換為向量、計算縮放比例、創(chuàng)建存儲檢測結(jié)果的向量等,將輸出數(shù)據(jù)轉(zhuǎn)換為檢測結(jié)果,并按照置信度從高到低排序。然后應(yīng)用非極大值抑制算法對檢測結(jié)果進行篩選,最后將篩選后的目標框位置、大小和類別置信度等信息繪制在圖像上。
// 按照分數(shù)對框進行排序std::sort(BBox.begin(), BBox.end(), comp);// 應(yīng)用非極大值抑制算法,獲取保留的框的索引std::vector<int> keep_index;nms_sorted_bboxes(BBox, keep_index, iou_threshold);// 創(chuàng)建存儲框位置的向量std::vector<cv::Rect> bbox_per_frame;// 遍歷保留的框,繪制框和標簽for(int i = 0; i < keep_index.size(); i++) {int left = BBox[keep_index[i]].xmin;int top = BBox[keep_index[i]].ymin;int right = BBox[keep_index[i]].xmax;int bottom = BBox[keep_index[i]].ymax;cv::rectangle(bgr, cv::Point(left, top), cv::Point(right, bottom), cv::Scalar(0, 0, 255), 1);char text[256];sprintf(text, "%s %.1f%%", class_names[BBox[keep_index[i]].cls_idx], BBox[keep_index[i]].score * 100);cv::putText(bgr, text, cv::Point(left, top), cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(0, 255, 255), 1, 8, 0);bbox_per_frame.emplace_back(left, top, width, height);}
NPU開發(fā)流程
V851se芯片內(nèi)置一顆NPU,其處理性能為最大0.5TOPS并有128KB內(nèi)部高速緩存用于高速數(shù)據(jù)交換,NPU 開發(fā)完整的流程如下圖所示:
模型訓(xùn)練
在模型訓(xùn)練階段,用戶根據(jù)需求和實際情況選擇合適的框架(如Caffe、TensorFlow 等)使用數(shù)據(jù)集進行訓(xùn)練得到符合需求的模型,此模型可稱為預(yù)訓(xùn)練模型。也可直接使用已經(jīng)訓(xùn)練好的模型。V851s 的 NPU 支持包括分類、檢測、跟蹤、人臉、姿態(tài)估計、分割、深度、語音、像素處理等各個場景90 多個公開模型。
signal函數(shù)
在模型轉(zhuǎn)化階段,通過Acuity Toolkit把預(yù)訓(xùn)練模型和少量訓(xùn)練數(shù)據(jù)轉(zhuǎn)換為NPU可用的模型NBG文件。一般步驟如下:
1、模型導(dǎo)入,生成網(wǎng)絡(luò)結(jié)構(gòu)文件、網(wǎng)絡(luò)權(quán)重文件、輸入描述文件和輸出描述文件。
2、模型量化,生成量化描述文件和熵值文件,可改用不同的量化方式。
3、仿真推理,可逐一對比float和其他量化精度的仿真結(jié)果的相似度,評估量化后的精度是否滿足要求。
4、模型導(dǎo)出,生成端側(cè)代碼和*.nb 文件,可編輯輸出描述文件的配置,配置是否添加后處理節(jié)點等。