Học AI & Lập trình

C# cho Vision: xử lý ảnh với OpenCvSharp

Dùng OpenCV trong C# và .NET để viết phần mềm trạm kiểm tra: cài đặt, đếm vật thể, đọc camera và quy tắc quản lý bộ nhớ Mat.

C# cho Vision: xử lý ảnh với OpenCvSharp
Nội dung bài viết
  1. OpenCvSharp là gì?
  2. Tạo dự án và cài đặt
  3. Đếm vật thể: từ Python sang C#
  4. Quản lý bộ nhớ: điều quan trọng nhất với Mat trong C#
  5. Đọc camera trong vòng lặp
  6. Python hay C#?
  7. Bài tập

Trong nhà máy, rất nhiều phần mềm điều khiển trạm kiểm tra được viết bằng C# và .NET: giao diện WinForms/WPF quen thuộc, dễ kết nối PLC, cơ sở dữ liệu và SDK camera công nghiệp (đa số hãng camera đều có SDK .NET). Tin vui là bạn vẫn dùng được toàn bộ sức mạnh của OpenCV trong C# nhờ thư viện OpenCvSharp.

OpenCvSharp là gì?

OpenCvSharp là lớp bọc (wrapper) .NET cho OpenCV, giữ tên hàm gần giống bản C++: Cv2.Threshold, Cv2.FindContours, Mat… Nên mọi tài liệu và kinh nghiệm OpenCV bằng Python/C++ đều chuyển sang C# rất dễ.

Tạo dự án và cài đặt

dotnet new console -n VisionDemo
cd VisionDemo
dotnet add package OpenCvSharp4
dotnet add package OpenCvSharp4.runtime.win

Gói OpenCvSharp4 chỉ chứa phần managed; bạn cần thêm gói runtime chứa thư viện native cho hệ điều hành (ví dụ runtime.win cho Windows). Khi làm giao diện WinForms/WPF, cài thêm OpenCvSharp4.Extensions (chuyển Mat sang Bitmap) hoặc OpenCvSharp4.WpfExtensions.

Đếm vật thể: từ Python sang C#

Đây là chuỗi xử lý "làm mờ → Otsu → contour" trong bài phân ngưỡng và contour, viết lại bằng C#:

using OpenCvSharp;

using var src = Cv2.ImRead("khay-oc-vit.png", ImreadModes.Color);
if (src.Empty()) throw new Exception("Không đọc được ảnh");

using var gray = new Mat();
using var blur = new Mat();
using var bin = new Mat();
Cv2.CvtColor(src, gray, ColorConversionCodes.BGR2GRAY);
Cv2.GaussianBlur(gray, blur, new Size(5, 5), 0);
double t = Cv2.Threshold(blur, bin, 0, 255, ThresholdTypes.Binary | ThresholdTypes.Otsu);

Cv2.FindContours(bin, out Point[][] contours, out HierarchyIndex[] _,
    RetrievalModes.External, ContourApproximationModes.ApproxSimple);

int count = 0;
foreach (var c in contours)
{
    double area = Cv2.ContourArea(c);
    if (area < 200) continue;                  // bỏ nhiễu
    count++;
    Rect r = Cv2.BoundingRect(c);
    Cv2.Rectangle(src, r, Scalar.LimeGreen, 2);
}

Cv2.PutText(src, $"Count: {count}", new Point(10, 30),
    HersheyFonts.HersheySimplex, 1.0, Scalar.Red, 2);
Cv2.ImWrite("ket-qua.png", src);
Console.WriteLine($"Ngưỡng Otsu = {t}, số vật = {count}");

Quản lý bộ nhớ: điều quan trọng nhất với Mat trong C#

Mat giữ bộ nhớ native (ngoài vùng quản lý của .NET). Garbage Collector không biết một Mat 5 megapixel "nặng" thế nào, nên trong vòng lặp camera chạy liên tục, quên giải phóng sẽ làm RAM tăng dần đến khi chương trình sập. Quy tắc:

  • Luôn dùng using var hoặc gọi Dispose() cho mọi Mat tạo ra.
  • Trong vòng lặp, tái sử dụng các Mat tạm thay vì tạo mới mỗi khung hình.
  • Kiểm tra bằng Task Manager: bộ nhớ phải đi ngang khi chạy vài giờ.

Đọc camera trong vòng lặp

using var cap = new VideoCapture(0);
using var frame = new Mat();
using var gray = new Mat();

while (true)
{
    if (!cap.Read(frame) || frame.Empty()) break;
    Cv2.CvtColor(frame, gray, ColorConversionCodes.BGR2GRAY);
    Cv2.ImShow("Camera", gray);
    if (Cv2.WaitKey(1) == 'q') break;
}

Với camera công nghiệp, bạn lấy buffer ảnh từ SDK của hãng rồi tạo Mat từ con trỏ dữ liệu, tránh copy không cần thiết.

Python hay C#?

PythonC#
Thử nghiệm thuật toán, AIRất mạnh (Jupyter, PyTorch)Hạn chế hơn
Giao diện vận hành trên máy công nghiệpLàm được nhưng ít phổ biếnRất mạnh (WinForms, WPF)
Kết nối PLC, SDK camera, databaseCó thư việnHệ sinh thái .NET rất đầy đủ
Chạy mô hình AITrực tiếpQua ONNX Runtime / OpenCV DNN

Cách làm phổ biến của nhiều kỹ sư: nghiên cứu và huấn luyện bằng Python, xuất mô hình ONNX, triển khai trong ứng dụng C#. Biết cả hai ngôn ngữ là lợi thế lớn khi ứng tuyển vị trí Vision Engineer.

Bài tập

  1. Viết lại chương trình đếm vật bằng C#, in ra diện tích từng vật.
  2. Tạo ứng dụng WinForms có nút "Chụp", hiển thị ảnh camera trong PictureBox và kết quả OK/NG.
  3. Chạy vòng lặp camera 30 phút và theo dõi bộ nhớ để chắc chắn không rò rỉ.
Ban biên tập HọcFree

Chúng tôi viết những bài hướng dẫn dễ hiểu, thực tế để ai cũng có thể tự học lập trình và ngoại ngữ, hoàn toàn miễn phí.