電子發(fā)燒友App

硬聲App

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示
創(chuàng)作
電子發(fā)燒友網(wǎng)>電子資料下載>電子資料>Ultra96 V2上基于標(biāo)記的增強(qiáng)現(xiàn)實(shí)

Ultra96 V2上基于標(biāo)記的增強(qiáng)現(xiàn)實(shí)

2022-11-16 | zip | 0.22 MB | 次下載 | 2積分

資料介紹

描述

介紹

增強(qiáng)現(xiàn)實(shí) (AR) 是真實(shí)世界環(huán)境的實(shí)時視圖,已通過計(jì)算機(jī)生成的圖形進(jìn)行了增強(qiáng)。AR有兩種實(shí)現(xiàn)方式:

  • 基于標(biāo)記的增強(qiáng)現(xiàn)實(shí)
  • 無標(biāo)記 AR

Marker-less AR 更加復(fù)雜,并且依賴于真實(shí)環(huán)境來確定參考點(diǎn)。這通常涉及識別物體和/或背景線索,例如地板和墻壁。

基于標(biāo)記的 AR 更易于實(shí)現(xiàn),并且依賴于場景中的方形標(biāo)記。

該項(xiàng)目將描述如何使用 OpenCV 在 Ultra96-V2 上實(shí)現(xiàn)基于標(biāo)記的 AR。

讓我們開始吧 !

靈感

在開始之前,我想分享一下這個項(xiàng)目的靈感和動力。

我受到以下創(chuàng)新產(chǎn)品/教程的啟發(fā):

  • 彩通,配色卡,
  • Adrian Rosebrock,使用 OpenCV 和 Python 檢測 ArUco 標(biāo)記,PyImageSearch,

動機(jī)

我實(shí)現(xiàn)類似功能的動機(jī)是能夠使用標(biāo)記自動觸發(fā)某種校準(zhǔn),例如:

  • 白平衡,使用白色參考圖表
  • 立體校準(zhǔn),使用棋盤參考圖

為了實(shí)現(xiàn)這一點(diǎn),我創(chuàng)建了以下三個圖表(使用 Microsoft Word)進(jìn)行實(shí)驗(yàn)。

?

在這項(xiàng)目中,我會檢測這些圖表的存在,并根據(jù)圖表進(jìn)行額外的處理:

  • 圖表 1 - 在棋盤圖案周圍畫一個綠色框
  • 圖表 2 - 測量標(biāo)記內(nèi)區(qū)域中 B、GR 像素的平均值,并在圖表上顯示帶有值的條形圖
  • 圖表 2 - 測量標(biāo)記內(nèi)區(qū)域的顏色直方圖,并在圖表上顯示直方圖

有關(guān)生成這些標(biāo)記的更多信息,請參閱以下優(yōu)秀教程:

  • Adrian Rosebrock,使用 OpenCV 和 Python 生成 ArUco 標(biāo)記,PyImageSearch,

檢測場景中的標(biāo)記

定義好目標(biāo)并創(chuàng)建帶有標(biāo)記的圖表后,我們就可以開始實(shí)施了。

我選擇用 C++ 實(shí)現(xiàn)這個項(xiàng)目,作為一個 gstreamer 插件。我需要感謝Tom Simpson為創(chuàng)建 gstreamer 插件奠定了基礎(chǔ)。

第一步是檢測場景中的標(biāo)記。這是通過 OpenCV 完成的。

/* Aruco Markers */
#include 

...

//
// Detect ARUCO markers
//   ref : https://docs.opencv.org/master/d5/dae/tutorial_aruco_detection.html
//
std::vector markerIds;
std::vector<std::vector<cv::Point2f>> markerCorners, rejectedCandidates;
cv::Ptr<cv::aruco::DetectorParameters> parameters = cv::aruco::DetectorParameters::create();
cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_ARUCO_ORIGINAL);
cv::aruco::detectMarkers(img, dictionary, markerCorners, markerIds, parameters, rejectedCandidates);
if ( markerIds.size() > 0 )
{
  cv::aruco::drawDetectedMarkers(img, markerCorners, markerIds);
}

