python計算不規則圖形面積演算法

来源:https://www.cnblogs.com/powerzzjcode/archive/2019/11/21/11908817.html
-Advertisement-
Play Games

介紹:大三上做一個醫學影像識別的項目,醫生在原圖上用紅筆標記病竈點,通過記錄紅色的坐標位置可以得到病竈點的外接矩形,但是後續會涉及到紅圈內的面積在外接矩形下的占比問題,有些外接矩形內有多個紅色標記,在使用網上的opencv的fillPoly填充效果非常不理想,還有類似python計算任意多邊形方法也 ...


介紹:大三上做一個醫學影像識別的項目,醫生在原圖上用紅筆標記病竈點,通過記錄紅色的坐標位置可以得到病竈點的外接矩形,但是後續會涉及到紅圈內的面積在外接矩形下的占比問題,有些外接矩形內有多個紅色標記,在使用網上的opencv的fillPoly填充效果非常不理想,還有類似python計算任意多邊形方法也不理想的情況下,自己探索出的一種效果還不錯的計算多圈及不規則圖形的面積的演算法。

醫生提供的病竈標記圖和原圖,大部分長這樣

 

 

 

 

但也有一些多圈情況

 

 

 

 

 很明顯,這些圖片都是非常需要計算面積占比的,對樣本需要篩選

通過百度,用opencv的填充來計算面積,一部分效果很差,單圈畫不全,多圈都是錯(用將面積計算結果上色,方便觀察)

 

 

 

 

 

通過此演算法之後,無論單圈,多圈,面積計算準確度提高許多

 

 

 

 

 能較為準確的計算出不規則圖形的面積

正文:演算法的思想很簡單,遍歷圖片每一列,通過色差判斷是否遇到標記圈,將坐標全部記錄,對每一列的坐標都進行最小行和最大行記錄,確定每一列的最小和最大的坐標,然後上色(類似opencv的fillPoly的實現,但是細節有些區別),只是這樣效果並不好,將圖片旋轉90度,再做一邊,將兩個圖片的結果放在一起做與操作,得到結果就能很好的處理多圈的標記問題和多算面積的問題(比如上面的08-LM),

 

 演算法實現

全程只用pillow庫

首先先用屏幕拾色器獲取目標顏色的rgb值,我這種情況下就是(237,28,36),前期截取外接矩形也是要這一步的,顏色也一致

1 def pixel_wanted(pix):
2     return pix==(237,28, 36)

每一列都設定翻轉位初始為False,如果上一個像素點不是目標色,當前是目標色則開始記錄,一旦不是目標色,停止檢測

top_Pixel都設定為黑色(0,0,0)因為有圖片最上方就是目標色,導致判定出問題,直接讓最上面的像素初始化是黑色

coordinate_List記錄了所有符合的點坐標

 1 coordinate_List = []
 2 top_Pixel = (0,0,0)
 3 for x in range(im.size[0]):
 4     flag = False #初始化每一列翻轉位為False
 5     for y in range(im.size[1]):
 6         current_pixel = im.getpixel((x,y))
 7         last_pixel = im.getpixel((x,y-1)) if y>0 else top_Pixel
 8         #翻轉判定
 9         if pixel_wanted(current_pixel) and \
10                 not pixel_wanted(last_pixel):
11             flag = True
12         if flag and not pixel_wanted(current_pixel):
13             flag = False
14         if(flag):
15             coordinate_List.append((x,y))

coordinate_List中的點如下圖

 

 然後就是將上面獲得coordinate列表進行處理

將coordinate列表中每一列的最小坐標和最大坐標進行記錄

因為每一列記錄的數量並不確定(應該可以在上一步改進一下),所以需要遍歷多次

首先找到第一個列出現的坐標,將它的行信息記錄(行信息最小確定),

