Nội dung đồ án được chia làm 4 chương, bao gồm: • Chương 1: Giới thiệu chung • Chương 2: Ứng dụng camera Orbbec đo khoảng cách • Chương 3: Thuật toán nhận diện đối tượng • Chương 4: Kết
Giới thiệu về camera Orbbec Astra Pro và AstraSDK
Camera Orbbec Astra Pro
Orbbec Astra Pro là một camera 3D mạnh mẽ và đáng tin cậy, tích hợp cảm biến VGA màu và khả năng theo dõi độ sâu tầm xa vượt trội Camera 3D này cung cấp giải pháp thị giác máy tính cho hàng loạt chức năng như nhận diện khuôn mặt, nhận diện cử chỉ, theo dõi toàn thân, đo lường ba chiều, nhận thức môi trường và tái tạo bản đồ 3D Astra Pro mang lại hiệu suất cao với đo độ sâu chính xác, chuyển màu mịn và đường viền chính xác, đồng thời lọc ra các pixel độ sâu chất lượng thấp Các phiên bản khác nhau cho phép nhà phát triển tinh chỉnh theo nhu cầu với các tùy chọn camera RGB tầm ngắn, tầm xa và độ phân giải cao.
Orbbec đã phát triển toàn bộ công nghệ lõi cho dòng máy ảnh Astra, từ thiết kế quang học tiên tiến đến thuật toán tính toán độ sâu, tích hợp ASIC tối ưu và SDK đầy đủ Sự kết hợp này cho phép Astra đạt độ chính xác đo khoảng cách cao, hiệu suất xử lý nhanh và độ ổn định vượt trội trong các ứng dụng AI, robot và thực tế ảo Với SDK phong phú và dễ tích hợp, các nhà phát triển có thể triển khai nhanh chóng, tùy biến và mở rộng các giải pháp máy ảnh Astra, giúp tối ưu chi phí và gia tăng giá trị cho doanh nghiệp.
Sản phẩm được thiết kế để thích ứng với nhu cầu của các nhà cung cấp đa dạng và đáp ứng nhiều kịch bản ứng dụng khác nhau Với khả năng linh hoạt và mở rộng, nó có thể được sử dụng rộng rãi trong truyền hình, thiết bị di động, robot, VR/AR và nhiều lĩnh vực khác.
Hình 1.3 Camera Orbbec Astra Pro
Camera Orbbec Astra Pro sử dụng công nghệ Structured light, chiếu sáng lên vật thể bằng một pattern tia sáng dạng lưới hoặc đường kẻ Nhờ các hình ảnh thu được từ quá trình chiếu sáng và nhận diện pattern, hệ thống có thể tính toán được các thông tin bề mặt như kích thước vật thể và khoảng cách từ camera đến vật thể.
AstraSDK
AstraSDK là bộ công cụ phần mềm do Orbbec cung cấp cho các nhà phát triển, bao gồm các công cụ, thư viện và tài liệu cần thiết để làm việc với camera Astra Nó cho phép tích hợp camera Astra vào các ứng dụng và dự án một cách dễ dàng, đồng thời tận dụng thông tin về độ sâu và màu RGB mà camera cung cấp để phát triển các tính năng xử lý hình ảnh và thị giác máy tính.
AstraSDK cung cấp các tính năng đo độ sâu, theo dõi khung xương và theo dõi tay, cho phép nhà phát triển truy cập và xử lý dữ liệu 3D từ camera một cách dễ dàng Với API của AstraSDK, bạn có thể tích hợp các chức năng này vào ứng dụng để đo khoảng cách, nhận diện cấu trúc xương và thao tác bằng bàn tay, từ đó xây dựng các giải pháp tương tác và phân tích chuyển động người dựa trên dữ liệu 3D.
Các bước để cài đặt AstraSDK như sau:
• Bước 1: Truy cập vào trang web: https://www.orbbec.com/developers/astra-sdk/
• Bước 2: Tải xuống thư mục AstraSDK đính kèm (tìm chọn trong Platforms nền tảng và môi trường lập trình mà bạn sử dụng)
• Bước 3: Nếu sử dụng nền tảng Windows, cần phải cài đặt Camera Driver dành cho Windows.
• Bước 4: Kết nối camera vào máy tính và chạy thử các file trong folder samples(hoặc các file exe trong folder bin) để kiểm tra kết nối.
Môi trường lập trình
Trong đề tài này sẽ sử dụng ngôn ngữ lập trình C# trong môi trường lập trình Visual Studio 2022.
Microsoft Visual Studio is an integrated development environment (IDE) from Microsoft that primarily supports C++ and C# development It enables developers to build Windows desktop applications as well as websites, web applications, and web services, all within a single, extensible platform Visual Studio leverages Microsoft's software development technologies, including Windows API, Windows Forms, Windows Presentation Foundation (WPF), Windows Store, and Microsoft Silverlight, to support a wide range of development scenarios.
Visual Studio hỗ trợ nhiều ngôn ngữ lập trình khác nhau và đi kèm với trình biên dịch và công cụ gỡ lỗi cho hầu như mọi ngôn ngữ được dùng trong phát triển ứng dụng Các ngôn ngữ tích hợp bao gồm C, C++ và C++/CLI (thông qua Visual C++), VB.NET (thông qua Visual Basic.NET), C# (thông qua Visual C#) và F# từ Visual Studio 2010 Ngoài ra, nó có thể mở rộng cho các ngôn ngữ khác như J++/J#, Python và Ruby thông qua các dịch vụ/tiện ích cài đặt riêng Visual Studio cũng hỗ trợ XML/XSLT, HTML/XHTML, JavaScript và CSS.
Microsoft provides free editions of Visual Studio The Express edition is available for Visual Studio 2013 and earlier, while the Community edition is available for Visual Studio 2015 and later.
ỨNG DỤNG CAMERA ORBBEC ĐO KHOẢNG CÁCH 4
Giao diện WPF
2.4.1 Giới thiệu về giao diện WPF trên Visual Studio Đề tài này sử dụng giao diện WPF trên Visual Studio WPF là một hệ thống đồ họa để hiển thị giao diện người dùng trong các ứng dụng dựa trên Windows Nó là một phần của framework NET và là một công nghệ quan trọng của Microsoft, thường được sử dụng cùng với Visual Studio để xây dựng các ứng dụng desktop đa dạng. WPF sử dụng 2 thư viện lõi là PresentationCore và PresentationFramework để xử lý các điều hướng, data binding, sự kiện và quản lý giao diện WPF dựa trên nền tảng đồ họa là DirectX, xử lý vector, hỗ trợ gam màu rộng, cho phép tùy biến giá trị opacity hay tạo gradient một cách dễ dàng Thư viện thực thi của WPF tự động tính toán và tận dụng tài nguyên của hệ thống một cách tối ưu để giảm tải cho CPU. Các khía cạnh quan trọng của WPF:
• User Interface (UI) Framework: WPF cung cấp một framework để tạo giao diện người dùng đa dạng và tương tác trong các ứng dụng Windows.
XAML (eXtensible Application Markup Language) là ngôn ngữ markup được WPF sử dụng để định nghĩa cấu trúc và giao diện người dùng XAML giúp tách biệt định nghĩa UI khỏi mã nguồn, từ đó dễ dàng thiết kế và bảo trì giao diện trong các ứng dụng WPF.
Trong WPF, Data Binding cho phép liên kết dữ liệu mạnh mẽ giữa nguồn dữ liệu và các thành phần UI, giúp các yếu tố giao diện tự động liên kết và đồng bộ với dữ liệu, và khi dữ liệu thay đổi, UI được cập nhật tự động mà không cần viết mã cập nhật thủ công.
• Tích hợp Đồ họa và Đa phương tiện: WPF hỗ trợ những tính năng đồ họa tiên tiến, bao gồm đồ họa vector, animations và đa phương tiện.
Trong WPF, MVVM (Model-View-ViewModel) là mô hình thiết kế phổ biến được sử dụng để phân tách rõ ràng các trách nhiệm giữa Model (dữ liệu), View (giao diện) và ViewModel (logic trình bày) Nhờ sự phân tách này, ứng dụng trở nên dễ bảo trì, dễ kiểm thử và dễ mở rộng khi phát triển phần mềm.
2.4.2 Giao diện WPF kết nối và hiển thị dữ liệu từ camera Orbbec Astra Pro ỞMainWindow, người dùng sẽ chọn chế độ hiển thị bao gồm:
• With color: Hiển thị hình ảnh màu RGB.
• With bodyTracking: Hiển thị hình ảnh theo dõi khung xương.
• With objectDetection: Nhận diện vật thể.
Khi có nhiều thiết bị kết nối với máy tính, tiến hành lựa chọn cảm biến được sử dụng cho hệ thống Nếu chỉ có một thiết bị được kết nối, cảm biến được chọn sẽ là sensor #0.
Sau khi lựa chọn sensor, cửa sổSensorWindowsẽ được hiển thị SensorWindow bao gồm 2 khung hình làDEPTHvàCOLOR.
• Mode: chế độ hiển thị của camera, với camera Orbbec Astra Pro ở chế độ hiển thị độ sâu, Mode = 640x480 at 30 FPS.
• Field of View: Trường nhìn.
• Depth value: Giá trị khoảng cách từ camera đến một điểm xác định trong khung hình.
• Registration: Lựa chọn chế độ Depth registration, đảm bảo hình ảnh độ sâu đồng nhất với hình ảnh màu do camera thu được.
Để đảm bảo hình ảnh hiển thị đúng thực tế, ta lật (mirror) ảnh nếu nó bị ngược với thực tế Ảnh độ sâu được hiển thị ở dạng grayscale (Greyscale Image) dưới dạng bitmap uint8, có kích thước 640x480, mỗi pixel tương ứng với giá trị khoảng cách từ camera đến vật thể trong khung hình; giá trị gần thì màu đậm, còn giá trị xa thì màu nhạt hơn Trong khung hình COLOR có các thành phần dữ liệu màu bổ sung để kết nối thông tin độ sâu với màu sắc, phục vụ cho việc phân tích và nhận diện đối tượng trong không gian.
• Mode: chế độ hiển thị của camera, với camera Orbbec Astra Pro ở chế độ hiển thị độ sâu, Mode = 640x480 at 30 FPS.
• Field of View: Trường nhìn.
Trong xử lý ảnh, khi hình hiển thị bị đảo ngược so với thực tế, ta thực hiện lật ảnh để đảm bảo hướng đúng Ảnh màu thu được từ camera ở định dạng BGR cần được chuyển sang RGB trước khi hiển thị để màu sắc thể hiện chuẩn trên màn hình.
Ngoài ra, khung PFS biểu diễn giá trị PFS trên thực tế Giá trị này được cập nhật mỗi khi nhận được khung hình mới từ camera.
Xử lý dữ liệu nhận được từ camera
Để nhận dữ liệu từ camera và hiển thị kết quả trên cửa sổ UI, một parent class
BufferOfT được sử dụng Parent class này có hai child class là ColorBuffer và
DepthBuffer Hai class này lần lượt xử lý dữ liệu về ảnh màu và ảnh độ sâu.
2.5.1 Nhận dữ liệu và hiển thị kết quả
BufferOfT là một class dùng để nhận dữ liệu gửi về từ camera, tạo ra các abstract method để xử lý dữ liệu và hiển thị.
Hình 2.9 thể hiện flowchart của class này.
Hình 2.9 Flowchart của class BufferOfT
2.5.2 Xử lý dữ liệu ảnh màu
ColorBufferlà child class củaBufferOfTdùng để xử lý dữ liệu về ảnh màu thu được từ camera.
Hình 2.10 Flowchart của class ColorBuffer
Hình 2.10 mô tả flowchart của lớp xử lý ảnh, trong đó dữ liệu thu được từ camera được lưu vào một ma trận ở lớp cha và được kế thừa bởi lớp con để xử lý Dữ liệu màu từ ma trận này ở định dạng BGR được chuyển đổi sang RGB bằng cách sử dụng con trỏ trỏ tới từng nhóm 3 byte; ba byte này tương ứng với các kênh màu Blue, Green và Red của ảnh ở định dạng BGR Bằng cách lấy lại vị trí của các byte theo các chỉ số 2, 1 và 0 lần lượt cho từng nhóm byte, ta có thể chuyển từ ảnh BGR sang RGB và làm tương tự với nhóm 3 byte tiếp theo.
2.5.3 Xử lý dữ liệu độ sâu
DepthBufferlà child class củaBufferOfT dùng để xử lý dữ liệu về độ sâu thu được từ camera.
Hình 2.11 mô tả flowchart của lớp này, cho thấy dữ liệu từ lớp cha được kế thừa sang lớp con và được xử lý để hiển thị dưới dạng ảnh grayscale Quy trình dùng con trỏ trỏ tới lần lượt 3 byte trong ma trận, lấy trị tuyệt đối của giá trị trong từng byte nhân với 255 để tính các giá trị màu sắc grayscale tương ứng Ảnh độ sâu và giá trị cụ thể của một tọa độ được hiển thị trên giao diện người dùng (UI).
Hình 2.11 Flowchart của class DepthBuffer
Kết quả
Kết quả khi chạy chương trình được thể hiện trong hình 2.12
Trong hình 2.12 khi chạy chương trình, cửa sổ SensorWindow hiển thị hai khung hình DEPTH và COLOR từ camera, cho thấy ảnh độ sâu và ảnh màu được ghi nhận Chấm đỏ trên cả hai màn hình thể hiện tọa độ của điểm đo độ sâu và hiển thị trên thanh Depth Value Giá trị FPS đạt 27.6, thấp hơn mức định mức 30 do độ phức tạp của thuật toán xử lý dữ liệu khi chạy chương trình; tuy nhiên sự khác biệt này không ảnh hưởng đáng kể đến hiệu suất tổng thể.
THUẬT TOÁN NHẬN DIỆN ĐỐI TƯỢNG 11
Thuật toán và công cụ
Trong những năm gần đây, nhận diện đối tượng thời gian thực đang được phát triển mạnh trong nhiều ứng dụng như theo dõi đa đối tượng, xe tự hành, robot và phân tích hình ảnh y tế Các mô hình mới như YOLOX và YOLOR tập trung vào cải thiện tốc độ xử lý trên nhiều loại CPU, trong khi YOLOv7 chú trọng tối ưu hóa cấu trúc mạng và quá trình huấn luyện dữ liệu Thuật toán YOLO nổi tiếng với khả năng nhận diện đối tượng thời gian thực, cho phép đồng thời phát hiện nhiều đối tượng trong một ảnh hoặc khung video Phiên bản đầu tiên của YOLO được Redmon và cộng sự giới thiệu vào năm 2016, biến bài toán nhận diện thành một bài toán hồi quy từ các điểm ảnh đến hộp giới hạn và xác suất lớp, tức là chỉ cần nhìn một lần (You Only Look Once) để dự đoán những đối tượng và vị trí của chúng.
YOLOv7 là một mô hình nhận diện đối tượng thời gian thực hiện đại, nổi bật về cả tốc độ lẫn độ chính xác với phạm vi xử lý từ 5 FPS đến 160 FPS Mô hình được huấn luyện trên tập dữ liệu Microsoft COCO có sẵn và không cần dùng bất kỳ bộ dữ liệu khác hoặc trọng số được huấn luyện trước nào, theo tài liệu tham khảo [3].
COCO là tập dữ liệu quy mô lớn chuyên về nhận diện, phân loại và đánh nhãn đối tượng, được thiết kế để thúc đẩy nghiên cứu trên nhiều loại đối tượng khác nhau và thường dùng để đánh giá độ tin cậy của các mô hình thị giác máy tính Đây là nguồn tài nguyên thiết yếu cho các nhà nghiên cứu và nhà phát triển làm việc với các nhiệm vụ phát hiện đối tượng.
Với tổng cộng 2.5 triệu đối tượng được đánh nhãn trong 328 nghìn bức ảnh, COCO names file cung cấp dữ liệu để nhận diện 80 đối tượng trong thực tế [5].
3.3.3 Thư viện OpenCV (Open Source Computer Vision Library)
OpenCV là thư viện thị giác máy tính lớn nhất hiện nay, với hơn 2500 thuật toán. OpenCV được ra mắt lần đầu bởi Intel vào tháng 6 năm 2000.
OpenCV được viết bằng ngôn ngữ lập trình C++, và tất cả các phát triển và thuật toán mới đều xuất hiện trong giao diện C++ Bên cạnh đó, OpenCV còn có các liên kết ngôn ngữ tới Python, Java và MATLAB/Octave, giúp người dùng tích hợp và triển khai dễ dàng trên nhiều nền tảng.
Ứng dụng thuật toán nhận diện đối tượng
Hình 3.3 là flowchart quá trình xử lý và hiển thị kết quả nhận diện đối tượng qua camera.
Trong quá trình nhận diện đối tượng, hệ thống tải và đọc dữ liệu huấn luyện từ file weights và file cấu hình (cfg) của YOLOv7, cùng với file nhãn COCO, vào mạng neural của chương trình Đây chính là nền tảng để thực hiện nhận diện và gán nhãn cho các đối tượng một cách chính xác và hiệu quả.
Vòng lặpwhileđược lặp lại liên tục do camera liên tục gửi các frame về Do đó, kết quả hiển thị được cập nhật liên tục theo thời gian thực.
Hình 3.3 Flowchart nhận diện đối tượng
Hình 3.4 biểu diễn kết quả ứng dụng thuật toán YOLOv7 trong nhận diện đối tượng.
Hình 3.4 Flowchart nhận diện đối tượng
Kết quả hiển thị các đối tượng được nhận diện và gắn nhãn theo thời gian thực, kèm theo độ tin cậy của thuật toán được thể hiện dưới dạng phần trăm Trong chương trình này, mỗi đối tượng chỉ được nhận diện và gắn nhãn khi độ tin cậy vượt ngưỡng 80%, giúp người dùng đánh giá nhanh chất lượng nhận diện và quan sát trạng thái hiển thị một cách trực quan.
Trong quá trình thực hiện đề tài, em đã kết nối và thu thập dữ liệu từ camera Orbbec Astra Pro và thực hiện nhận diện đối tượng bằng thuật toán YOLOv7, nhưng vẫn gặp phải một số khó khăn nhất định Một trong những thách thức lớn là ngôn ngữ lập trình C# không được hãng sản xuất Orbbec Camera hỗ trợ về thư viện, gây ra các vấn đề trong việc thu thập và xử lý dữ liệu từ driver của camera và đặc biệt là gặp khó khăn khi tích hợp nhận diện đối tượng vào chương trình thu thập giá trị độ sâu để đo khoảng cách từ camera đến một đối tượng xác định Đến thời điểm hiện tại, mặc dù nhận được sự giúp đỡ nhiệt tình từ giảng viên hướng dẫn, em vẫn chưa thể hoàn thành mục tiêu cuối cùng của đề tài này.
[1] Z Ge, S Liu, F Wang, Z Li, and J Sun, “Yolox: Exceeding yolo series in 2021,” arXiv preprint arXiv:2107.08430, 2021.
[2] C.-Y Wang, I.-H Yeh, and H.-Y M Liao, “You only learn one representation: Unified network for multiple tasks,”arXiv preprint arXiv:2105.04206, 2021.
[3] C.-Y Wang, A Bochkovskiy, and H.-Y M Liao, “YOLOv7: Trainable bag-of- freebies sets new state-of-the-art for real-time object detectors,” arXiv preprint arXiv:2207.02696, 2022.
[4] J Redmon, S Divvala, R Girshick, and A Farhadi, “You only look once: Unified, real-time object detection,” in Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition (CVPR), June 2016.
[5] T.-Y Lin, M Maire, S Belongie, J Hays, P Perona, D Ramanan, P Dollár, and C L Zitnick, “Microsoft coco: Common objects in context,” in Computer Vision–ECCV 2014: 13th European Conference, Zurich, Switzerland, September 6-12, 2014, Proceedings, Part V 13 Springer, 2014, pp 740–755.
[6] (2020) Opencv Accessed on Date [Online] Available: https://en.wikipedia.org/ wiki/OpenCV
3.5 Code chương trình thu thập và hiển thị ảnh màu và ảnh độ sâu từ Camera Orbbec Astra Pro
3.5.1 Class BufferOfT using System; using System.Threading; using System.Threading.Tasks; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Threading; namespace AstraTestWpf
/// Base class for helper buffers that allow to get and show depth and color frames
/// Type of frame element.
/// This class works in two steps:
/// 1 Data is copied from Astra.ImageFrame to internal buffer (array of bytes)
/// This operation is performed from background thread as a rule during processing of received frame from Astra SDK
/// 2 After that in UI thread WritableBitmap is updated based on data in internal intermediate buffer
/// This image is available as property ImageSource and can be used in UI
/// public abstract class Buffer where T : struct
/// Constructs object Call from UI thread because during construction ImageSource is being created
/// Dispatcher of owner thread As a rule, UI thread.
/// Width of frame in pixels.
/// Height of frame in pixels.
/// Pixel format of frame.
/// Byte count per one pixel. protected Buffer(Dispatcher dispatcher, int width, int height, Astra.PixelFormat pixelFormat, int bytesPerPixel)
{ if (dispatcher.Thread != Thread.CurrentThread)
"Call this constructor from UI thread please, because it creates ImageSource object for UI"); }
17 this.dispatcher = dispatcher; this.width = width; this.height = height; this.pixelFormat = pixelFormat; innerBuffer = new byte[width * height * bytesPerPixel]; writeableBitmap = new WriteableBitmap(width, height, 96, 96, PixelFormats.Bgr24, null);
/// Image with visualized frame You can use this property in WPF controls/windows
/// public BitmapSource ImageSource => writeableBitmap;
//When an object is created from this class, you can call object.ImageSource and it will return value of writableBitmap
/// Updates ImageSource based on Astra.ImageFrame, received from Astra sensor ///
Update is a method that takes a frame from an Astra sensor (Astra.ImageFrame), which can be null, and tries to update the internal state using that frame It returns true when the update succeeds; it returns false when the frame is not compatible or is an old frame that cannot be used for updating.
// Is compatible? if (frame == null
|| frame.Width != width || frame.Height != height
// Is new frame? var frameIndex = Interlocked.Exchange(ref lastFrameIndex, frame.FrameIndex); if (frameIndex == frame.FrameIndex)
// 1st step: new frame => update
FillInnerBuffer(frame.DataPtr, frame.ByteLength); depthValue = GetDepthAt(x_off+320, y_off+240);
// 2nd step: we can update WritableBitmap only from its owner thread (as a rule, UI thread) dispatcher.BeginInvoke(DispatcherPriority.Render, new Action(FillWritableBitmap));
18 private unsafe void FillInnerBuffer(IntPtr srcPtr, long byteLength)
// This method can be called from some background thread, thus use synchronization lock (innerBuffer)
Buffer.MemoryCopy((void*)srcPtr, dstPtr, innerBuffer.Length, byteLength);
/// thực hiện song song method FillWritableBitmapLine cho các hàng từ 0 -> height private void FillWritableBitmap()
{ var backBuffer = writeableBitmap.BackBuffer; var backBufferStride = writeableBitmap.BackBufferStride;
// This method works in UI thread, and uses innerBuffer
// that is filled in Update() method from some background thread lock (innerBuffer)
// We use parallelism here to speed up
Parallel.For(0, height, y => FillWritableBitmapLine(y, backBuffer, backBufferStride)); //thực hiện song song method FillWritableBitmapLine cho các hàng từ 0 -> height }
// Inform UI infrastructure that we have updated content of image writeableBitmap.AddDirtyRect(new System.Windows.Int32Rect(0, 0, width, height));
This C# abstract component defines the core interface for bitmap processing, requiring implementations to fill a line of a writable bitmap via FillWritableBitmapLine(int y, IntPtr backBuffer, int backBufferStride) and to retrieve the depth value at specific coordinates with GetDepthAt(int x, int y) It exposes read-only properties DepthValue, X_off, and Y_off that map to the internal fields depthValue, x_off, and y_off, respectively, providing quick access to depth and offset information The class also maintains protected readonly infrastructure, including a Dispatcher for threading context and a width representing the bitmap’s dimension, ensuring coordinated rendering and accurate coordinate handling. -**Support Pollinations.AI:**🌸 **Ad** 🌸 Streamline your C# bitmap processing with Pollinations.AI’s smart APIs—[Support our mission](https://pollinations.ai/redirect/kofi) for seamless integration and better code!
This component defines several key properties for image processing and rendering: protected readonly int height, protected readonly Astra.PixelFormat pixelFormat, protected readonly byte[] innerBuffer, and protected readonly WriteableBitmap writeableBitmap, which establish the essential data and format for a frame It also maintains a long lastFrameIndex initialized to long.MinValue to track frame progression, along with a depthValue to convey depth information, and public offsets x_off and y_off initialized to 0 to control rendering position Together these members enable efficient frame handling, pixel format management, and precise placement in a rendering pipeline.
3.5.2 Class ColorBuffer using System; using System.Windows.Media.Imaging; using System.Windows.Threading; namespace AstraTestWpf
/// Helper buffer for color data For details see description of base class.
//internal sealed class ColorBuffer : Buffer public class ColorBuffer : Buffer
{ public static readonly Astra.PixelFormat PixelFormat = Astra.PixelFormat.RGB888; public static readonly int BytesPerPixel = 3;
/// Constructs object Call from UI thread because during construction ImageSource is being created
/// Dispatcher of owner thread As a rule, UI thread.
/// Width of color frame in pixels.
/// Height of color frame in pixels. public ColorBuffer(Dispatcher dispatcher, int width, int height)
: base(dispatcher, width, height, PixelFormat, BytesPerPixel)
{ } public override float GetDepthAt(int x, int y)
} protected override unsafe void FillWritableBitmapLine(int y, IntPtr backBuffer, int backBufferStride) { byte* dstPtr = (byte*)backBuffer + y * backBufferStride; fixed (byte* innerBufferPtr = innerBuffer)
// reverse order to convert from RGB to BGR
3.5.3 Class DepthBuffer using System; using System.Windows.Media.Imaging; using System.Windows; using System.Windows.Threading; using Emgu.CV; namespace AstraTestWpf
/// Helper buffer for depth data For details see description of base class
/// public class DepthBuffer : Buffer
{ public static readonly Astra.PixelFormat PixelFormat = Astra.PixelFormat.DepthMM; public static readonly int BytesPerPixel = sizeof(short);
/// Constructs object Call from UI thread because during construction ImageSource is being created
/// Dispatcher of owner thread As a rule, UI thread.
/// Width of depth map in pixels.
/// Height of depth map in pixels. public DepthBuffer(Dispatcher dispatcher, int width, int height)
: base(dispatcher, width, height, PixelFormat, BytesPerPixel)
This class inherits from the base Buffer constructor, which accepts a Dispatcher, the bitmap width and height, Astra.PixelFormat, and bytesPerPixel, setting up the drawing context for the writable bitmap It then overrides the unsafe method FillWritableBitmapLine to render a single scanline of the bitmap Inside this method, the code computes the starting address of the line by casting backBuffer to a byte pointer and adding y * backBufferStride, specifically dstPtr = (byte*)backBuffer + y * backBufferStride This pointer arithmetic enables efficient per-line writes to the back buffer, ensuring correct pixel placement for each y coordinate.
//declares a pointer dstPtr to a byte and initializes it to point to the memory location in the back buffer //corresponding to the specified vertical position y and stride backBufferStride
{ short* srcPtr = (short*)innerBufferPtr + y * width; for (var x = 0; x < width; x++)
//some random heuristic to colorize depth map slightly like height-based colorization of earth maps
//(from blue though green to red)
*(dstPtr++) = (byte)(Math.Max(0, (Math.Abs(v)) * 255));
*(dstPtr++) = (byte)(Math.Max(0, (Math.Abs(v)) * 255));
*(dstPtr++) = (byte)(Math.Max(0, (Math.Abs(v)) * 255));
} internal unsafe short GetNativeDepthAt(int x, int y)
{ short* srcPtr = (short*)innerBufferPtr + (y * width) + x; return *srcPtr;
// Returns depth in millimeters at coordinate public override float GetDepthAt(int x, int y)
{ short depth = GetNativeDepthAt(x, y); return ((float)depth);
Code chương trình nhận diện ảnh sử dụng thuật toán YOLOv7
using Emgu.CV; using Emgu.CV.Structure; using Emgu.CV.Util; using Emgu.CV.Dnn; using Emgu.CV.OCR; using System.Text.RegularExpressions; namespace ObjectDetection
{ public partial class Camera : Form
} private void Camera_Load(object sender, EventArgs e)
_streaming = false; videoCapture = new VideoCapture();
} private void detecting(object sender, EventArgs e)
//Read the model file var net = Emgu.CV.Dnn.DnnInvoke.ReadNetFromDarknet("D:\\0 Study\\WSR Lab\\Orbbec
Cam\\Code\\ObjectDetection_yolov7\\detection\\yolov7.cfg",
"D:\\0 Study\\WSR Lab\\Orbbec Cam\\Code\\ObjectDetection_yolov7\\detection\\yolov7.weights"); var classLabels = File.ReadAllLines("D:\\0 Study\\WSR Lab\\Orbbec
Cam\\Code\\ObjectDetection\\ObjectDetection\\detection\\coco.names"); net.SetPreferableBackend(Emgu.CV.Dnn.Backend.OpenCV); net.SetPreferableTarget(Emgu.CV.Dnn.Target.Cpu);
VectorOfInt indices = new VectorOfInt(); while (true)
In this computer vision pipeline, the frame is resized by a scale factor of 0.4, and vectors for bounding boxes, class indices, and confidence scores are initialized to store the detection results The frame is then converted to a BGR image, a neural network blob is created from the image with a 1/255.0 normalization and the color channels swapped (swapRB: true) to match the network’s input format, and this blob is set as the input to the neural network for processing.
23 net.Forward(output, net.UnconnectedOutLayersNames); for (int i = 0; i < output.Size; i++)
{ var mat = output[i]; var data = (float[,])mat.GetData(); for (int j = 0; j < data.GetLength(0); j++)
{ float[] row = Enumerable.Range(0, data.GetLength(1))
ToArray(); var rowScore = row.Skip(5).ToArray(); var classId = rowScore.ToList().IndexOf(rowScore.Max()); var confidence = rowScore[classId]; if (confidence > 0.8f)
Converting detections to pixel coordinates, the algorithm multiplies the normalized center coordinates (row[0], row[1]) by the frame’s width and height to obtain centerX and centerY, and scales the bounding box dimensions (row[2]) by the frame’s width and height to produce boxWidth and boxHeight It then computes the top-left corner (x, y) by subtracting half the width and height from the center coordinates The resulting bounding box is constructed as a Rectangle with (x, y, boxWidth, boxHeight) and added to the boxes collection, while the corresponding class identifier and confidence score are stored in the indices and scores collections respectively.
//Output var bestIndex = DnnInvoke.NMSBoxes(boxes.ToArray(), scores.ToArray(), 8f, 8f);
Image frameOut = frame.ToImage(); for (int i = 0; i < bestIndex.Length; i++)
{ int index = bestIndex[i]; var box = boxes[index]; float confidence = scores[index]; string confidenceText = $"{confidence:P}"; // Format confidence as percentage
CvInvoke.Rectangle(frameOut, box, new MCvScalar(0, 255, 0), 2);
CvInvoke.PutText(frameOut, classLabels[indices[index]], new System.Drawing.Point(box.X, box.Y -
Emgu.CV.CvEnum.FontFace.HersheyPlain, 0.75, new MCvScalar(0, 0, 255), 1);
CvInvoke.PutText(frameOut, confidenceText, new System.Drawing.Point(box.X, box.Y - 10), Emgu.CV.CvEnum.FontFace.HersheyPlain, 0.75, new MCvScalar(0, 0, 255), 1);
CvInvoke.Resize(frameOut, frameOut, new System.Drawing.Size(0, 0), 4, 4);
//var bmp = frameOut.ToBitmap(); picture.Image = frameOut; if (CvInvoke.WaitKey(1) == 27)
} private void btnStream_Click(object sender, EventArgs e)
Application.Idle += detecting; btnStream.Text = "Stop"; btnStream.ForeColor = Color.White; btnStream.BackColor = Color.Red;
Application.Idle -= detecting; btnStream.Text = "Start"; btnStream.ForeColor = Color.Black; btnStream.BackColor = Color.Gainsboro;
} private void btnQuit_Click(object sender, EventArgs e)
} private void picture_Click(object sender, EventArgs e)