簡體   English   中英

如何在二維 numpy 數組中查找行?

[英]How to find lines in a 2d numpy array?

我有一個2D numpy 數組,我想找到水平線和垂直線的邊界點

gray_img = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0],
                     [0, 255, 255, 255, 255, 255, 255, 255, 0],
                     [0, 255, 255, 255, 255, 255, 255, 255, 0],
                     [0, 255, 255, 0, 0, 0, 0, 0, 0],
                     [0, 255, 255, 0, 0, 0, 0, 0, 0],
                     [0, 255, 255, 0, 0, 0, 0, 0, 0],
                     [0, 255, 255, 0, 0, 255, 255, 255, 255],
                     [0, 255, 255, 0, 0, 255, 255, 255, 255],
                     [0, 255, 255, 0, 0, 0, 0, 0, 0],
                     [0, 255, 255, 0, 0, 0, 0, 0, 0],
                     [0, 255, 255, 0, 0, 0, 0, 0, 0],
                     [0, 0, 0, 0, 0, 0, 0, 0, 0],
                     [0, 0, 0, 0, 0, 0, 0, 0, 0],
                     [0, 0, 0, 0, 0, 0, 0, 0, 0],
                     [0, 0, 0, 0, 0, 0, 0, 0, 0]])

desired_outcome = [ [[1,1],[10,1]],
                    [[1,2],[10,2]],
                    [[1,3],[2,3]], ...]

這是我要查找的行

在此處輸入圖像描述 在此處輸入圖像描述

稍后,我想刪除較小的線以僅保留那些距離超過 2 點的線。

垂直線:

m = np.diff(gray_img, 1, 0) # get discrete difference along the 0-axis
m = np.argwhere(m != 0)     # get indices where value is not zero 
m = m[np.lexsort(m.T)]      # sort indices first 1-column then 0-column
m[::2,0] += 1               #

輸出:

[[ 1  1]
 [10  1]
 [ 1  2]
 [10  2]
 [ 1  3]
 [ 2  3]
 [ 1  4]
 [ 2  4]
 [ 1  5]
 [ 2  5]
 [ 6  5]
 [ 7  5]
 [ 1  6]
 [ 2  6]
 [ 6  6]
 [ 7  6]
 [ 1  7]
 [ 2  7]
 [ 6  7]
 [ 7  7]
 [ 6  8]
 [ 7  8]]

水平線:

m = np.diff(gray_img, 1, 1, append=np.zeros((gray_img.shape[0], 1)))
m = np.argwhere(m != 0)
m[::2,1] += 1

輸出:

[[ 1  1]
 [ 1  7]
 [ 2  1]
 [ 2  7]
 [ 3  1]
 [ 3  2]
 [ 4  1]
 [ 4  2]
 [ 5  1]
 [ 5  2]
 [ 6  1]
 [ 6  2]
 [ 6  5]
 [ 6  8]
 [ 7  1]
 [ 7  2]
 [ 7  5]
 [ 7  8]
 [ 8  1]
 [ 8  2]
 [ 9  1]
 [ 9  2]
 [10  1]
 [10  2]]

這是基於前綴和的水平線算法:

# Do a prefix sum to get the lengths of each line.
gray_cumsum = np.cumsum(gray_img / 255, axis=1)
gray_cumsum[:, 1:] = gray_cumsum[:, 1:] * (gray_cumsum[:, 1:] != gray_cumsum[:, :-1])
# Reindex all the points so each line starts at 1.
start_num = gray_cumsum.copy()
a = start_num[:,1:-1] != 0
b = start_num[:,:-2] == 0
c = start_num[:,2:] != 0
start_num[:,1:-1] = start_num[:,1:-1] * np.logical_and(np.logical_and(a, b), c)
start_num[:, -1] = 0
start_num = np.maximum.accumulate(start_num, axis=1)
gray_cumsum = np.maximum(gray_cumsum - start_num, 0)
# Detect only the ends of each line.
gray_cumsum[:,:-1] = gray_cumsum[:,:-1] * (gray_cumsum[:,1:] == 0)
# Get the starting and endings points of each line.
end_points = np.stack(gray_cumsum.nonzero(), axis=-1)
lengths = gray_cumsum[gray_cumsum.nonzero()]
start_points = end_points.copy()
start_points[:, 1] = start_points[:, 1] - lengths
print(start_points)
print(end_points)

只需更改索引即可獲得垂直線。 您可以使用長度數組來過濾掉您想要的行。

編輯:收集水平線和垂直線,我還減少了我在第一稿中使用的一些多余的比較:掃描時有一個方向,因此只需要更新右/下端坐標,而左/上是​​恆定的,等於開始掃描當前線段。 還有一些多余的代碼可以壓縮。

EDIT2:添加了問題中列表的最終格式。

它首先查找並列出水平線,如果在您的示例輸出中必須首先出現垂直線,那么只需將第二個遍歷放在頂部。

    import numpy as np
                
    gray_img = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0],
                                     [0, 255, 255, 255, 255, 255, 255, 255, 0],
                                     [0, 255, 255, 255, 255, 255, 255, 255, 0],
                                     [0, 255, 255, 0, 0, 0, 0, 0, 0],
                                     [0, 255, 255, 0, 0, 0, 0, 0, 0],
                                     [0, 255, 255, 0, 0, 0, 0, 0, 0],
                                     [0, 255, 255, 0, 0, 255, 255, 255, 255],
                                     [0, 255, 255, 0, 0, 255, 255, 255, 255],
                                     [0, 255, 255, 0, 0, 0, 0, 0, 0],
                                     [0, 255, 255, 0, 0, 0, 0, 0, 0],
                                     [0, 255, 255, 0, 0, 0, 0, 0, 0],
                                     [0, 0, 0, 0, 0, 0, 0, 0, 0],
                                     [0, 0, 0, 0, 0, 0, 0, 0, 0],
                                     [0, 0, 0, 0, 0, 0, 0, 0, 0],
                                     [0, 0, 0, 0, 0, 0, 0, 0, 0]])
                
    bounds = []
    a = gray_img

    #SCANNING HORIZONTAL LINES
    for y in range(0,a.shape[0]):
      print("\nY=",y)  
      found = False #set to True when scanning a line
      left_x, right_x = 0,0
      top_y = y; bottom_y = y
      if a[y,0]==255:
        top_y = min(top_y, y)
        bottom_y = max(bottom_y,y)     
        found = True
      for x in range(0,a.shape[1]): #
        #while x < len(a[1]) or x!==0 #...
         if a[y,x]==255 and not found: #first item
           found = True
           right_x = x
           left_x = x
           #right_x = max(right_x, x)     
           #left_x = x # min(left_x, x)
           print("START",top_y, bottom_y, left_x, right_x)
         else:
           if a[y,x]==255 and found: #running line       
             right_x = max(right_x, x)     
             #left_x = min(left_x, x)
             #print(top_y, bottom_y, left_x, right_x)
         if a[y,x]==0 and found: #end of a running line
            bounds.append([top_y, left_x, bottom_y, right_x])
            print(a[y,x],end=",")
            found = False
      if found: #end of a running line matches the end of the dimension/line
         bounds.append([top_y, left_x, bottom_y, right_x])
         print(a[y,x],end=",")
         found = False                                       
    print("\n")
    print(bounds)
    print(a.shape)
    #print(f"LEN= {a.shape[0])}, {a.shape[1])}")  
    
    #SCANNING VERTICAL LINES
    for x in range(0,a.shape[1]):
      print("\nY=",y)  
      found = False #set to True when scanning a line
      left_x, right_x = x,x
      top_y = 0; bottom_y = 0
      if a[0,x]==255:
        top_y = min(top_y, y)
        bottom_y = max(bottom_y,y)     
        found = True
      for y in range(0,a.shape[0]): #
        #while x < len(a[1]) or x!==0 #...
         if a[y,x]==255 and not found: #first item
           found = True
           #right_x = max(right_x, x)     
           bottom_y = y       
           top_y = y
           left_x = x # min(left_x, x)
           print("START",top_y, bottom_y, left_x, right_x)
         else:
           if a[y,x]==255 and found: #running line       
             bottom_y = y #max(right_x, x)     
             #top_y = min(left_x, x)
             #print(top_y, bottom_y, left_x, right_x)
         if a[y,x]==0 and found: #end of a running line
            bounds.append([top_y, left_x, bottom_y, right_x])
            print(a[y,x],end=",")
            found = False
      if found: #end of a running line matches the end of the dimension/line
         bounds.append([top_y, left_x, bottom_y, right_x])
         print(a[y,x],end=",")
         found = False                                       
    print("\n")
    print(bounds)
    print(a.shape)   

# [[1, 1, 1, 7], [2, 1, 2, 7], [3, 1, 3, 2], [4, 1, 4, 2], [5, 1, 5, 2], [6, 1, 6, 2], [6, 5, 6, 8], [7, 1, 7, 2], [7, 5, 7, 8], [8, 1, 8, 2], [9, 1, 9, 2], [10, 1, 10, 2], [1, 1, 10, 1], [1, 2, 10, 2], [1, 3, 2, 3], [1, 4, 2, 4], [1, 5, 2, 5], [6, 5, 7, 5], [1, 6, 2, 6], [6, 6, 7, 6], [1, 7, 2, 7], [6, 7, 7, 7], [6, 8, 7, 8]]
#(15, 9)

#This list has to be additionally traversed in order to form [ [[1,1][1,7]], [...]] e.g.:

fm = []
for i in bounds:
  #i=[1,1,1,7] etc.
  f = [[i[0],i[1]],[i[2],i[3]]]
  fm.append(f)

print(fm) 

[[[1, 1], [1, 7]], [[2, 1], [2, 7]], [[3, 1], [3, 2]], [[4, 1], [4, 2]], [[5, 1], [5, 2]], [[6, 1], [6, 2]], [[6, 5], [6, 8]], [[7, 1], [7, 2]], [[7, 5], [7, 8]], [[8, 1], [8, 2]], [[9, 1], [9, 2]], [[10, 1], [10, 2]], [[1, 1], [10, 1]], [[1, 2], [10, 2]], [[1, 3], [2, 3]], [[1, 4], [2, 4]], [[1, 5], [2, 5]], [[6, 5], [7, 5]], [[1, 6], [2, 6]], [[6, 6], [7, 6]], [[1, 7], [2, 7]], [[6, 7], [7, 7]], [[6, 8], [7, 8]]]

然后您可以遍歷結果列表並計算該距離(或者您的意思是線的長度)並僅將較長的線傳輸到另一個列表。

這是你想要的嗎?

import pandas as pd
import numpy as np

a = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0],
                     [0, 255, 255, 255, 255, 255, 255, 255, 0],
                     [0, 255, 255, 255, 255, 255, 255, 255, 0],
                     [0, 255, 255, 0, 0, 0, 0, 0, 0],
                     [0, 255, 255, 0, 0, 0, 0, 0, 0],
                     [0, 255, 255, 0, 0, 0, 0, 0, 0],
                     [0, 255, 255, 0, 0, 255, 255, 255, 255],
                     [0, 255, 255, 0, 0, 255, 255, 255, 255],
                     [0, 255, 255, 0, 0, 0, 0, 0, 0],
                     [0, 255, 255, 0, 0, 0, 0, 0, 0],
                     [0, 255, 255, 0, 0, 0, 0, 0, 0],
                     [0, 0, 0, 0, 0, 0, 0, 0, 0],
                     [0, 0, 0, 0, 0, 0, 0, 0, 0],
                     [0, 0, 0, 0, 0, 0, 0, 0, 0],
                     [0, 0, 0, 0, 0, 0, 0, 0, 0]])

a = a[a != 0]
list = a.tolist()
print(list)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM