校园春色亚洲色图_亚洲视频分类_中文字幕精品一区二区精品_麻豆一区区三区四区产品精品蜜桃

主頁 > 知識庫 > 運用Python3實現Two-Pass算法檢測區域連通性

運用Python3實現Two-Pass算法檢測區域連通性

熱門標簽:外呼并發線路 ai電銷機器人源碼 百度地圖標注沒有了 長沙高頻外呼系統原理是什么 地圖標注審核表 湛江智能外呼系統廠家 ai電話機器人哪里好 宿遷星美防封電銷卡 西藏房產智能外呼系統要多少錢

技術背景

連通性檢測是圖論中常常遇到的一個問題,我們可以用五子棋的思路來理解這個問題五子棋中,橫、豎、斜相鄰的兩個棋子,被認為是相連接的,而一樣的道理,在一個二維的圖中,只要在橫、豎、斜三個方向中的一個存在相鄰的情況,就可以認為圖上相連通的。比如以下案例中的python數組,3號元素和5號元素就是相連接的,5號元素和6號元素也是相連接的,因此這三個元素實際上是屬于同一個區域的:

array([[0, 3, 0],
       [0, 5, 0],
       [6, 0, 0]])

而再如下面這個例子,其中的1、2、3三個元素是相連的,4、5、6三個元素也是相連的,但是這兩個區域不存在連接性,因此這個網格被分成了兩個區域:

array([[1, 0, 4],
       [2, 0, 5],
       [3, 0, 6]])

那么如何高效的檢測一張圖片或者一個矩陣中的所有連通區域并打上標簽,就是我們所關注的一個問題。

Two-Pass算法

一個典型的連通性檢測的方案是Two-Pass算法,該算法可以用如下的一張動態圖來演示:

該算法的核心在于用兩次的遍歷,為所有的節點打上分區的標簽,如果是不同的分區,就會打上不同的標簽。其基本的算法步驟可以用如下語言進行概述:

  1. 遍歷網格節點,如果網格的上、左、左上三個格點不存在元素,則為當前網格打上新的標簽,同時標簽編號加一;
  2. 當上、左、左上的網格中存在一個元素時,將該元素值賦值給當前的網格作為標簽;
  3. 當上、左、左上的網格中有多個元素時,取最低值作為當前網格的標簽;
  4. 在標簽賦值時,留意標簽上邊和左邊已經被遍歷過的4個元素,將4個元素中的最低值與這四個元素分別添加到Union的數據結構中(參考鏈接1);
  5. 再次遍歷網格節點,根據Union數據結構中的值刷新網格中的標簽值,最終得到劃分好區域和標簽的元素矩陣。

測試數據的生成

這里我們以Python3為例,可以用Numpy來產生一系列隨機的0-1矩陣,這里我們產生一個20*20大小的矩陣:

# two_pass.py

import numpy as np
import matplotlib.pyplot as plt

if __name__ == "__main__":
    np.random.seed(1)
    graph = np.random.choice([0,1],size=(20,20))
    print (graph)

    plt.figure()
    plt.imshow(graph)
    plt.savefig('random_bin_graph.png')

執行的輸出結果如下:

$ python3 two_pass.py 
[[1 1 0 0 1 1 1 1 1 0 0 1 0 1 1 0 0 1 0 0]
 [0 1 0 0 1 0 0 0 1 0 0 0 1 1 1 1 1 0 0 0]
 [1 1 1 1 1 1 0 1 1 0 0 1 0 0 1 1 1 0 1 0]
 [0 1 1 0 1 1 1 1 0 0 1 1 0 0 0 0 1 1 1 0]
 [1 0 0 1 1 0 1 1 0 1 0 0 1 1 1 0 1 1 0 1]
 [1 1 1 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0]
 [0 1 1 1 1 1 1 0 0 1 1 0 0 1 0 0 0 1 1 1]
 [1 1 0 1 0 1 0 0 0 1 1 1 0 1 0 0 0 0 1 0]
 [1 0 1 1 1 0 0 0 0 0 0 1 0 0 1 0 0 1 1 0]
 [0 0 1 0 0 0 0 1 0 0 0 0 1 1 0 0 1 1 1 0]
 [0 0 0 0 1 1 1 0 1 1 0 0 0 1 1 0 1 1 1 0]
 [1 1 1 1 0 1 0 0 1 0 1 0 1 1 0 1 1 0 1 1]
 [1 0 1 0 1 0 1 1 1 1 1 1 0 0 1 1 0 0 0 1]
 [1 0 0 0 0 0 1 1 1 1 1 1 1 0 0 1 0 0 0 1]
 [0 1 0 1 0 0 0 0 1 1 0 0 0 1 0 1 1 0 0 1]
 [0 1 0 0 0 1 0 1 0 1 1 1 0 1 0 1 1 1 1 0]
 [0 1 0 0 0 0 1 1 0 1 1 0 0 1 1 1 1 1 1 1]
 [0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 1 1 0 0 0]
 [1 0 1 0 1 0 0 0 0 0 0 1 0 0 0 1 0 1 1 0]
 [0 1 1 0 1 0 1 0 1 1 0 0 1 0 0 0 0 0 1 1]]