此時,您會注意到我正在使用 DICT_ARUCO_ORIGINAL 系列標(biāo)記。標(biāo)記包含一個由黑色邊框包圍的 5x5 方格。

?
?
?
pYYBAGNy7QOAYTfaAAALiIPgwzk770.png
?
1 / 6 ? DICT_ARUCO_ORIGINAL - ID = 923
?

對于每個檢測到的標(biāo)記,OpenCV API 返回以下信息:

  • markerIds : 每個標(biāo)記的標(biāo)識
  • markerCorners : 每個標(biāo)記的坐標(biāo),格式如下: [0] top-left [1] top-right [2] bottom-right [3] bottom-left
pYYBAGNy7QWAPSfrAAAUQAvaWxA531.png
檢測到的標(biāo)記信息
?

下表和圖像說明了我創(chuàng)建的圖表中使用了哪些標(biāo)記。

pYYBAGNy7QeAGPX7AABL0ceJpXc987.png
ArUco 標(biāo)記用法
?

我使用 switch case 狀態(tài)掃描檢測到的標(biāo)記,并識別感興趣的標(biāo)記。

...
  if (markerIds.size() >= 4 )
  {
    int tl_id = 0;
    int tr_id = 0;
    int bl_id = 0;
    int br_id = 0;
    cv::Point2f tl_xy, tr_xy, bl_xy, br_xy;
    for ( unsigned i = 0; i < markerIds.size(); i++ )
    {
      switch ( markerIds[i] )
      {
      case 923:
        tl_id = markerIds[i];
        tl_xy = markerCorners[i][3]; // bottom left corner of top left marker
        break;
      case 1001:
      case 1002:
      case 1003:
      case 1004:
      case 1005:
      case 1006:
        tr_id = markerIds[i];
        tr_xy = markerCorners[i][2]; // bottom right corner of top right marker
        break;
      case 1007:
        bl_id = markerIds[i];
        bl_xy = markerCorners[i][0]; // top left corner of bottom left marker
        break;
      case 241:
        br_id = markerIds[i];
        br_xy = markerCorners[i][1]; // top right corner of bottom right marker
        break;
      default:
        break;
      }
    }
    ...
  }
  ...

下圖說明了我保留哪些 ID 和 X/Y 坐標(biāo)來定義感興趣區(qū)域 (ROI) 以進(jìn)行附加處理。

poYBAGNy7QqAba8GAABSJMHlrRY300.png
感興趣區(qū)域 (ROI) 規(guī)范
?

檢測特定圖表是通過以下簡單的條件語句完成的。

