如何在2D numpy数组中找到行?

发布于 2025-02-08 18:41:28 字数 1451 浏览 1 评论 0原文

我有一个 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点距离的线条。

I have a 2D numpy array and I want to find boundary points of both horizontal and vertical lines.

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]], ...]

Here are the lines I want to find:

enter image description here
enter image description here

Later, I want to remove the smaller lines to keep only those with more than 2 points distance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

谁许谁一生繁华 2025-02-15 18:41:28

垂直线:

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]]

vertical lines:

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               #

output:

[[ 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]]

horizontal lines:

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

output:

[[ 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]]
心碎的声音 2025-02-15 18:41:28

这是基于前缀总和的水平线算法:

# 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)

只需更改索引以获取垂直线即可。
您可以使用长度数组来过滤出所需的线。

Here's an algorithm for horizontal lines based on prefix sums:

# 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)

Just change the indexing to get vertical lines.
You can use the lengths array to filter out which lines you want.

来世叙缘 2025-02-15 18:41:28

编辑:收集水平和垂直线,我还减少了我在第一稿中使用的一些多余的比较:当扫描一个方向时,只有右/底端坐标才能更新,而左/顶部则是恒定的,等于当前线段扫描的开始。仍然有一些可以压缩的多余代码。

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]]]

然后,您可以穿越结果列表并计算该距离(或者是指线路的Lenght),并仅将较长的行传输到另一个列表。

EDIT: Collecting both Horizontal and Vertical lines, also I reduced some superfluous comparisons that I used in the first draft: when scanning there is one direction, thus only the right/bottom end coordinates have to be updated, while the left/top are constant, equal to the beginning of the scanning of the current line segment. There is still some superfluous code that can be compressed.

EDIT2: Added the final formatting of the list as in the question.

It finds and lists first the horizontal lines, if the vertical have to come first as in your example output, then just put the second traversal on top.

    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]]]

Then you may traverse the result list and compute that distance (or you mean the lenght of the lines) and transfer only the longer lines to another list.

捶死心动 2025-02-15 18:41:28

这是你想要的吗?

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)

Is this what you want?

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)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文