同時會生成一張網格的圖片:


其實從這個圖片中我們可以看出,圖片的上面部分幾乎都是連接在一起的,只有最下面存在幾個獨立的區域。

Two-Pass算法的實現

這里需要說明的是,因為我們并沒有使用Union的數據結構,而是只使用了Python的字典數據結構,因此代碼寫起來會比較冗余而且不是那么美觀,但是這里我們主要的目的是先用代解決這一實際問題,因此代碼亂就亂一點吧。

# two_pass.py

import numpy as np
import matplotlib.pyplot as plt
from copy import deepcopy

def first_pass(g) -> list:
    graph = deepcopy(g)
    height = len(graph)
    width = len(graph[0])
    label = 1
    index_dict = {}
    for h in range(height):
        for w in range(width):
            if graph[h][w] == 0:
                continue
            if h == 0 and w == 0:
                graph[h][w] = label
                label += 1
                continue
            if h == 0 and graph[h][w-1] > 0:
                graph[h][w] = graph[h][w-1]
                continue
            if w == 0 and graph[h-1][w] > 0:
                if graph[h-1][w] = graph[h-1][min(w+1, width-1)]:
                    graph[h][w] = graph[h-1][w]
                    index_dict[graph[h-1][min(w+1, width-1)]] = graph[h-1][w]
                elif graph[h-1][min(w+1, width-1)] > 0:
                    graph[h][w] = graph[h-1][min(w+1, width-1)]
                    index_dict[graph[h-1][w]] = graph[h-1][min(w+1, width-1)]
                continue
            if h == 0 or w == 0:
                graph[h][w] = label
                label += 1
                continue
            neighbors = [graph[h-1][w], graph[h][w-1], graph[h-1][w-1], graph[h-1][min(w+1, width-1)]]
            neighbors = list(filter(lambda x:x>0, neighbors))
            if len(neighbors) > 0:
                graph[h][w] = min(neighbors)
                for n in neighbors:
                    if n in index_dict:
                        index_dict[n] = min(index_dict[n], min(neighbors))
                    else:
                        index_dict[n] = min(neighbors)
                continue
            graph[h][w] = label
            label += 1
    return graph, index_dict

def remap(idx_dict) -> dict:
    index_dict = deepcopy(idx_dict)
    for id in idx_dict:
        idv = idx_dict[id]
        while idv in idx_dict:
            if idv == idx_dict[idv]:
                break
            idv = idx_dict[idv]
        index_dict[id] = idv
    return index_dict

def second_pass(g, index_dict) -> list:
    graph = deepcopy(g)
    height = len(graph)
    width = len(graph[0])
    for h in range(height):
        for w in range(width):
            if graph[h][w] == 0:
                continue
            if graph[h][w] in index_dict:
                graph[h][w] = index_dict[graph[h][w]]
    return graph

def flatten(g) -> list:
    graph = deepcopy(g)
    fgraph = sorted(set(list(graph.flatten())))
    flatten_dict = {}
    for i in range(len(fgraph)):
        flatten_dict[fgraph[i]] = i
    graph = second_pass(graph, flatten_dict)
    return graph

if __name__ == "__main__":
    np.random.seed(1)
    graph = np.random.choice([0,1],size=(20,20))
    graph_1, idx_dict = first_pass(graph)
    idx_dict = remap(idx_dict)
    graph_2 = second_pass(graph_1, idx_dict)
    graph_3 = flatten(graph_2)
    print (graph_3)

    plt.subplot(131)
    plt.imshow(graph)
    plt.subplot(132)
    plt.imshow(graph_3)
    plt.subplot(133)
    plt.imshow(graph_3>0)
    plt.savefig('random_bin_graph.png')