// Chart 1 - Checkerboard (9x7)
if ( (tl_id==923) && (tr_id==1001) && (bl_id==1007) && (br_id==241) )
{
   ...
}
// Chart 2 - White Reference
if ( (tl_id==923) && (tr_id==1002) && (bl_id==1007) && (br_id==241) )
   ...
}
{
// Chart 3 - Histogram
if ( (tl_id==923) && (tr_id==1003) && (bl_id==1007) && (br_id==241) )
{
   ...
}

將計(jì)算機(jī)生成的圖形添加到場景中

對于“Chart 1 - CheckerBoard (9x7)”,繪制了一個綠色矩形來標(biāo)識感興趣的區(qū)域。

// Extract ROI (area, ideally within 4 markers)
      std::vector<cv::Point> polygonPoints;
      polygonPoints.push_back(cv::Point(tl_xy.x,tl_xy.y));
      polygonPoints.push_back(cv::Point(tr_xy.x,tr_xy.y));
      polygonPoints.push_back(cv::Point(br_xy.x,br_xy.y));
      polygonPoints.push_back(cv::Point(bl_xy.x,bl_xy.y));
      // Draw border around "checkerboard"
      cv::polylines(img, polygonPoints, true, cv::Scalar (0, 255, 0), 2, 16);

對于“圖表 2 - 白色參考”,感興趣區(qū)域用于計(jì)算藍(lán)色 (B)、綠色 (G) 和紅色 (R) 分量中的每一個的平均值。下面的代碼使用了一個掩碼,它支持一個不是完美矩形的 ROI。

//
      // Calculate color gains
      //   ref : https://stackoverflow.com/questions/32466616/finding-the-average-color-within-a-polygon-bound-in-opencv
      //
      cv::Point pts[1][4];
      pts[0][0] = cv::Point(tl_xy.x,tl_xy.y);
      pts[0][1] = cv::Point(tr_xy.x,tr_xy.y);
      pts[0][2] = cv::Point(br_xy.x,br_xy.y);
      pts[0][3] = cv::Point(bl_xy.x,bl_xy.y);
      const cv::Point* points[1] = {pts[0]};
      int npoints = 4;
      // Create the mask with the polygon
      cv::Mat1b mask(img.rows, img.cols, uchar(0));
      cv::fillPoly(mask, points, &npoints, 1, cv::Scalar(255));
      // Calculate mean in masked area
      auto bgr_mean = cv::mean( img, mask );
      double b_mean = bgr_mean(0);
      double g_mean = bgr_mean(1);
      double r_mean = bgr_mean(2);

計(jì)算出平均值后,將創(chuàng)建一個 plotImage,其中包含一個帶有 B、G 和 R 像素平均值的條形圖圖像。

// Draw bars
int plot_w = 100, plot_h = 100;
cv::Mat plotImage( plot_h, plot_w, CV_8UC3, cv::Scalar(255,255,255) );
int b_bar = int((b_mean/256.0)*80.0);
int g_bar = int((g_mean/256.0)*80.0);
int r_bar = int((r_mean/256.0)*80.0);
// layout of bars : |<-10->|<---20-->|<-10->|<---20-->|<-10->|<---20-->|<-10->|
cv::rectangle(plotImage, cv::Rect(10,(80-b_bar),20,b_bar), cv::Scalar(255, 0, 0), cv::FILLED, cv::LINE_8);
cv::rectangle(plotImage, cv::Rect(40,(80-g_bar),20,g_bar), cv::Scalar(0, 255, 0), cv::FILLED, cv::LINE_8);
cv::rectangle(plotImage, cv::Rect(70,(80-r_bar),20,r_bar), cv::Scalar(0, 0, 255), cv::FILLED, cv::LINE_8);
std::stringstream b_str;
std::stringstream g_str;
std::stringstream r_str;
b_str << int(b_mean);
g_str << int(g_mean);
r_str << int(r_mean);
cv::putText(plotImage, b_str.str(), cv::Point(10,90), cv::FONT_HERSHEY_PLAIN, 0.75, cv::Scalar(255,0,0), 1, cv::LINE_AA);
cv::putText(plotImage, g_str.str(), cv::Point(40,90), cv::FONT_HERSHEY_PLAIN, 0.75, cv::Scalar(0,255,0), 1, cv::LINE_AA);
cv::putText(plotImage, r_str.str(), cv::Point(70,90), cv::FONT_HERSHEY_PLAIN, 0.75, cv::Scalar(0,0,255), 1, cv::LINE_AA);
poYBAGNy7QyADLBjAAAOqFvHp2s114.png
顏色平均值的示例條形圖圖像
?

最后,使用以下 OpenCV 函數(shù)將此繪圖圖像扭曲到感興趣區(qū)域:

  • findHomography :計(jì)算源坐標(biāo)和目標(biāo)坐標(biāo)之間的變換矩陣
  • warpPerspective :將源圖像扭曲到目標(biāo)坐標(biāo)

然后使用掩碼將扭曲的條形圖圖像與實(shí)時圖像組合。

// Calculate transformation matrix
std::vector<cv::Point2f> srcPoints;
std::vector<cv::Point2f> dstPoints;
srcPoints.push_back(cv::Point(       0,       0)); // top left
srcPoints.push_back(cv::Point(plot_w-1,       0)); // top right
srcPoints.push_back(cv::Point(plot_w-1,plot_h-1)); // bottom right
srcPoints.push_back(cv::Point(       0,plot_h-1)); // bottom left
dstPoints.push_back(tl_xy);
dstPoints.push_back(tr_xy);
dstPoints.push_back(br_xy);
dstPoints.push_back(bl_xy);
cv::Mat h = cv::findHomography(srcPoints,dstPoints);
// Warp plot image onto video frame
cv::Mat img_temp = img.clone();
cv::warpPerspective(plotImage, img_temp, h, img_temp.size());
cv::Point pts_dst[4];
for( int i = 0; i < 4; i++)
{
pts_dst[i] = dstPoints[i];
}
cv::fillConvexPoly(img, pts_dst, 4, cv::Scalar(0), cv::LINE_AA);
img = img + img_temp;

對于“圖表 3 - 直方圖”,使用了與“圖表 2”類似的技術(shù)。不是顯示顏色平均值的條形圖,而是顯示每個顏色分量的直方圖。

poYBAGNy7Q-AB7k-AABPYTtbqQI822.png
顏色分量的示例直方圖繪圖圖像
?

了解了所有理論之后,是時候在 Ultra96-V2 上進(jìn)行嵌入式實(shí)現(xiàn)了。

第 0 步 - 打印圖表

為了運(yùn)行此示例,您將需要三個圖表,這些圖表已在“原理圖”部分以 PDF 格式提供。

  • 圖 1 - 棋盤 (9x7)
  • 圖表 2 - 白色參考
  • 圖表 2 - 直方圖

第 1 步 - 創(chuàng)建 SD

為以下 Avnet 平臺提供了預(yù)構(gòu)建的 Vitis-AI 1.3 SD 卡映像:

  • u96v2_sbc_base : Ultra96-V2 開發(fā)板
  • uz7ev_evcc_base:UltraZed-EV SOM (7EV) + FMC 載卡
  • uz3eg_iocc_base:UltraZed-EG SOM (3EG) + IO 載卡

可在此處找到預(yù)構(gòu)建 SD 卡映像的下載鏈接:

下載并解壓后,.img 文件可以編程到 16GB 微型 SD 卡。

0.解壓壓縮包得到.img文件

1. 將開發(fā)板特定的 SD 卡映像編程到 16GB(或更大)的 micro SD 卡

一個。在 Windows 機(jī)器上,使用 Balena Etcher 或 Win32DiskImager(免費(fèi)開源軟件)

灣。linux 機(jī)器上,使用 Balena Etcher 或使用 dd 實(shí)用程序

$ sudo dd bs=4M if=Avnet-{platform}-Vitis-AI-1-3-{date}.img of=/dev/sd{X} status=progress conv=fsync

其中 {X} 是一個小寫字母,用于指定 SD 卡的設(shè)備。您可以使用“df -h”來確定您的 SD 卡對應(yīng)的設(shè)備。

第 2 步 - 克隆源代碼存儲庫

本項(xiàng)目中使用的源代碼可以從以下存儲庫中獲?。?/font>

如果您有活動的互聯(lián)網(wǎng)連接,您可以簡單地將存儲庫克隆到嵌入式平臺的根目錄:

$ cd ~
$ git clone 

第 3 步 - 編譯和安裝 gstreamer 插件

gstreamer 插件可以在 Ultra96-V2 嵌入式平臺上使用 make 命令構(gòu)建:

$ cd vitis_ai_gstreamer_plugins
$ cd markerdetect
$ make

編譯完成后,gstreamer 插件可以按如下方式安裝:

$ cp libgstmarkerdetect.so /usr/lib/gstreamer-1.0/.

可以使用 gst-inspect-1.0 實(shí)用程序驗(yàn)證 gstreamer 插件的安裝:

$ gst-inspect-1.0 | grep markerdetect
markerdetect:  markerdetect: Marker detection using the OpenCV Library

$ gst-inspect-1.0 markerdetect
Factory Details:
  Rank                     none (0)
  Long-name                Marker detection using the OpenCV Library
  Klass                    Video Filter
  Description              Marker Detection
  Author                   FIXME 

Plugin Details:
  Name                     markerdetect
  Description              Marker detection using the OpenCV Library
  Filename                 /usr/lib/gstreamer-1.0/libgstmarkerdetect.so
  Version                  0.0.0
  License                  LGPL
  Source module            markerdetect
  Binary package           OpenCV Library
  Origin URL               http://avnet.com

GObject
 +----GInitiallyUnowned
       +----GstObject
             +----GstElement
                   +----GstBaseTransform
                         +----GstVideoFilter
                               +----GstMarkerDetect

Pad Templates:
  SRC template: 'src'
    Availability: Always
    Capabilities:
      video/x-raw
                 format: { (string)BGR }
                  width: [ 1, 1920 ]
                 height: [ 1, 1080 ]
              framerate: [ 0/1, 2147483647/1 ]

  SINK template: 'sink'
    Availability: Always
    Capabilities:
      video/x-raw
                 format: { (string)BGR }
                  width: [ 1, 1920 ]
                 height: [ 1, 1080 ]
              framerate: [ 0/1, 2147483647/1 ]

Element has no clocking capabilities.
Element has no URI handling capabilities.

Pads:e--
  SINK: 'sink'
    Pad Template: 'sink'
  SRC: 'src'
    Pad Template: 'src'

Element Properties:
  name                : The name of the object
                        flags: readable, writable
                        String. Default: "markerdetect0"
  parent              : The parent of the object
                        flags: readable, writable
                        Object of type "GstObject"
  qos                 : Handle Quality-of-Service events
                        flags: readable, writable
                        Boolean. Default: true

第 4 步 - 使用實(shí)時視頻源執(zhí)行示例

為了便于啟動示例,請?jiān)谀那度胧狡脚_上創(chuàng)建以下啟動腳本 (launch_usb_markerdetect.sh):

