Python計算不規(guī)則圖形面積算法實現(xiàn)解析
這篇文章主要介紹了Python計算不規(guī)則圖形面積算法實現(xiàn)解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
介紹:大三上做一個醫(yī)學(xué)影像識別的項目,醫(yī)生在原圖上用紅筆標(biāo)記病灶點,通過記錄紅色的坐標(biāo)位置可以得到病灶點的外接矩形,但是后續(xù)會涉及到紅圈內(nèi)的面積在外接矩形下的占比問題,有些外接矩形內(nèi)有多個紅色標(biāo)記,在使用網(wǎng)上的opencv的fillPoly填充效果非常不理想,還有類似python計算任意多邊形方法也不理想的情況下,自己探索出的一種效果還不錯的計算多圈及不規(guī)則圖形的面積的算法。
能較為準(zhǔn)確的計算出不規(guī)則圖形的面積
正文:算法的思想很簡單,遍歷圖片每一列,通過色差判斷是否遇到標(biāo)記圈,將坐標(biāo)全部記錄,對每一列的坐標(biāo)都進行最小行和最大行記錄,確定每一列的最小和最大的坐標(biāo),然后上色(類似opencv的fillPoly的實現(xiàn),但是細(xì)節(jié)有些區(qū)別),只是這樣效果并不好,將圖片旋轉(zhuǎn)90度,再做一邊,將兩個圖片的結(jié)果放在一起做與操作,得到結(jié)果就能很好的處理多圈的標(biāo)記問題和多算面積的問題(比如上面的08-LM),

算法實現(xiàn)
全程只用pillow庫
首先先用屏幕拾色器獲取目標(biāo)顏色的rgb值,我這種情況下就是(237,28,36),前期截取外接矩形也是要這一步的,顏色也一致
def pixel_wanted(pix): return pix==(237,28, 36)
每一列都設(shè)定翻轉(zhuǎn)位初始為False,如果上一個像素點不是目標(biāo)色,當(dāng)前是目標(biāo)色則開始記錄,一旦不是目標(biāo)色,停止檢測
top_Pixel都設(shè)定為黑色(0,0,0)因為有圖片最上方就是目標(biāo)色,導(dǎo)致判定出問題,直接讓最上面的像素初始化是黑色
coordinate_List記錄了所有符合的點坐標(biāo)
coordinate_List = []
top_Pixel = (0,0,0)
for x in range(im.size[0]):
flag = False #初始化每一列翻轉(zhuǎn)位為False
for y in range(im.size[1]):
current_pixel = im.getpixel((x,y))
last_pixel = im.getpixel((x,y-1)) if y>0 else top_Pixel
#翻轉(zhuǎn)判定
if pixel_wanted(current_pixel) and \
not pixel_wanted(last_pixel):
flag = True
if flag and not pixel_wanted(current_pixel):
flag = False
if(flag):
coordinate_List.append((x,y))
coordinate_List中的點如下圖

然后就是將上面獲得coordinate列表進行處理
將coordinate列表中每一列的最小坐標(biāo)和最大坐標(biāo)進行記錄
因為每一列記錄的數(shù)量并不確定(應(yīng)該可以在上一步改進一下),所以需要遍歷多次
首先找到第一個列出現(xiàn)的坐標(biāo),將它的行信息記錄(行信息最小確定),
然后遍歷出全部的同列的坐標(biāo),比較行坐標(biāo),如果大的就將最大的代替(行信息最大確定),用一個新的列表記錄數(shù)據(jù)
coordinate_Min_Max_List = []
#找最小最大
for i in range(im.size[0]):
min=-1
max=-1
for coordinate in coordinate_List:
if coordinate[0] == i:
min = coordinate[1]
max = coordinate[1]
break
for coordinate in coordinate_List:
if coordinate[0] == i:
if coordinate[1]>max:
max = coordinate[1]
coordinate_Min_Max_List.append(min)
coordinate_Min_Max_List.append(max)
其中要將min和max都初始化為一個坐標(biāo)不存在的值比如-1,為了在下一步多圈且有空隙情況下,不會出現(xiàn)殘影現(xiàn)象,如下圖


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