完整代碼的輸出如下所示:

$ python3 two_pass.py 
[[1 1 0 0 1 1 1 1 1 0 0 1 0 1 1 0 0 1 0 0]
 [0 1 0 0 1 0 0 0 1 0 0 0 1 1 1 1 1 0 0 0]
 [1 1 1 1 1 1 0 1 1 0 0 1 0 0 1 1 1 0 1 0]
 [0 1 1 0 1 1 1 1 0 0 1 1 0 0 0 0 1 1 1 0]
 [1 0 0 1 1 0 1 1 0 1 0 0 1 1 1 0 1 1 0 1]
 [1 1 1 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0]
 [0 1 1 1 1 1 1 0 0 1 1 0 0 1 0 0 0 1 1 1]
 [1 1 0 1 0 1 0 0 0 1 1 1 0 1 0 0 0 0 1 0]
 [1 0 1 1 1 0 0 0 0 0 0 1 0 0 1 0 0 1 1 0]
 [0 0 1 0 0 0 0 1 0 0 0 0 1 1 0 0 1 1 1 0]
 [0 0 0 0 1 1 1 0 1 1 0 0 0 1 1 0 1 1 1 0]
 [1 1 1 1 0 1 0 0 1 0 1 0 1 1 0 1 1 0 1 1]
 [1 0 1 0 1 0 1 1 1 1 1 1 0 0 1 1 0 0 0 1]
 [1 0 0 0 0 0 1 1 1 1 1 1 1 0 0 1 0 0 0 1]
 [0 1 0 2 0 0 0 0 1 1 0 0 0 1 0 1 1 0 0 1]
 [0 1 0 0 0 1 0 1 0 1 1 1 0 1 0 1 1 1 1 0]
 [0 1 0 0 0 0 1 1 0 1 1 0 0 1 1 1 1 1 1 1]
 [0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 1 1 0 0 0]
 [3 0 3 0 4 0 0 0 0 0 0 5 0 0 0 1 0 1 1 0]
 [0 3 3 0 4 0 6 0 7 7 0 0 5 0 0 0 0 0 1 1]]

同樣的我們可以看看此時得到的新的圖像:


這里我們并列的畫了三張圖,第一張圖是原圖,第二張圖是劃分好區域和標簽的圖,第三張是對第二張圖進行二元化的結果,以確保在運算過程中沒有丟失原本的信息。經過確認這個標簽的結果劃分是正確的,但是因為涉及到一些算法實現的細節,這里我們還是需要展開來介紹一下。

算法的執行流程

if __name__ == "__main__":
    np.random.seed(1)
    graph = np.random.choice([0,1],size=(20,20))
    graph_1, idx_dict = first_pass(graph)
    idx_dict = remap(idx_dict)
    graph_2 = second_pass(graph_1, idx_dict)
    graph_3 = flatten(graph_2)

這個部分是算法的核心框架,在本文中的算法實現流程為:先用first_pass遍歷一遍網格節點,按照上一個章節中介紹的Two-Pass算法打上標簽,并獲得一個映射關系;然后用remap將上面得到的映射關系做一個重映射,確保每一個級別的映射都對應到了最根部(可以聯系參考鏈接1的內容進行理解,雖然這里沒有使用Union的數據結構,但是本質上還是一個樹形的結構,需要做一個重映射);然后用second_pass執行Two-Pass算法的第二次遍歷,得到一組打上了新的獨立標簽的網格節點;最后需要用flatten將標簽進行壓平,因為前面映射的關系,有可能導致標簽不連續,所以我們這里又做了一次映射,確保標簽是連續變化的,實際應用中可以不使用這一步。

標簽的重映射

關于節點的遍歷,大家可以直接看算法代碼,這里需要額外講解的是標簽的重映射模塊的代碼:

def remap(idx_dict) -> dict:
    index_dict = deepcopy(idx_dict)
    for id in idx_dict:
        idv = idx_dict[id]
        while idv in idx_dict:
            if idv == idx_dict[idv]:
                break
            idv = idx_dict[idv]
        index_dict[id] = idv
    return index_dict

這里的算法是先對得到的標簽進行遍歷,在字典中獲取當前標索引所對應的值,作為新的索引,直到鍵跟值一致為止,相當于在一個樹形的數據結構中重復尋找父節點直到找到根節點。

