Opencv C# 重疊 粘連 Overlap 輪廓分割 (不知道不知道)

先上效果圖

一種基于凹陷檢測重疊輪廓分割的方法

這兩個星期壓力大的一批,心臟都給干得亂跳了,現在高血壓+心率不齊+貧血。兄弟們保重身體啊。

簡單說下邏輯:

  1. 前處理:的噼里啪啦我就不說了,根據樣品來(灰度,濾波,二值化,形態學...)
  2. 提取輪廓并計算凸包
  3. 填充凸包后的輪廓 減去 原始輪廓得到凹陷區域
  4. 計算凹陷區域的面積,利用最大的兩個凹陷區域計算出兩個凹陷區域的最近兩點
  5. 兩點一條線作為分割線

步驟說起來很簡單,做起來準備上天。

要想做到好的效果就需要有過濾參數,我做了基本的四個參數

  1. 最小輪廓長度:用來過濾小顆粒
  2. 深度閾值:凸包凹陷的閾值 用來過濾凹陷淺的輪廓
  3. 迭代次數:我們上面只是拿了單個輪廓兩個最大凹陷區域進行分割,只適合兩個規則形狀的重疊,那三個呢 四個呢 無數個呢(管他那么多就是干)
  4. 線寬:分割線的寬度 最好要為2,別問 問就是坑

下面看看不同參數的效果:

迭代次數:可以簡單理解我要分為幾個顆粒?

深度閾值:越小 小凹陷就越多

效果就這樣了,這是基于形狀的,但是都說基于距離變換+分水嶺的好。先貼上代碼吧白嫖兄弟們
!!!這是我封裝的方法不一定適合你 參數自己傳進來就行。最好別用,不一定好用。打開思路很重要..........

比如:根據長軸作為分界線 對應點是不是就可以不用那么多迭代???更好的?骨架作為分界線???迭代次數應該寫在輪廓遍歷里面???當然是的,但是我腦子不想思考了才來寫個文章。