然后就是繪制圖片了,每一列將列表中對應(yīng)的最小行到最大行涂滿
#上色
for x in range(im.size[0]):
for y in range(im.size[1]):
min = coordinate_Min_Max_List[x*2]
max = coordinate_Min_Max_List[x*2+1]
if min<y<max:
im.putpixel((x,y),(0,255,0))
else:
#可以把非紅圈的上掩膜遮住
pass
至此,就是類似opencv的算法實現(xiàn),雖然還差翻轉(zhuǎn)做與操作,但是已經(jīng)比opencv生成的效果好,寫成函數(shù)后續(xù)調(diào)用,
然后就是簡單的翻轉(zhuǎn)90度,再調(diào)用一次這個函數(shù)再做一遍
def Cal_S(im):
im_0 = im.rotate(0)
im_90 = im.rotate(90, expand=True)
im_0 = fillPoly(im_0)
im_90 = fillPoly(im_90)
im_90 = im_90.rotate(-90, expand=True)
i=0
for x in range(im.size[0]):
for y in range(im.size[1]):
if(im_0.getpixel((x,y))==(0,255,0) and
im_90.getpixel((x,y))==(0,255,0)):
im.putpixel((x,y),(0,255,0))
i+=1
return i/(im.size[0]*im.size[1])
做兩遍的效果圖


可以看到效果非常不錯,但是依舊有個別圖像有問題,比如十字分布的,
但現(xiàn)在的話誤差已經(jīng)降低非常多了,這些極其個別的十字現(xiàn)象可以手動把原圖切割一下,或者干脆不處理了

所有代碼,畫出綠圖片為了方便直觀的查看,函數(shù)中可以把圖片順便保存一下,總體看一下效果
from PIL import Image
def pixel_wanted(pix):
return pix==(237,28, 36)
def fillPoly(im):
coordinate_List = []
top_Pixel = (0,0,0)
for x in range(im.size[0]):
flag = False #初始化每一列翻轉(zhuǎn)位為False
for y in range(im.size[1]):
current_pixel = im.getpixel((x,y))
last_pixel = im.getpixel((x,y-1)) if y>0 else top_Pixel
#翻轉(zhuǎn)判定
if pixel_wanted(current_pixel) and \
not pixel_wanted(last_pixel):
flag = True
if flag and not pixel_wanted(current_pixel):
flag = False
if(flag):
coordinate_List.append((x,y))
coordinate_Min_Max_List = []
#找最小最大
for i in range(im.size[0]):
min=-1
max=-1
for coordinate in coordinate_List:
if coordinate[0] == i:
min = coordinate[1]
max = coordinate[1]
break
for coordinate in coordinate_List:
if coordinate[0] == i:
if coordinate[1]>max:
max = coordinate[1]
coordinate_Min_Max_List.append(min)
coordinate_Min_Max_List.append(max)
#上色
for x in range(im.size[0]):
for y in range(im.size[1]):
min = coordinate_Min_Max_List[x*2]
max = coordinate_Min_Max_List[x*2+1]
if min<y<max:
im.putpixel((x,y),(0,255,0))
else:
#可以把非紅圈的上掩膜遮住
pass
return im
def Cal_S(im):
im_0 = im.rotate(0)
im_90 = im.rotate(90, expand=True)
im_0 = fillPoly(im_0)
im_90 = fillPoly(im_90)
im_90 = im_90.rotate(-90, expand=True)
i=0
for x in range(im.size[0]):
for y in range(im.size[1]):
if(im_0.getpixel((x,y))==(0,255,0) and
im_90.getpixel((x,y))==(0,255,0)):
im.putpixel((x,y),(0,255,0))
i+=1
return i/(im.size[0]*im.size[1])
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Python3 venv搭建輕量級虛擬環(huán)境的步驟(圖文)
這篇文章主要介紹了Python3 venv搭建輕量級虛擬環(huán)境的步驟(圖文),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08