然後遍歷出全部的同列的坐標,比較行坐標,如果大的就將最大的代替(行信息最大確定),用一個新的列表記錄數據

 1 coordinate_Min_Max_List = []
 2 #找最小最大
 3 for i in range(im.size[0]):
 4     min=-1
 5     max=-1
 6     for coordinate in coordinate_List:
 7         if coordinate[0] == i:
 8             min = coordinate[1]
 9             max = coordinate[1]
10             break
11     for coordinate in coordinate_List:
12         if coordinate[0] == i:
13             if coordinate[1]>max:
14                 max = coordinate[1]
15     coordinate_Min_Max_List.append(min)
16     coordinate_Min_Max_List.append(max)

其中要將min和max都初始化為一個坐標不存在的值比如-1,為了在下一步多圈且有空隙情況下,不會出現殘影現象,如下圖

 

 

 

上一步的最後得到一個列表,第n列的最小行和最大行分別是第2n和2n+1元素,結果中的-1,為了讓下一步不會畫進去

 

然後就是繪製圖片了,每一列將列表中對應的最小行到最大行塗滿

 1 #上色
 2 for x in range(im.size[0]):
 3     for y in range(im.size[1]):
 4         min = coordinate_Min_Max_List[x*2]
 5         max = coordinate_Min_Max_List[x*2+1]
 6         if min<y<max:
 7             im.putpixel((x,y),(0,255,0))
 8         else:
 9             #可以把非紅圈的上掩膜遮住
10             pass

至此,就是類似opencv的演算法實現,雖然還差翻轉做與操作,但是已經比opencv生成的效果好,寫成函數後續調用,

然後就是簡單的翻轉90度,再調用一次這個函數再做一遍

 1 def Cal_S(im):
 2     im_0 = im.rotate(0)
 3     im_90 = im.rotate(90, expand=True)
 4     
 5     im_0 = fillPoly(im_0)
 6     im_90 = fillPoly(im_90)
 7     im_90 = im_90.rotate(-90, expand=True)
 8 
 9     i=0
10     for x in range(im.size[0]):
11         for y in range(im.size[1]):
12             if(im_0.getpixel((x,y))==(0,255,0) and
13             im_90.getpixel((x,y))==(0,255,0)):
14                 im.putpixel((x,y),(0,255,0))
15                 i+=1
16     return i/(im.size[0]*im.size[1])

做兩遍的效果圖

 

 

 可以看到效果非常不錯,但是依舊有個別圖像有問題,比如十字分佈的,

但現在的話誤差已經降低非常多了,這些極其個別的十字現象可以手動把原圖切割一下,或者乾脆不處理了

 

 

所有代碼,畫出綠圖片為了方便直觀的查看,函數中可以把圖片順便保存一下,總體看一下效果

 1 from PIL import Image
 2 
 3 def pixel_wanted(pix):
 4     return pix==(237,28, 36)
 5 
 6 def fillPoly(im):
 7     coordinate_List = []
 8 
 9     top_Pixel = (0,0,0)
