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.
Nội dung bài viết
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 varhoặc gọiDispose()cho mọiMattạo ra. - Trong vòng lặp, tái sử dụng các
Mattạ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#?
| Python | C# | |
|---|---|---|
| Thử nghiệm thuật toán, AI | Rất mạnh (Jupyter, PyTorch) | Hạn chế hơn |
| Giao diện vận hành trên máy công nghiệp | Làm được nhưng ít phổ biến | Rất mạnh (WinForms, WPF) |
| Kết nối PLC, SDK camera, database | Có thư viện | Hệ sinh thái .NET rất đầy đủ |
| Chạy mô hình AI | Trực tiếp | Qua 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
- Viết lại chương trình đếm vật bằng C#, in ra diện tích từng vật.
- Tạo ứng dụng WinForms có nút "Chụp", hiển thị ảnh camera trong
PictureBoxvà kết quả OK/NG. - Chạy vòng lặp camera 30 phút và theo dõi bộ nhớ để chắc chắn không rò rỉ.