#!/bin/sh

gst-launch-1.0  \
  v4l2src device=/dev/video0 io-mode=4 ! \
  video/x-raw, width=640, height=480, format=YUY2, framerate=30/1 ! \
  videoconvert ! \
  video/x-raw, format=BGR ! \
  queue ! markerdetect ! queue ! \
  videoconvert ! \
  fpsdisplaysink sync=false text-overlay=false fullscreen-overlay=true \
  \
  -v

在啟動示例之前,我們要定義我們的 DISPLAY 環(huán)境變量,并配置我們的 DisplayPort 顯示器的分辨率。

$ export DISPLAY=:0.0
$ xrandr --output DP-1 --mode 800x600

該示例可以使用我們剛剛創(chuàng)建的腳本啟動:

$ ./launch_usb_markerdetect.sh

我第一次使用 USB 攝像頭執(zhí)行這個“markerdetect”gstreamer 插件讓我感到驚訝。我使用的 USB 相機(jī)是具有自動白平衡功能的羅技 C720,所以我希望看到藍(lán)色、綠色和紅色的平均值大致相同。

標(biāo)記檢測 - 面向監(jiān)視器
?

事實(shí)證明,DisplayPort 監(jiān)視器正在生成一種藍(lán)色色調(diào),該色調(diào)被圖表拾取,并略微扭曲了結(jié)果。

