0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

RK3568开发板:USB摄像头实时AI物品识别代码实现

电子发烧友开源社区 来源:未知 2023-03-11 14:15 次阅读

上篇文章演示了使用飞凌OK3568-C开发板外接USB摄像头进行AI物品识别,并进行了视频演示,本篇来介绍下代码实现。

01

SSD模型介绍

SSD,全称为Single Shot MultiBox Detector,是Wei Liu在ECCV 2016上提出的一种目标检测算法,属于一阶段One Stage方法,SSD 模型利用不同尺度的特征图进行目标的检测,其模型结构图如下:

8d4b2dbe-bfd2-11ed-bfe3-dac502259ad0.png

SSD具有如下主要特点:

  • 从YOLO中继承了将detection转化为regression的思路,同时一次即可完成网络训练

  • 基于Faster RCNN中的anchor,提出了相似的prior box

  • 加入基于特征金字塔(Pyramidal Feature Hierarchy)的检测方式,相当于半个FPN思路

SSD网络结构图如下:

8d6790da-bfd2-11ed-bfe3-dac502259ad0.png

其算法步骤为:

  • 将图像输入预训练好的分类网络(基于VGG16-Atrous)得到不同大小的特征映射

  • 分别提取Conv4_3、Conv7、Conv8_2、Conv9_2、Conv10_2、Conv11_2层的特征映射feature map,在每个特征映射的每个点构造6个不同大小尺度的bounding box,进行检测和分类来生成一些列bounding box

  • 采用NMS处理不同特征映射的bounding box,删掉部分重叠或者不正确的bounding box,得到最终的检测框

OK3568-C开发板中自带了已训练好的AI模型,位于/userdata/model目录下的ssd_inception_v2.rknn,我们直接用就可以了。

02

USB摄像头实现物品识别代码

先来看下整个代码的项目结构,然后再来分别介绍各个功能模块。

  • imageutil.h:图像类型转换相关函数

  • myvideosourceface.cpp/h:用于USB摄像头图像显示

  • qtcamera.cpp/h:qt界面

  • rknn_ssd_process.cpp/h:用于SSD模型进行AI物品识别的接口函数

  • rknn_ssd.cpp/h:SSD模型相关函数

8d815498-bfd2-11ed-bfe3-dac502259ad0.png

03

按帧获取USB摄像头图像

3.1 改为自己的Viewfinder

之前测试USB摄像头显示时,使用的是Qt的QCameraViewfinder用来显示摄像头图像,为了能获取到每一帧的图像,可以自己实现一个Viewfinder,然后在m_camera->setViewfinder时设置为自己的,并添加槽函数rcvFrame,当获取到一帧图像时,会触发此函数。

void qtCamera::on_cameraClick()
{
  //创建摄像头对象
  m_camera = new QCamera(m_cameraInfo);


  m_camera->unload();
  //配置摄像头的模式--捕获静止图像
  m_camera->setCaptureMode(QCamera::CaptureStillImage);


  //设置默认摄像头参数
  QCameraViewfinderSettings set;
  set.setResolution(640, 480);         //设置显示分辨率
  set.setMaximumFrameRate(25);         //设置帧率


  //自己用QPainter将每一帧视频画出来
  myvideosurface *surface = new myvideosurface(this);


  //设置取景器显示
  m_camera->setViewfinder(surface);
  connect(surface, SIGNAL(frameAvailable(QVideoFrame)), this, SLOT(rcvFrame(QVideoFrame)), Qt::DirectConnection);
  connect(this,SIGNAL(sendOneQImage(QImage)), this, SLOT(recvOneQImage(QImage)));


  //启动摄像头
  m_camera->start();
}

(左右移动查看全部内容)

接收到一帧图像后,其原始图像格式是QVideoFrame类型的,需要先转为QImage类型,然后就可以进行显示或进行图像处理了,这里触发一个sendOneQImage信号来通知进行图像处理:

void qtCamera::rcvFrame(QVideoFrame m_currentFrame)
{
  m_currentFrame.map(QAbstractVideoBuffer::ReadOnly);


  QImage videoImg = QImage(m_currentFrame.bits(),
          m_currentFrame.width(),
          m_currentFrame.height(),
          QVideoFrame::imageFormatFromPixelFormat(m_currentFrame.pixelFormat())).copy(); 
  
  m_currentFrame.unmap(); 
  QWidget::update();   


  emit sendOneQImage(videoImg); //发送信号
}