其他的測試用例

這里我們可以再額外測試一些案例,比如增加幾個0元素使得網格節點更加稀疏:

graph = np.random.choice([0,0,0,1],size=(20,20))

得到的結果圖片如下所示:


還可以再稀疏一些:

graph = np.random.choice([0,0,0,0,0,1],size=(20,20))

得到的結果如下圖所示:


越是稀疏的圖,得到的分組結果就越分散。

總結概要

在本文中我們主要介紹了利用Two-Pass的算法來檢測區域連通性,并給出了Python3的代碼實現,當然在實現的過程中因為沒有使用到Union這樣的數據結構,僅僅用了字典來存儲標簽之間的關系,因此效率和代碼可讀性都會低一些,單純作為用例的演示和小規模區域劃分的計算是足夠用了。在該代碼實現方案中,還有一點與原始算法不一致的是,本實現方案中打新的標簽是讀取上、上左和左三個方向的格點,但是存儲標簽的映射關系時,是讀取了上、上左、上右和左這四個方向的格點。

參考鏈接

  1. https://blog.csdn.net/lichengyu/article/details/13986521
  2. https://www.cnblogs.com/riddick/p/8280883.html

到此這篇關于運用Python3實現Two-Pass算法檢測區域連通性的文章就介紹到這了,更多相關Python3實現Two-Pass算法檢測區域流通內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:
  • Python3基礎語法知識點總結

標簽:林芝 盤錦 海南 南平 普洱 大同 寧夏 漯河