pYYBAGNy7RGAO-pPAABttB3bYdM738.png
顏色平均值 - 面向顯示器
?

我跑了同樣的測試,這次遠(yuǎn)離顯示器,結(jié)果更符合我的預(yù)期。

標(biāo)記檢測 - 遠(yuǎn)離顯示器
?

這一次,藍(lán)色、綠色和紅色的平均值大致相同。

pYYBAGNy7ROAN2XWAABeX-vWKnA614.png
顏色平均值 - 遠(yuǎn)離顯示器
?

結(jié)論

我希望本教程能激發(fā)您在 Ultra96-V2 上嘗試增強(qiáng)現(xiàn)實(shí) (AR)。

你能想到其他應(yīng)用程序會使用這些類型的標(biāo)記嗎?

如果您還想看到任何其他相關(guān)內(nèi)容,請?jiān)谙旅娴脑u論中分享您的想法。

?


下載該資料的人也在下載 下載該資料的人還在閱讀
更多 >

評論

查看更多

下載排行

本周

  1. 1山景DSP芯片AP8248A2數(shù)據(jù)手冊
  2. 1.06 MB  |  532次下載  |  免費(fèi)
  3. 2RK3399完整板原理圖(支持平板,盒子VR)
  4. 3.28 MB  |  339次下載  |  免費(fèi)
  5. 3TC358743XBG評估板參考手冊
  6. 1.36 MB  |  330次下載  |  免費(fèi)
  7. 4DFM軟件使用教程
  8. 0.84 MB  |  295次下載  |  免費(fèi)
  9. 5元宇宙深度解析—未來的未來-風(fēng)口還是泡沫
  10. 6.40 MB  |  227次下載  |  免費(fèi)
  11. 6迪文DGUS開發(fā)指南
  12. 31.67 MB  |  194次下載  |  免費(fèi)
  13. 7元宇宙底層硬件系列報(bào)告
  14. 13.42 MB  |  182次下載  |  免費(fèi)
  15. 8FP5207XR-G1中文應(yīng)用手冊
  16. 1.09 MB  |  178次下載  |  免費(fèi)