(左右移动查看全部内容)

3.2 自定义Viewfinder的实现

参考网上的一些代码实现,其主要逻辑如下:

bool myvideosurface::present(const QVideoFrame &frame)
{
  if (frame.isValid())
  {
    QVideoFrame cloneFrame(frame);        
    emit frameAvailable(cloneFrame);  
    return true;
  }
  stop();
  return false;
}


//这些虚函数,会自动被调用,start检测图像是否可以对等转换,每一帧有没有
bool myvideosurface::start(const QVideoSurfaceFormat &videoformat)
{
  if(QVideoFrame::imageFormatFromPixelFormat(videoformat.pixelFormat()) != QImage::Format_Invalid && !videoformat.frameSize().isEmpty())
  {
    QAbstractVideoSurface::start(videoformat);
    return true;
  }
  return false;
}


void myvideosurface::stop()
{
  QAbstractVideoSurface::stop();
}


//将视频流中像素格式转换成格式对等的图片格式,若无对等的格式,返回QImage::Format_Invalid
bool myvideosurface::isFormatSupported(const QVideoSurfaceFormat &videoformat) const
{
  //imageFormatFromPixelFormat()-----返回与视频帧像素格式等效的图像格式
  //pixelFormat()-----返回视频流中帧的像素格式
  return QVideoFrame::imageFormatFromPixelFormat(videoformat.pixelFormat()) != QImage::Format_Invalid;
}


//支持的像素格式
QListmyvideosurface::supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const
{
  if(handleType == QAbstractVideoBuffer::NoHandle){
    return QList() << QVideoFrame::Format_RGB32
                         << QVideoFrame::Format_ARGB32
                         << QVideoFrame::Format_ARGB32_Premultiplied
                         << QVideoFrame::Format_RGB565
                         << QVideoFrame::Format_RGB555;
    qDebug() << QList() << QVideoFrame::Format_RGB32;
  }
  else
  {
    return QList();
  }
}

(左右移动查看全部内容)

对应的头文件类定义:

class myvideosurface : public QAbstractVideoSurface
{
  Q_OBJECT


public:
  explicit myvideosurface(QObject *parent = nullptr);
  ~myvideosurface() Q_DECL_OVERRIDE;


  bool present(const QVideoFrame &) Q_DECL_OVERRIDE;  //每一帧画面将回到这里处理
  bool start(const QVideoSurfaceFormat &) Q_DECL_OVERRIDE; //只有摄像头开,就会调用
  void stop() Q_DECL_OVERRIDE;  //出错就停止了
  bool isFormatSupported(const QVideoSurfaceFormat &) const Q_DECL_OVERRIDE;  
  QListsupportedPixelFormats(QAbstractVideoBuffer::HandleType type = QAbstractVideoBuffer::NoHandle) const Q_DECL_OVERRIDE;


private:
  QVideoFrame m_currentFrame;  //视频帧


signals:
  void frameAvailable(QVideoFrame); //将捕获的每一帧视频通过信号槽方式发出去
};

(左右移动查看全部内容)

04

图像类型的转换与显示

4.1 QImage转Mat

Qt是QCamera创建的USB摄像头,获取到的图片格式是QImage类型,而使用OpenCV进行图像处理,需要转换为cv::Mat类型,转换的方式如下:

cv::Mat QImageToMat(QImage image)
{
  image = image.convertToFormat(QImage::Format_RGB888);
  cv::Mat tmp(image.height(), image.width(), CV_8UC3, (uchar *)image.bits(), image.bytesPerLine());
  cv::Mat result; // deep copy just in case (my lack of knowledge with open cv)
  cvtColor(tmp, result, CV_BGR2RGB);
  return result;
}

(左右移动查看全部内容)

4.2 Mat转QImage

OpenCV进行图像处理完成后,比如进行AI物品识别完成,并将识别的信息标记到图像上后,需要再转成QImage的类型用于在Qt中显示出来,转换的方式如下:

QImage MatToQImage(cv::Mat mat)
{
  cv::cvtColor(mat, mat, CV_BGR2RGB);
  QImage qim((const unsigned char *)mat.data, mat.cols, mat.rows, mat.step,
        QImage::Format_RGB888);
  return qim;
}

(左右移动查看全部内容)

4.3 QImage转QPixmap

QImage在Qt中还不能直接显示出来,还需要再转为QPixmap类型,转换的方式如下:

QImage qImage;
QPixmap tempPixmap = QPixmap::fromImage(qImage);

(左右移动查看全部内容)

4.4 图像的显示

这里创建一个QLabel用于显示图像,调用setPixmap方法即可将图像显示出来,最后的adjustSize用来自动调整大小。

//创建一个label用于显示图像
m_lableShowImg = new QLabel();
m_lableShowImg->setPixmap(tempPixmap);
m_lableShowImg->adjustSize();

(左右移动查看全部内容)

05

RKNN例程移植

飞凌OK3568-C开发板资料中,自带了ssd模型的测试程序,代码位置如下,ssd的测试代码是这3个文件:

8da65f68-bfd2-11ed-bfe3-dac502259ad0.png

测试代码,需要在执行时,输入模型的目录位置和测试图片的位置,AI物品识别之后会产生一个输出图片,需要再使用图片查看器查看结果。

为了方便功能的调用,这里将fltest_opencv_rknn_ssd_main.cc改写为rknn_ssd_process.cpp,并将具体功能进行拆分,封装为C++的形式。

5.1 按功能封装为C++形式

自己封装的RknnSsdModel类定义:

class RknnSsdModel
{
public:
  RknnSsdModel(){};
  ~RknnSsdModel(){};


  int RknnInit(const char *model_path);
  int RknnDeInit();
  unsigned char *LoadModel(const char *filename, int *model_size);
  int DoRknnSsd(cv::Mat &src, cv::Mat &res);


private:
  unsigned char *m_pModel = nullptr;
  rknn_context m_rknnCtx;
  rknn_input_output_num m_rknnIoNum;


};

(左右移动查看全部内容)

5.1.1 RKNN初始化

主要功能是根据传入的rknn模型进行相关的初始化

int RknnSsdModel::RknnInit(const char *model_path)
{
  int ret = 0;
  int model_len = 0;


  // Load RKNN Model
  printf("Loading model ...
");
  m_pModel = LoadModel(model_path, &model_len);


  printf("rknn_init ...
");
  ret = rknn_init(&m_rknnCtx, m_pModel, model_len, 0, NULL);
  if (ret < 0)
  {
    printf("rknn_init fail! ret=%d
", ret);
    return -1;
  }


  // Get Model Input Output Info
  ret = rknn_query(m_rknnCtx, RKNN_QUERY_IN_OUT_NUM, &m_rknnIoNum, sizeof(m_rknnIoNum));
  if (ret != RKNN_SUCC)
  {
    printf("rknn_query fail! ret=%d
", ret);
    return -1;
  }
  printf("model input num: %d, output num: %d
", m_rknnIoNum.n_input, m_rknnIoNum.n_output);


  printf("input tensors:
");
  rknn_tensor_attr input_attrs[m_rknnIoNum.n_input];
  memset(input_attrs, 0, sizeof(input_attrs));
  for (int i = 0; i < m_rknnIoNum.n_input; i++)
  {
    input_attrs[i].index = i;
    ret = rknn_query(m_rknnCtx, RKNN_QUERY_INPUT_ATTR, &(input_attrs[i]), sizeof(rknn_tensor_attr));
    if (ret != RKNN_SUCC)
    {
      printf("rknn_query fail! ret=%d
", ret);
      return -1;
    }
    printRKNNTensor(&(input_attrs[i]));
  }


  printf("output tensors:
");
  rknn_tensor_attr output_attrs[m_rknnIoNum.n_output];
  memset(output_attrs, 0, sizeof(output_attrs));
  for (int i = 0; i < m_rknnIoNum.n_output; i++)
  {
    output_attrs[i].index = i;
    ret = rknn_query(m_rknnCtx, RKNN_QUERY_OUTPUT_ATTR, &(output_attrs[i]), sizeof(rknn_tensor_attr));
    if (ret != RKNN_SUCC)
    {
      printf("rknn_query fail! ret=%d
", ret);
      return -1;
    }
    printRKNNTensor(&(output_attrs[i]));
  }


  return ret;
}

(左右移动查看全部内容)

5.1.2 RKNN运行

传入一张Mat格式的图片(一帧视频图像),经过AI识别,并将识别的信息标注到图片上后,将识别结果也以Mat格式传出:

int RknnSsdModel::DoRknnSsd(cv::Mat &src, cv::Mat &res)
{
  const int img_width = 300;
  const int img_height = 300;
  const int img_channels = 3;
  int ret = 0;


  cv::Mat img = src.clone();
  if (src.cols != img_width || src.rows != img_height)
  {
    printf("resize %d %d to %d %d
", src.cols, src.rows, img_width, img_height);
    cv::resize(src, img, cv::Size(img_width, img_height), (0, 0), (0, 0), cv::INTER_LINEAR);
  }


  // Set Input Data
  rknn_input inputs[1];
  memset(inputs, 0, sizeof(inputs));
  inputs[0].index = 0;
  inputs[0].type = RKNN_TENSOR_UINT8;
  inputs[0].size = img.cols * img.rows * img.channels();
  inputs[0].fmt = RKNN_TENSOR_NHWC;
  inputs[0].buf = img.data;


  ret = rknn_inputs_set(m_rknnCtx, m_rknnIoNum.n_input, inputs);
  if (ret < 0)
  {
    printf("rknn_input_set fail! ret=%d
", ret);
    return -1;
  }


  // Run
  printf("rknn_run
");
  ret = rknn_run(m_rknnCtx, nullptr);
  if (ret < 0)
  {
    printf("rknn_run fail! ret=%d
", ret);
    return -1;
  }


  // Get Output
  rknn_output outputs[2];
  memset(outputs, 0, sizeof(outputs));
  outputs[0].want_float = 1;
  outputs[1].want_float = 1;
  ret = rknn_outputs_get(m_rknnCtx, m_rknnIoNum.n_output, outputs, NULL);
  if (ret < 0)
  {
    printf("rknn_outputs_get fail! ret=%d
", ret);
    return -1;
  }


  // Post Process
  detect_result_group_t detect_result_group;
  postProcessSSD((float *)(outputs[0].buf), (float *)(outputs[1].buf), src.cols, src.rows, &detect_result_group);
  // Release rknn_outputs
  rknn_outputs_release(m_rknnCtx, 2, outputs);


  // Draw Objects
  for (int i = 0; i < detect_result_group.count; i++)
  {
    detect_result_t *det_result = &(detect_result_group.results[i]);
    printf("%s @ (%d %d %d %d) %f
",
        det_result->name,
        det_result->box.left, det_result->box.top, det_result->box.right, det_result->box.bottom,
        det_result->prop);
    int x1 = det_result->box.left;
    int y1 = det_result->box.top;
    int x2 = det_result->box.right;
    int y2 = det_result->box.bottom;
    rectangle(src, Point(x1, y1), Point(x2, y2), Scalar(255, 0, 0, 255), 3);
    putText(src, det_result->name, Point(x1, y1 - 12), 1, 4, Scalar(0, 255, 0, 255), 4);
  }


  res = src;
  return 0;
}

(左右移动查看全部内容)

5.2 AI识别调用

OK3568-C开发板中自带了已训练好的AI模型,位于/userdata/model目录下的ssd_inception_v2.rknn,在程序初始化时需要用到。

8dbb9a40-bfd2-11ed-bfe3-dac502259ad0.png

AI识别的代码逻辑为:先在qtCamera初始化时调用RKNN的初始化,然后打开USB摄像头,USB获取到每帧图像后, 调用DoRknnSsd进行AI物品识别,最后将识别的结果通过setPixmap方法展示出来

//先在qtCamera初始化时调用RKNN的初始化
std::string ssd_model = "/userdata/model/ssd_inception_v2.rknn";
m_rknnModel.RknnInit(ssd_model.c_str());


//USB获取到每帧图像后, 调用DoRknnSsd进行AI物品识别
void qtCamera::recvOneQImage(QImage qImage)
{
  cv::Mat srcImg = ImageUtil::QImageToMat(qImage);
  cv::Mat dstImg;
  m_rknnModel.DoRknnSsd(srcImg, dstImg);
  QImage qDstImage = ImageUtil::MatToQImage(dstImg);
  QPixmap tempPixmap = QPixmap::fromImage(qDstImage);


  m_lableShowImg->setPixmap(tempPixmap);
  m_lableShowImg->adjustSize();
}

(左右移动查看全部内容)

5.3 编译

需要注意下Qt工程的配置文件,要把opencv的一些库链接进去

qcamera.pri

INCLUDEPATH     += $$PWD/src


HEADERS += 
  $$PWD/src/qtcamera.h 
  $$PWD/src/myvideosurface.h 
  $$PWD/src/rknn_ssd.h 
  $$PWD/src/rknn_ssd_process.h 
  $$PWD/src/imageutil.h


SOURCES += 
  $$PWD/src/qtcamera.cpp 
  $$PWD/src/myvideosurface.cpp 
  $$PWD/src/rknn_ssd.cpp 
  $$PWD/src/rknn_ssd_process.cpp

(左右移动查看全部内容)

qcamera.pro

TARGET = USBCameraSSD
TEMPLATE = app


QT += widgets multimedia multimediawidgets


SOURCES += main.cpp


include($$PWD/qcamera.pri)


LIBS+=-lopencv_core -lopencv_objdetect -lopencv_highgui -lopencv_videoio -lopencv_imgproc -lopencv_imgcodecs -lrknn_api -lOpenCL -lpthread


#temp file
DESTDIR     = $$PWD/app_bin
MOC_DIR     = $$PWD/build/qcamera
OBJECTS_DIR   = $$PWD/build/qcamera

(左右移动查看全部内容)

最后的编译脚本还和之前的一样:

#! /bin/bash


mkdir -p build
cd build


export PATH=/home/xxpcb/myTest/OK3568/sourcecode/OK3568-linux-source/buildroot/output/OK3568/host/bin:$PATH


qmake .. && make

(左右移动查看全部内容)

06

总结

本篇介绍了在飞凌OK3568-C开发板中,外接USB摄像头,利用Qt和RKNN进行AI物品识别,通过已训练好的SSD模型,进行摄像头画面的实时AI物品检查的代码实现原理。

8dc969c2-bfd2-11ed-bfe3-dac502259ad0.png


更多热点文章阅读
  • OS内核及视窗分论坛详解之OpenHarmony 3D显示支持
  • 应用模型开发指南上新介绍
  • 技术构筑万物智联,第一届OpenHarmony技术峰会圆满举行
  • OpenHarmony L1(3.0)串口功能开发
  • 小白指南:手把手教你用低代码开发一个应用页面

提示:本文由电子发烧友论坛发布,转载请注明来源。如需社区合作及入群交流,请添加微信EEFans0806,或者发邮箱liuyong@huaqiu.com。


原文标题:RK3568开发板:USB摄像头实时AI物品识别代码实现

文章出处:【微信公众号:电子发烧友开源社区】欢迎添加关注!文章转载请注明出处。


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 电子发烧友
    +关注

    关注

    33

    文章

    546

    浏览量

    32359
  • 开源社区
    +关注

    关注

    0

    文章

    92

    浏览量

    342

原文标题:RK3568开发板:USB摄像头实时AI物品识别代码实现

文章出处:【微信号:HarmonyOS_Community,微信公众号:电子发烧友开源社区】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    迅为RK3568开发板驱动开发指南-输入子系统

    迅为RK3568开发板驱动开发指南-输入子系统
    的头像 发表于 02-23 15:11 211次阅读
    迅为<b class='flag-5'>RK3568</b><b class='flag-5'>开发板</b>驱动<b class='flag-5'>开发</b>指南-输入子系统

    RK3568-视频开发案例

    RK3568-视频开发案例
    的头像 发表于 01-18 15:51 293次阅读
    <b class='flag-5'>RK3568</b>-视频<b class='flag-5'>开发</b>案例

    toybrick_RK3568X开发板:跑通 android 开发流程

    前段时间买了一块官方的开发板,瑞芯微的 RK3568 芯片的 toybrick TB-RK3568X 开发板,配置是 4G 内存,32G 存储,想用这个
    发表于 11-16 21:30

    RK3568开发板SG90 舵机模块的功能实现

    RK3568开发板SG90 舵机模块的功能实现-迅为电子
    的头像 发表于 09-20 14:29 442次阅读
    <b class='flag-5'>RK3568</b><b class='flag-5'>开发板</b>SG90 舵机模块的功能<b class='flag-5'>实现</b>

    迅为RK3568开发板Debian系统使用python 进行摄像头开发

    迅为RK3568开发板Debian系统使用python 进行摄像头开发
    的头像 发表于 09-14 16:58 657次阅读
    迅为<b class='flag-5'>RK3568</b><b class='flag-5'>开发板</b>Debian系统使用python 进行<b class='flag-5'>摄像头</b><b class='flag-5'>开发</b>

    瑞芯微RK3568开发板多屏同显方案

    HD-RK3568核心板基于瑞芯微RK3568设计,支持HDMI、MIPI、eDP、LVDS四种显示接口,适配多种显示方案,满足医疗电子、电力电子、工业自动化、车载中控等多种行业应用。
    的头像 发表于 09-14 14:03 758次阅读
    瑞芯微<b class='flag-5'>RK3568</b><b class='flag-5'>开发板</b>多屏同显方案

    迅为RK3568开发板GPIO之外接模块

    迅为RK3568开发板GPIO之外接模块
    的头像 发表于 08-24 17:41 673次阅读
    迅为<b class='flag-5'>RK3568</b><b class='flag-5'>开发板</b>GPIO之外接模块

    rk3568是什么架构的?

    在22nm FD-SOI工艺节点上。那么,RK3568使用什么架构呢? RK3568采用ARM控股公司开发的ARM Cortex-A55四核CPU架构。Cortex-A55是ARM最新、最高效的CPU
    的头像 发表于 08-15 17:25 1656次阅读

    瑞芯微RK3568主板开发板PET_RK3568_P01简述

    瑞芯微RK3568主板开发板PET_RK3568_P01简述
    的头像 发表于 08-08 11:41 1773次阅读
    瑞芯微<b class='flag-5'>RK3568</b>主板<b class='flag-5'>开发板</b>PET_<b class='flag-5'>RK3568</b>_P01简述

    RK3568 MIPI CSI摄像头GC8034适配工作流程

    首先介绍一下硬件。主板为风火轮科技的YY3568开发板,主控RK3568。此开发板的相关介绍可以参考
    的头像 发表于 07-04 09:27 2955次阅读
    <b class='flag-5'>RK3568</b> MIPI CSI<b class='flag-5'>摄像头</b>GC8034适配工作流程

    迅为RK3568/RK3588开发板视频教程 | RKNPU2 从入门到实践一套搞定!

    迅为RK3568/RK3588开发板视频教程 | RKNPU2 从入门到实践一套搞定!
    的头像 发表于 06-30 15:07 1005次阅读
    迅为<b class='flag-5'>RK3568</b>/<b class='flag-5'>RK</b>3588<b class='flag-5'>开发板</b>视频教程 | RKNPU2 从入门到实践一套搞定!

    触觉智能RK3568_OpenHarmony开发板适配

    触觉智能RK3568_OpenHarmony开发板适配 2023-5-24 master openharmony 4.0.7.3 openharmony版本更新代码会变化,请看当前文件夹其他md
    的头像 发表于 06-07 16:18 719次阅读
    触觉智能<b class='flag-5'>RK3568</b>_OpenHarmony<b class='flag-5'>开发板</b>适配

    基于Rockchip RK3568的路由器开发方案

    Banana Pi BPI-R2 Pro 开源路由器采用Rockchip RK3568芯片方案设计, 板载2GB LPDDR4内存和16GB eMMC存储,支持2个USB 3.0接口,5千兆网口
    发表于 06-07 09:17

    国产工业级RK3568核心板-AI人脸识别产品方案

    国产工业级RK3568核心板-AI人脸识别产品方案
    的头像 发表于 05-06 14:51 721次阅读
    国产工业级<b class='flag-5'>RK3568</b>核心板-<b class='flag-5'>AI</b>人脸<b class='flag-5'>识别</b>产品方案

    国产工业级RK3568核心-AI人脸识别产品方案

    迅为RK3568开发板采用瑞芯微推出的一款高性能、低功耗的RK3568处理器,其拥有强大的AI计算能力和图像处理能力,非常适合用于人脸识别
    发表于 05-06 14:30