public ProcessingResult ProcessImage(Mat src, Dictionary<string, object> parameters, Mat? originalMat = null)
{if (!src.IsValidMat()) return new ProcessingResult();try{int depthThreshold = parameters.GetValueOrDefault("depthThreshold", 100)?.ToString()?.ToInt(100) ?? 100;int lineThickness = parameters.GetValueOrDefault("lineThickness", 2)?.ToString()?.ToInt(2) ?? 2;int miniArcLength = parameters.GetValueOrDefault("miniArcLength", 20)?.ToString()?.ToInt(20) ?? 20;int iterations = parameters.GetValueOrDefault("iterations", 1)?.ToString()?.ToInt(1) ?? 1;Mat binary = new Mat();if (src.Channels() > 1){var gray = src.CvtColor(ColorConversionCodes.BGR2GRAY);double otsuThresh = Cv2.Threshold(src, binary, 0, 255, ThresholdTypes.Binary | ThresholdTypes.Otsu);}else{binary = src;}Mat resultImage = binary.CvtColor(ColorConversionCodes.GRAY2BGR); // 彩色圖方便顯示for (int iteration = 0; iteration < iterations; iteration++){var contours = Cv2.FindContoursAsArray(binary, RetrievalModes.External, ContourApproximationModes.ApproxSimple);foreach (var contour in contours){try{if (contour.Length < 5) continue;double arcLen = Cv2.ArcLength(contour, true);if (arcLen < miniArcLength) continue;int[] hullIndices = Cv2.ConvexHullIndices(contour, true);if (hullIndices.Length < 3) continue;var defects = Cv2.ConvexityDefects(contour, hullIndices);if (defects == null || defects.Length == 0) continue;if (!defects.Any(a => a.Item3 / 256f > depthThreshold)) continue;Point[] hull = new Point[hullIndices.Length];for (int i = 0; i < hullIndices.Length; i++){hull[i] = contour[hullIndices[i]];}var rect = Cv2.BoundingRect(contour);using Mat mask = new Mat(rect.Height, rect.Width, MatType.CV_8UC1, Scalar.Black);Point[] TranslateContour(Point[] pts, Point offset){return pts.Select(p => new Point(p.X - offset.X, p.Y - offset.Y)).ToArray();}var hullLocal = TranslateContour(hull, rect.TopLeft);var contourLocal = TranslateContour(contour, rect.TopLeft);Cv2.DrawContours(mask, new List<Point[]>() { hullLocal }, 0, Scalar.White, -1);Cv2.DrawContours(mask, new List<Point[]>() { contourLocal }, 0, Scalar.Black, -1);var maskContours = Cv2.FindContoursAsArray(mask, RetrievalModes.External, ContourApproximationModes.ApproxSimple);if (maskContours.Length < 2) continue;var maxAreaContours = GetTop2MaxAreaContours(maskContours).Take(2).ToArray();var minDistancePoints = GetMinDistancePoint(maxAreaContours[0], maxAreaContours[1]);var distance = Math.Sqrt((minDistancePoints[0].X - minDistancePoints[1].X) * (minDistancePoints[0].X - minDistancePoints[1].X) + (minDistancePoints[0].Y - minDistancePoints[1].Y) * (minDistancePoints[0].Y - minDistancePoints[1].Y));if (distance > rect.Width / 2) continue;// 注意minDistancePoints中是mask局部坐標,轉回resultImage全局坐標:Cv2.Line(binary, minDistancePoints[0] + rect.TopLeft, minDistancePoints[1] + rect.TopLeft, Scalar.Black, lineThickness);Cv2.Line(resultImage, minDistancePoints[0] + rect.TopLeft, minDistancePoints[1] + rect.TopLeft, Scalar.OrangeRed, lineThickness);}catch (Exception){continue;}}}return new ProcessingResult(resultImage);}catch (Exception ex){Console.WriteLine(ex);return new ProcessingResult();}
}private Point[][] GetTop2MaxAreaContours(Point[][] contours)
{if (contours == null || contours.Length == 0)return new Point[0][];// 按輪廓面積降序排序,取前2個var top2 = contours.OrderByDescending(contour => Cv2.ContourArea(contour)).ToArray();return top2;
}
private Point[] GetMinDistancePoint(Point[] contour, Point[] contour1)
{if (contour == null || contour1 == null || contour.Length == 0 || contour1.Length == 0)return new Point[0];Point minP1 = new Point();Point minP2 = new Point();double minDist = double.MaxValue;foreach (var p1 in contour){foreach (var p2 in contour1){double dist = Math.Sqrt((p1.X - p2.X) * (p1.X - p2.X) + (p1.Y - p2.Y) * (p1.Y - p2.Y));if (dist < minDist){minDist = dist;minP1 = p1;minP2 = p2;}}}return new Point[] { minP1, minP2 };
}

上面是基于凸包凹陷的,那都說分水嶺+距離變換好!!!但是,好是有前提的 對一同樣大小顆粒的分割效果是很好的。但是對大小不一效果不太行,但是我也做了優化 下面給出大體邏輯。

?一種基于距離變幻+分水嶺 檢測重疊輪廓分割的方法

  1. 前處理:的噼里啪啦我就不說了,根據樣品來(灰度,濾波,二值化,形態學...)
  2. 進行距離變換?DistanceTransform+Normalize
  3. 獲取前景標記??Cv2.Threshold(distTrans8u, distTrans8u, foregroundThreshold * 255, 255, ThresholdTypes.Binary);
  4. 創建標記圖像? Mat markers = Mat.Zeros(binary.Size(), MatType.CV_32S);
  5. 標記背景?? ?using var sureBg = new Mat();
    Cv2.Dilate(binary, sureBg, new Mat(), iterations: 3);
  6. 應用分水嶺算法?Cv2.Watershed(originalMat, markers);
  7. 前面幾步都是爛大街的 隨便一搜都有的代碼 不清楚的直接搜?距離變換+分水嶺
  8. 得到輪廓并繪制在一張與原圖大小相等的黑圖上并把邊界涂色
      result = Mat.Zeros(originalMat.Size(), originalMat.Type());var boundaries = new Mat();Cv2.Compare(markers, new Scalar(-1), boundaries, CmpType.EQ);result.SetTo(new Scalar(255, 255, 255), boundaries);result.Row(0).SetTo(new Scalar(0, 0, 0));result.Row(result.Rows - 1).SetTo(new Scalar(0, 0, 0));result.Col(0).SetTo(new Scalar(0, 0, 0));result.Col(result.Cols - 1).SetTo(new Scalar(0, 0, 0));boundaries.Dispose();
  9. ?上一步得到了所謂分水嶺的輪廓,但是很有可能把你的小輪廓給干掉了 或者說正常的輪廓,那么我們需要合并:
    這是分水嶺前后的圖片,會發現少了很多。其實也不多就那幾個。
    ? ? ? ? ??
    1.原圖減去分水嶺得到的二值圖 再做形態學處理得到 圖4
    ? ? ? ?
    2.合并分水嶺二值圖與圖四

  10. 至于效果我覺得一般 邏輯嘛也覺得一般 我就是菜雞。

打個總結,牛馬不如騾子。?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/92603.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/92603.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/92603.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

CentOS7 安裝 rust 1.82.0

CentOS7 安裝 rust 1.82.0 我在CentOS7.9中安裝rust遇到報錯版本低&#xff0c;再升級版本的過程中遇到諸多問題&#xff0c;簡單記錄。 遇到的問題 提示版本低 centos7 安裝 ERROR: Rust 1.75.0 or newer required.Rust version 1.72.1 was found.原因是 CentOS7 的默認的軟件…

Compose 適配 - 鍵鼠模式

一、概念不止觸摸交互&#xff0c;在 ChromeOS 或外接鍵鼠的設備上&#xff0c;需要考慮焦點、懸停、右鍵等操作邏輯。二、使用2.1 焦點使用 Tab 鍵來導航&#xff0c;改變邊框以提供清晰的焦點指示器。Composable fun Demo() {val interactionSource remember { MutableInter…

征服 Linux 網絡:核心服務與實戰解析

在當今的IT基礎設施中&#xff0c;Linux作為服務器操作系統的基石&#xff0c;其強大的網絡功能是其不可或缺的優勢。對于任何志在成為高級系統管理員或運維工程師的人來說&#xff0c;精通Linux網絡配置與服務管理是核心競爭力。 與日常應用不同&#xff0c;Linux網絡管理往往…

Spark 之 DataFrame

# foreach useFeatureDF.rdd.foreachPartition {iter => iter.foreach {row =>val userId = row.getAs[Int]

射頻信號(大寬高比)時頻圖目標檢測anchors配置(下)

書接上文&#xff1a; 射頻信號&#xff08;大寬高比&#xff09;時頻圖目標檢測anchors配置&#xff08;上&#xff09; 三、4090加成檢測效果深度優化 在4090 24G專用顯存加持下繼續探究大寬高比目標檢測的奧秘&#xff1a; Conda環境遷移至租的云服 在云服上第一次測試…

跨境支付入門~國際支付結算(區塊鏈篇)

摘要Web3區塊鏈技術架構解析&#xff1a;從底層共識到應用生態本文系統梳理了Web3作為穩定幣基礎設施的技術架構&#xff0c;采用"數字共和國"的比喻框架&#xff0c;將區塊鏈技術分解為六大核心模塊&#xff1a;憲法根基&#xff08;區塊鏈層&#xff09;&#xff1…

Docker 私服

什么是 Docker 私服&#xff1f; Docker 官方的 Docker Hub 是一個用于管理公共鏡像的倉庫&#xff0c;我們可以從上面拉取鏡像 到本地&#xff0c;也可以把我們自己的鏡像推送上去。 但是&#xff0c;有時候我們的服務器無法訪問互聯網&#xff0c;或者你不希望將自己的鏡像…

DeepSeek vs ChatGPT:誰更勝一籌?

新興 AI 聊天機器人的崛起與挑戰&#xff1a;對話模型發展觀察近年來&#xff0c;生成式人工智能領域持續取得突破&#xff0c;聊天機器人作為其中的代表&#xff0c;廣泛應用于寫作、編程、問答和信息處理等任務。2025 年初&#xff0c;國內某 AI 團隊宣布了多項模型技術進展&…

飛算科技:以原創技術為翼,賦能產業數字化轉型

在數字經濟浪潮席卷全球的當下&#xff0c;一批專注于技術創新的中國企業正加速崛起&#xff0c;飛算數智科技&#xff08;深圳&#xff09;有限公司&#xff08;簡稱 “飛算科技”&#xff09;便是其中的佼佼者。作為一家國家級高新技術企業&#xff0c;飛算科技以自主創新為核…

電商接口什么意思?

“電商接口”這四個字&#xff0c;在中文互聯網上出現的頻次越來越高&#xff1a;商家后臺、小程序、ERP、數據大屏……幾乎任何與線上零售沾邊的場景都會提到它。然而&#xff0c;對大多數剛進入電商行業的新人&#xff0c;甚至一些已經開了很多年網店的老板來說&#xff0c;這…

前端面試專欄-前沿技術:30.跨端開發技術(React Native、Flutter)

&#x1f525; 歡迎來到前端面試通關指南專欄&#xff01;從js精講到框架到實戰&#xff0c;漸進系統化學習&#xff0c;堅持解鎖新技能&#xff0c;祝你輕松拿下心儀offer。 前端面試通關指南專欄主頁 前端面試專欄規劃詳情 跨端開發技術&#xff08;React Native、Flutter&am…

復盤—MySQL觸發器實現監聽數據表值的變化,對其他數據表做更新

文章目錄 MySQL交換數據庫表中兩列的值(額外的知識) 為防止后面有疑問,提前解釋為什么需要 `$$` ? 第一版需求 第二版需求 第三版需求 注意事項: 存在的嚴重問題 最終版 關鍵修復說明: 完整測試場景: 額外建議(如果需要顯式處理NULL): COALESCE函數 業務中出現的問題…

SpringCloud【Sentinel】

1&#xff0c;工作原理 2&#xff0c;常見規則 流量控制&#xff08;FlowRule&#xff09; 1&#xff0c;閾值類型設置如下 單機均攤&#xff1a;每個機器均攤&#xff0c;比如閾值填5&#xff0c;三個機器&#xff0c;就個機器都可以有5個 總體閾值&#xff1a;所有機器總閾…

解構未來金融:深入剖析DeFi與去中心化交易所(DEX)的技術架構

今天&#xff0c;我們來聊一個顛覆傳統金融界的熱門話題——DeFi&#xff08;去中心化金融&#xff09;。大家可能聽說過它如何承諾將銀行、交易所、保險等金融服務構建在一個開放、無需許可的區塊鏈網絡上。而這一切魔法的核心&#xff0c;正是其獨特的“技術架構”。 在這篇文…

中國西北典型綠洲區土壤水分特征(2018-2019年)

數據集摘要該數據包含張掖綠洲黑河沿岸濕地、過渡帶楊樹林土壤水分、溫度數據。數據采集時間為2018年至2019年&#xff0c;采集地點為張掖綠洲&#xff0c;數據為日數據。該數據集是按照課題制定的試驗方案和中國生態系統研究網絡編著的陸地生態系統水土氣生觀測規范進行數據的…

MySQL高可用部署

目錄 一、MHA&#xff08;一主多從模式&#xff09; 1.環境準備&#xff08;所有節點&#xff09; 2. 部署 MySQL 主從復制&#xff08;MasterSlave&#xff09; 3.部署 MHA Manager&#xff08;管理節點&#xff09; &#xff08;1&#xff09;安裝 MHA Manager &#xf…

從 XSS 到 Bot 攻擊:常見網絡攻擊防不勝防?雷池 WAF 用全場景防護為網站筑牢安全墻

1. 網絡攻擊類型當前常見的網絡攻擊類型包括&#xff1a;重放攻擊&#xff08;HTTP Request Replay Attack&#xff09;&#xff1a;攻擊者截獲合法用戶的 HTTP 請求并重新發送&#xff0c;以欺騙服務器執行相同操作。危害包括消耗服務器資源、大量抓取數據或繞過認證操作敏感接…

【王樹森推薦系統】推薦系統漲指標的方法05:特殊用戶人群

為什么要特殊對待特殊人群&#xff1f; 新用戶&#xff0c;低活用戶的行為很少&#xff0c;個性化推薦不準確。個性化的召回和排序都需要基于用戶的歷史行為&#xff0c;如果歷史行為少&#xff0c;個性化就做不好&#xff0c;尤其是新用戶&#xff0c;這就需要策略把個性化做的…

Java 大視界 -- Java 大數據在智能家居能源管理與節能優化中的深度應用(361)

Java 大視界 -- Java 大數據在智能家居能源管理與節能優化中的深度應用&#xff08;361&#xff09;引言&#xff1a;正文&#xff1a;一、Java 構建的智能家居能源數據架構1.1 多源能耗數據實時采集1.2 家庭能源畫像與異常檢測二、Java 驅動的節能策略與智能控制2.1 多場景節能…

從零開始的云計算生活——番外5,使用ELK實現對應用日志的監控

目錄 一.環境準備 試驗機安裝 修改文件配置 二.收集測試機&#xff08;test&#xff09;日志 配置pipline文件 配置filebeat配置文件 三.收集測試機nginx日志 下載安裝nginx 修改filebeat文件 修改pipline文件 四.收集網絡服務模塊日志 1.DHCP 下載dhcp 修改配置…