本月

  1. 1OrCAD10.5下載OrCAD10.5中文版軟件
  2. 0.00 MB  |  234315次下載  |  免費(fèi)
  3. 2555集成電路應(yīng)用800例(新編版)
  4. 0.00 MB  |  33566次下載  |  免費(fèi)
  5. 3接口電路圖大全
  6. 未知  |  30323次下載  |  免費(fèi)
  7. 4開關(guān)電源設(shè)計(jì)實(shí)例指南
  8. 未知  |  21549次下載  |  免費(fèi)
  9. 5電氣工程師手冊免費(fèi)下載(新編第二版pdf電子書)
  10. 0.00 MB  |  15349次下載  |  免費(fèi)
  11. 6數(shù)字電路基礎(chǔ)pdf(下載)
  12. 未知  |  13750次下載  |  免費(fèi)
  13. 7電子制作實(shí)例集錦 下載
  14. 未知  |  8113次下載  |  免費(fèi)
  15. 8《LED驅(qū)動電路設(shè)計(jì)》 溫德爾著
  16. 0.00 MB  |  6656次下載  |  免費(fèi)

總榜

  1. 1matlab軟件下載入口
  2. 未知  |  935054次下載  |  免費(fèi)
  3. 2protel99se軟件下載(可英文版轉(zhuǎn)中文版)
  4. 78.1 MB  |  537798次下載  |  免費(fèi)
  5. 3MATLAB 7.1 下載 (含軟件介紹)
  6. 未知  |  420027次下載  |  免費(fèi)
  7. 4OrCAD10.5下載OrCAD10.5中文版軟件
  8. 0.00 MB  |  234315次下載  |  免費(fèi)
  9. 5Altium DXP2002下載入口
  10. 未知  |  233046次下載  |  免費(fèi)
  11. 6電路仿真軟件multisim 10.0免費(fèi)下載
  12. 340992  |  191187次下載  |  免費(fèi)
  13. 7十天學(xué)會AVR單片機(jī)與C語言視頻教程 下載
  14. 158M  |  183279次下載  |  免費(fèi)
  15. 8proe5.0野火版下載(中文版免費(fèi)下載)
  16. 未知  |  138040次下載  |  免費(fèi)