10     for x in range(im.size[0]):
11         flag = False #初始化每一列翻轉位為False
12         for y in range(im.size[1]):
13             current_pixel = im.getpixel((x,y))
14             last_pixel = im.getpixel((x,y-1)) if y>0 else top_Pixel
15             #翻轉判定
16             if pixel_wanted(current_pixel) and \
17                     not pixel_wanted(last_pixel):
18                 flag = True
19             if flag and not pixel_wanted(current_pixel):
20                 flag = False
21             if(flag):
22                 coordinate_List.append((x,y))
23     coordinate_Min_Max_List = []
24     #找最小最大
25     for i in range(im.size[0]):
26         min=-1
27         max=-1
28         for coordinate in coordinate_List:
29             if coordinate[0] == i:
30                 min = coordinate[1]
31                 max = coordinate[1]
32                 break
33         for coordinate in coordinate_List:
34             if coordinate[0] == i:
35                 if coordinate[1]>max:
36                     max = coordinate[1]
37         coordinate_Min_Max_List.append(min)
38         coordinate_Min_Max_List.append(max)
39     #上色
40     for x in range(im.size[0]):
41         for y in range(im.size[1]):
42             min = coordinate_Min_Max_List[x*2]
43             max = coordinate_Min_Max_List[x*2+1]
44             if min<y<max:
45                 im.putpixel((x,y),(0,255,0))
46             else:
47                 #可以把非紅圈的上掩膜遮住
48                 pass
49     return im
50 
51 def Cal_S(im):
52     im_0 = im.rotate(0)
53     im_90 = im.rotate(90, expand=True)
54 
55     im_0 = fillPoly(im_0)
56     im_90 = fillPoly(im_90)
57     im_90 = im_90.rotate(-90, expand=True)
58 
59     i=0
60     for x in range(im.size[0]):
61         for y in range(im.size[1]):
62             if(im_0.getpixel((x,y))==(0,255,0) and
63             im_90.getpixel((x,y))==(0,255,0)):
64                 im.putpixel((x,y),(0,255,0))
65                 i+=1
66     return i/(im.size[0]*im.size[1])

 

 

 

 

 

 

 

 

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 進程管理控制 這裡實現的是一個自定義timer用於統計子進程運行的時間。使用方式主要是 例如要統計 的運行時間可以直接輸入 ,其後的 是指所要運行的程式的參數。如: 。如果要指定程式運行多少時間,如5秒鐘,可以輸入 。需要註意的是,該程式對輸入沒有做異常檢測,所以要確保程式輸入正確。 Linux 程 ...
  • 線程狀態概述: 當線程被創建並啟動以後,它既不是一啟動就進入了執行狀態,也不是一直處於執行狀態。線上程的生命周期中, 有幾種狀態呢?在API中 java.lang.Thread.State 這個枚舉中給出了六種線程狀態 Timed Waiting(計時等待) Timed Waiting在API中的描 ...
  • 連接上imap服務後,什麼都不操作,我測試大約5分鐘會被服務端斷掉,測試代碼如下 為了保持住這條連接,每隔10秒列取一下郵件夾列表,這樣就可以一直保持住連接了。開三個視窗,一個視窗不停的netstat查看tcp連接情況,一個視窗運行代碼,一個視窗打開tcpdump監聽埠查看數據請求 while t ...
  • 本文介紹,PHP運行在FastCGI模式時,FPM提供的方法:fastcgi_finish_request。在說這個方法之前,我們先瞭解PHP有哪些常用的運行模式? PHP運行模式CGI 通用網關介面 / Common Gateway InterfaceCGI已經是比較老的模式了,這幾年都很少用了。 ...
  • 反射 反射的基本介紹 17.3.1 基本介紹 1) 反射可以在運行時 動態獲取變數的各種信息, 比如變數的類型(type),類別(kind) 2) 如果是結構體變數,還可以獲取到結構體本身的信息(包括結構體的 欄位、 方法) 3) 通過反射,可以修改變數的值,可以調用關聯的方法。 4) 使用反射,需 ...
  • 技術:Java;JSP;Struts2 spring hibernate資料庫: mysqlweb伺服器:tomcat集成開發工具: MyEclipse2014基於SSH的嬰幼兒產品銷售系統主要實現基本的網路購物的功能。本系統結構如下:1,游客訪問 |--系統首頁,查看所有的商品信息和相關的菜單信息 ...
  • 安裝Homebrew 如果已經安裝可以忽略,沒有安裝的請查看小明之前寫好的文章 "mac安裝homebrew" 使用Homebrew安裝Redis (1) 安裝命令 (2) 查看軟體安裝及配置文件位置 Homebrew安裝的軟體會預設在 路徑下; redis的配置文件 存放在 路徑下。 (3) 啟動 ...
  • Mapper映射文件 mapper.xml映射文件主要是用來編寫SQL語句的,以及一些結果集的映射關係的編寫,還有就是緩存的一些配置等等。 在映射文件裡面可以配置以下標簽: | 元素名稱 | 描述 | 備註 | | | | | | select | 查詢語句,最常用、最複雜的元素之一 | 可以自定義 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...