巨人網絡通訊聲明:本文標題《運用Python3實現Two-Pass算法檢測區域連通性》,本文關鍵詞  運用,Python3,實現,Two-Pass,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《運用Python3實現Two-Pass算法檢測區域連通性》相關的同類信息!
  • 本頁收集關于運用Python3實現Two-Pass算法檢測區域連通性的相關信息資訊供網民參考!
  • 推薦文章
    校园春色亚洲色图_亚洲视频分类_中文字幕精品一区二区精品_麻豆一区区三区四区产品精品蜜桃
    另类综合日韩欧美亚洲| 激情深爱一区二区| 国产精品美女视频| 精品国产一区二区三区忘忧草| 色婷婷激情久久| 91麻豆国产精品久久| 91官网在线观看| 欧美亚洲禁片免费| 69p69国产精品| 精品国产伦理网| 中文一区二区在线观看| 国产精品久久久久久一区二区三区| 久久精品一区蜜桃臀影院| 欧美国产精品v| 亚洲四区在线观看| 亚洲成av人片在线观看| 久久精品国产秦先生| 国产毛片精品国产一区二区三区| 粉嫩一区二区三区在线看| eeuss鲁一区二区三区| 欧美三日本三级三级在线播放| 色菇凉天天综合网| 欧美电影一区二区三区| 精品处破学生在线二十三| 国产精品午夜免费| 亚洲成人一区二区在线观看| 老司机免费视频一区二区三区| 国产精品资源站在线| 色综合天天在线| 91精品欧美一区二区三区综合在| 久久精品男人天堂av| 一区二区三区日韩精品| 麻豆国产精品视频| 99综合影院在线| 欧美一区二区三区在线观看视频 | 一区二区三区在线影院| 婷婷丁香激情综合| 国产91丝袜在线18| 欧美精品一级二级三级| 欧美高清在线精品一区| 午夜精品一区二区三区电影天堂 | 欧美成人综合网站| 亚洲三级在线看| 国产在线观看一区二区| 欧美在线免费播放| 国产欧美日韩在线看| 国产欧美日韩精品在线| 天堂在线亚洲视频| av网站一区二区三区| 欧美精品一区二区三区蜜臀 | 日韩av一级片| 91丨九色porny丨蝌蚪| 精品久久久久久久久久久久包黑料| 亚洲男同性恋视频| 成人免费看黄yyy456| 精品美女被调教视频大全网站| 亚洲精选免费视频| av在线不卡网| 国产日韩精品一区| 精品中文字幕一区二区小辣椒 | 欧美一区二区三区免费| 一区二区三区日韩精品视频| 成人激情动漫在线观看| 久久久久久99精品| 美女视频一区二区| 日韩午夜激情视频| 久久机这里只有精品| 制服.丝袜.亚洲.另类.中文| 亚欧色一区w666天堂| 在线视频亚洲一区| 亚洲午夜久久久久久久久久久| jizz一区二区| 怡红院av一区二区三区| 日本久久一区二区三区| 亚洲精品一二三| 一本色道久久综合亚洲91| 亚洲狼人国产精品| 欧美性欧美巨大黑白大战| 亚洲精品欧美专区| 欧美三级乱人伦电影| 亚洲国产成人va在线观看天堂| 欧美视频一区二区三区在线观看| 亚洲综合色视频| 欧美精品电影在线播放| 日本不卡视频一二三区| 欧美成人激情免费网| 久久精品久久精品| 欧美国产精品一区二区| 一本大道久久a久久精品综合| 亚洲乱码精品一二三四区日韩在线| 91丝袜美腿高跟国产极品老师| 亚洲美腿欧美偷拍| 欧美日韩亚洲综合在线| 久久精品国产一区二区三| 久久久精品天堂| 色综合中文字幕国产| 亚洲六月丁香色婷婷综合久久 | 亚洲日本中文字幕区| 色欧美日韩亚洲| 蜜臀久久久久久久| 国产三级精品三级| 欧美在线综合视频| 久久精品久久99精品久久| 国产精品久久久久久户外露出 | 丰满白嫩尤物一区二区| 亚洲黄色av一区| 精品国产伦一区二区三区观看方式| 高清不卡一区二区在线| 亚洲成人激情av| 亚洲日本一区二区三区| 91在线无精精品入口| 五月综合激情网| 久久精品视频免费观看| 欧美最新大片在线看| 国产毛片精品国产一区二区三区| 亚洲色欲色欲www在线观看| 欧美一区二区免费观在线| 国产不卡视频在线观看| 午夜精品爽啪视频| 国产精品午夜在线观看| 欧美成人一区二区三区片免费| av在线一区二区三区| 韩国精品免费视频| 亚洲高清视频的网址| 中文字幕在线不卡一区二区三区| 欧美精品在线视频| 91美女片黄在线观看91美女| 国产原创一区二区| 蜜臀久久久久久久| 一区二区三区在线播放| 国产精品九色蝌蚪自拍| 久久九九全国免费| 日韩一区二区免费在线电影| 欧美性极品少妇| 91在线视频官网| 国产 欧美在线| 国产精品一区二区三区99| 日韩福利电影在线观看| 一区二区三区国产精华| 国产精品理论片在线观看| 久久久久久久综合狠狠综合| 精品久久国产97色综合| 欧美一级专区免费大片| 欧美日韩综合色| 欧美性受xxxx| 欧亚洲嫩模精品一区三区| 91网上在线视频| 在线视频一区二区免费| 欧洲国内综合视频| 精品视频在线视频| 欧美日韩高清一区| 欧美日韩一区二区电影| 欧美无砖砖区免费| 欧美绝品在线观看成人午夜影视| 欧美日免费三级在线| 欧美日韩国产经典色站一区二区三区| 日本高清不卡视频| 欧美伊人精品成人久久综合97| 在线观看国产91| 欧美日本不卡视频| 欧美一区二区三区精品| 日韩欧美亚洲国产精品字幕久久久 | 国产成人av资源| 成人av网址在线| 欧洲一区二区av| 欧美视频一二三区| 欧美大肚乱孕交hd孕妇| www国产成人| 国产精品久久久久久久久久久免费看 | 欧美三级电影网站| 91麻豆精品国产91久久久久久 | 26uuu另类欧美亚洲曰本| 久久精品无码一区二区三区| 一区视频在线播放| 舔着乳尖日韩一区| 国产一区二区三区久久悠悠色av| 成人精品免费网站| 欧美亚洲愉拍一区二区| 日韩一区二区三区视频在线| 久久这里只有精品6| 亚洲精品免费视频| 免费在线欧美视频| 国产成人av网站| 欧美日韩免费一区二区三区视频 | 国产精品嫩草影院com| 亚洲一区电影777| 久久国产三级精品| 色天天综合久久久久综合片| 日韩欧美自拍偷拍| 亚洲人成网站在线| 国内精品久久久久影院一蜜桃| 97久久精品人人澡人人爽| 欧美一区二区人人喊爽| 中文av字幕一区| 美女视频网站黄色亚洲| 色猫猫国产区一区二在线视频| 欧美成人官网二区| 午夜激情综合网| 91片黄在线观看| 日本一区二区三区免费乱视频|