百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

C#使用 OpenCvSharp 计算每个轮廓面积的指南

csdh11 2025-02-10 11:58 36 浏览

在计算机视觉领域中,找到和分析图像中的轮廓(contours)是一个非常基础且重要的任务。轮廓可以帮助我们识别和处理图像中的对象。在本文中,我们将详细探讨如何使用 OpenCvSharp 库来找到图像中的轮廓并计算每个轮廓的面积。我们将使用一个完整的示例代码来解释整个流程。

准备工作

首先,我们需要确保已经安装了 OpenCvSharp。你可以通过 NuGet 包管理器来安装 OpenCvSharp4 和 OpenCvSharp4.runtime.win。

dotnet add package OpenCvSharp4
dotnet add package OpenCvSharp4.runtime.win

计算轮廓面积的步骤

  1. 读取图像
  2. 将图像转换为灰度图
  3. 应用阈值处理或边缘检测
  4. 查找轮廓
  5. 计算每个轮廓的面积

下面是详细的示例代码。

using OpenCvSharp;

namespace App5
{
    internal class Program
    {
        static void Main(string[] args)
        {
            // 读取图像
            Mat src = Cv2.ImRead("0.jpg", ImreadModes.Color);

            if (src.Empty())
            {
                Console.WriteLine("无法读取图像");
                return;
            }

            // 2. 将图像转换为灰度图
            Mat gray = new Mat();
            Cv2.CvtColor(src, gray, ColorConversionCodes.BGR2GRAY);
            Cv2.ImShow("灰度图", gray);

            // 3. 应用阈值处理
            Mat binary = new Mat();
            Cv2.Threshold(gray, binary, 128, 255, ThresholdTypes.Binary);
            Cv2.ImShow("阈值", binary);

            // 4. 查找轮廓
            Point[][] contours;
            HierarchyIndex[] hierarchy;
            Cv2.FindContours(binary, out contours, out hierarchy, RetrievalModes.CComp, ContourApproximationModes.ApproxSimple);

            // 5. 遍历所有轮廓并过滤
            for (int i = 0; i < contours.Length; i++)
            {
                // 过滤尺度太小的轮廓
                double area = Cv2.ContourArea(contours[i]);
                if (area < 100) // 可调节的最小轮廓面积阈值
                {
                    continue;
                }

                // 只绘制最外层的轮廓(忽略嵌套的子轮廓)
                if (hierarchy[i].Parent == -1)
                {
                    // 输出每个有效轮廓的面积
                    Console.WriteLine($"轮廓 {i + 1} 的面积: {area}");

                    // 绘制轮廓
                    Cv2.DrawContours(src, contours, i, Scalar.Red, 2);

                    // 计算轮廓的中心点
                    Moments moments = Cv2.Moments(contours[i]);
                    int cx = (int)(moments.M10 / moments.M00);
                    int cy = (int)(moments.M01 / moments.M00);

                    // 标注面积
                    Cv2.PutText(src, area.ToString("F2"), new Point(cx, cy), HersheyFonts.HersheySimplex, 0.6, Scalar.Red, 2);
                }
            }

            // 显示并保存结果图像
            Cv2.ImShow("对像与面积", src);
            Cv2.WaitKey();
        }
    }
}

遍历并过滤轮廓

// 遍历所有轮廓并过滤
for (int i = 0; i < contours.Length; i++)
{
    // 过滤尺度太小的轮廓
    double area = Cv2.ContourArea(contours[i]);
    if (area < 100) // 可调节的最小轮廓面积阈值
    {
        continue;
    }

    // 只绘制最外层的轮廓(忽略嵌套的子轮廓)
    if (hierarchy[i].Parent == -1)
    {
        // 输出每个有效轮廓的面积
        Console.WriteLine($"轮廓 {i + 1} 的面积: {area}");

        // 绘制轮廓
        Cv2.DrawContours(src, contours, i, Scalar.Red, 2);

        // 计算轮廓的中心点
        Moments moments = Cv2.Moments(contours[i]);
        int cx = (int)(moments.M10 / moments.M00);
        int cy = (int)(moments.M01 / moments.M00);

        // 标注面积
        Cv2.PutText(src, area.ToString("F2"), new Point(cx, cy), HersheyFonts.HersheySimplex, 0.6, Scalar.Red, 2);
    }
}
  • 过滤面积过小的轮廓:通过计算轮廓面积,过滤掉面积小于100的轮廓。
  • 仅绘制最外层轮廓:通过检查hierarchy[i].Parent == -1,只绘制最外层的轮廓,忽略嵌套轮廓。
  • 输出有效轮廓的面积:在控制台输出每个有效轮廓的面积。
  • 绘制轮廓:在原图上用红色绘制有效轮廓。
  • 计算和标注轮廓中心点:计算每个轮廓的中心点并标注面积值。

总结

本文介绍了如何使用 OpenCvSharp 库计算图像中每个轮廓的面积。我们通过一个完整的示例代码展示了从读取图像、灰度处理、二值化、查找轮廓到计算面积的整个流程。希望这能对你在图像处理上的工作有所帮助。

相关推荐

探索Java项目中日志系统最佳实践:从入门到精通

探索Java项目中日志系统最佳实践:从入门到精通在现代软件开发中,日志系统如同一位默默无闻却至关重要的管家,它记录了程序运行中的各种事件,为我们排查问题、监控性能和优化系统提供了宝贵的依据。在Java...

用了这么多年的java日志框架,你真的弄懂了吗?

在项目开发过程中,有一个必不可少的环节就是记录日志,相信只要是个程序员都用过,可是咱们自问下,用了这么多年的日志框架,你确定自己真弄懂了日志框架的来龙去脉嘛?下面笔者就详细聊聊java中常用日志框架的...

物理老师教你学Java语言(中篇)(物理专业学编程)

第四章物质的基本结构——类与对象...

一文搞定!Spring Boot3 定时任务操作全攻略

各位互联网大厂的后端开发小伙伴们,在使用SpringBoot3开发项目时,你是否遇到过定时任务实现的难题呢?比如任务调度时间不准确,代码报错却找不到方向,是不是特别头疼?如今,随着互联网业务规模...

你还不懂java的日志系统吗 ?(java的日志类)

一、背景在java的开发中,使用最多也绕不过去的一个话题就是日志,在程序中除了业务代码外,使用最多的就是打印日志。经常听到的这样一句话就是“打个日志调试下”,没错在日常的开发、调试过程中打印日志是常干...

谈谈枚举的新用法--java(java枚举的作用与好处)

问题的由来前段时间改游戏buff功能,干了一件愚蠢的事情,那就是把枚举和运算集合在一起,然后运行一段时间后buff就出现各种问题,我当时懵逼了!事情是这样的,做过游戏的都知道,buff,需要分类型,且...

你还不懂java的日志系统吗(javaw 日志)

一、背景在java的开发中,使用最多也绕不过去的一个话题就是日志,在程序中除了业务代码外,使用最多的就是打印日志。经常听到的这样一句话就是“打个日志调试下”,没错在日常的开发、调试过程中打印日志是常干...

Java 8之后的那些新特性(三):Java System Logger

去年12月份log4j日志框架的一个漏洞,给Java整个行业造成了非常大的影响。这个事情也顺带把log4j这个日志框架推到了争议的最前线。在Java领域,log4j可能相对比较流行。而在log4j之外...

Java开发中的日志管理:让程序“开口说话”

Java开发中的日志管理:让程序“开口说话”日志是程序员的朋友,也是程序的“嘴巴”。它能让程序在运行过程中“开口说话”,告诉我们它的状态、行为以及遇到的问题。在Java开发中,良好的日志管理不仅能帮助...

吊打面试官(十二)--Java语言中ArrayList类一文全掌握

导读...

OS X 效率启动器 Alfred 详解与使用技巧

问:为什么要在Mac上使用效率启动器类应用?答:在非特殊专业用户的环境下,(每天)用户一般可以在系统中进行上百次操作,可以是点击,也可以是拖拽,但这些只是过程,而我们的真正目的是想获得结果,也就是...

Java中 高级的异常处理(java中异常处理的两种方式)

介绍异常处理是软件开发的一个关键方面,尤其是在Java中,这种语言以其稳健性和平台独立性而闻名。正确的异常处理不仅可以防止应用程序崩溃,还有助于调试并向用户提供有意义的反馈。...

【性能调优】全方位教你定位慢SQL,方法介绍下!

1.使用数据库自带工具...

全面了解mysql锁机制(InnoDB)与问题排查

MySQL/InnoDB的加锁,一直是一个常见的话题。例如,数据库如果有高并发请求,如何保证数据完整性?产生死锁问题如何排查并解决?下面是不同锁等级的区别表级锁:开销小,加锁快;不会出现死锁;锁定粒度...

看懂这篇文章,你就懂了数据库死锁产生的场景和解决方法

一、什么是死锁加锁(Locking)是数据库在并发访问时保证数据一致性和完整性的主要机制。任何事务都需要获得相应对象上的锁才能访问数据,读取数据的事务通常只需要获得读锁(共享锁),修改数据的事务需要获...