溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Python計算不規(guī)則圖形面積算法實現(xiàn)解析

發(fā)布時間:2020-10-11 17:45:52 來源:腳本之家 閱讀:278 作者:PowerZZJ 欄目:開發(fā)技術(shù)

這篇文章主要介紹了Python計算不規(guī)則圖形面積算法實現(xiàn)解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下

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

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

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

Python計算不規(guī)則圖形面積算法實現(xiàn)解析

算法實現(xiàn)

全程只用pillow庫

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

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

每一列都設(shè)定翻轉(zhuǎn)位初始為False,如果上一個像素點不是目標色,當(dāng)前是目標色則開始記錄,一旦不是目標色,停止檢測

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

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

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中的點如下圖

Python計算不規(guī)則圖形面積算法實現(xiàn)解析

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

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

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

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

然后遍歷出全部的同列的坐標,比較行坐標,如果大的就將最大的代替(行信息最大確定),用一個新的列表記錄數(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都初始化為一個坐標不存在的值比如-1,為了在下一步多圈且有空隙情況下,不會出現(xiàn)殘影現(xiàn)象,如下圖

Python計算不規(guī)則圖形面積算法實現(xiàn)解析Python計算不規(guī)則圖形面積算法實現(xiàn)解析

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

Python計算不規(guī)則圖形面積算法實現(xiàn)解析

然后就是繪制圖片了,每一列將列表中對應(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])

做兩遍的效果圖

Python計算不規(guī)則圖形面積算法實現(xiàn)解析Python計算不規(guī)則圖形面積算法實現(xiàn)解析

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

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

Python計算不規(guī)則圖形面積算法實現(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í)有所幫助,也希望大家多多支持億速云。

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI