我有一个二维Numpy数组,其中包含被NaN包围的数据岛。
我希望裁剪数组,使其仅包含边界框和非NaN区域的内容。
我还想知道相对于原始数组的该框的索引和大小。
这个可能吗?
import numpy as np
a = np.empty((15,10))
a.fill(np.nan)
a[7,6] = 76
a[8,5] = 85
a[9,5] = 95
a[9,7] = 97
现在我们有一个15行10列的数组,包含一片数据海洋中的一座小岛:
nan, 76., nan,
85., nan, nan,
95., nan, 97.,
接下来:
nans = np.isnan(a)
nancols = np.all(nans, axis=0) # 10 booleans, True where col is all NAN
nanrows = np.all(nans, axis=1) # 15 booleans
firstcol = nancols.argmin() # 5, the first index where not NAN
firstrow = nanrows.argmin() # 7
lastcol = len(nancols) - nancols[::-1].argmin() # 8, last index where not NAN
lastrow = len(nanrows) - nanrows[::-1].argmin() # 10
a[firstrow:lastrow,firstcol:lastcol]
array([[ nan, 76., nan],
[ 85., nan, nan],
[ 95., nan, 97.]])
import numpy as np
image = np.empty((15,10))
image.fill(np.nan)
image[1,5] = 1
image[2,3:6] = 1
image[3,3:7] = 1
image[4,3:8] = 1
image[5,2:9] = 1
image[6,1:9] = 1
image[7,1:8] = 1
image[8,1:8] = 1
image[9,1:9] = 1
image[10,2:7] = 1
image[11,2:] = 1
image[12,4:6] = 1
print(image)
[[nan nan nan nan nan nan nan nan nan nan]
[nan nan nan nan nan 1. nan nan nan nan]
[nan nan nan 1. 1. 1. nan nan nan nan]
[nan nan nan 1. 1. 1. 1. nan nan nan]
[nan nan nan 1. 1. 1. 1. 1. nan nan]
[nan nan 1. 1. 1. 1. 1. 1. 1. nan]
[nan 1. 1. 1. 1. 1. 1. 1. 1. nan]
[nan 1. 1. 1. 1. 1. 1. 1. nan nan]
[nan 1. 1. 1. 1. 1. 1. 1. nan nan]
[nan 1. 1. 1. 1. 1. 1. 1. 1. nan]
[nan nan 1. 1. 1. 1. 1. nan nan nan]
[nan nan 1. 1. 1. 1. 1. nan nan nan]
[nan nan nan nan 1. 1. nan nan nan nan]
[nan nan nan nan nan nan nan nan nan nan]
[nan nan nan nan nan nan nan nan nan nan]]
nans = np.isnan(image) #Find position al all the NaNs
nancols = np.all(nans, axis=0) # Find all the columns that have only NaNs
nanrows = np.all(nans, axis=1) # Find all the columns that have only NaNs
top_left_x = nancols.argmin() # position of the left most column that does not contain all NaNs
top_left_y = nanrows.argmin() # position of the top most column that does not contain all NaNs
cropped_image = image[:,~nancols][~nanrows] #remove all the rows and columns that are all NaNs
print(cropped_image)
[[nan nan nan nan 1. nan nan nan nan]
[nan nan 1. 1. 1. nan nan nan nan]
[nan nan 1. 1. 1. 1. nan nan nan]
[nan nan 1. 1. 1. 1. 1. nan nan]
[nan 1. 1. 1. 1. 1. 1. 1. nan]
[ 1. 1. 1. 1. 1. 1. 1. 1. nan]
[ 1. 1. 1. 1. 1. 1. 1. nan nan]
[ 1. 1. 1. 1. 1. 1. 1. nan nan]
[ 1. 1. 1. 1. 1. 1. 1. 1. nan]
[nan 1. 1. 1. 1. 1. nan nan nan]
[nan 1. 1. 1. 1. 1. 1. 1. 1.]
[nan nan nan 1. 1. nan nan nan nan]]
while np.any(np.isnan(cropped_image)): #Loop over the image until there a no NaNs left
nans = np.isnan(cropped_image) # Locate all NaNs
nans_in_cols = np.sum(nans,axis=0) # Figure out how many NaNs are in each column
nans_in_rows = np.sum(nans,axis=1) # Figure out how many NaNs are in each row
if np.max(nans_in_cols) > np.max(nans_in_rows): # Remove the column or Row with the most NaNs, if it first row or column of the image, add 1 to the top left x or y coordinate
cropped_image = np.delete(cropped_image, np.argmax(nans_in_cols), 1)
if np.argmax(nans_in_cols) == 0: top_left_x += 1
else:
cropped_image = np.delete(cropped_image, np.argmax(nans_in_rows), 0)
if np.argmax(nans_in_rows) == 0: top_left_y += 1
print(cropped_image, top_left_x,top_left_y)
[[1. 1. 1. 1.]
[1. 1. 1. 1.]
[1. 1. 1. 1.]
[1. 1. 1. 1.]
[1. 1. 1. 1.]
[1. 1. 1. 1.]
[1. 1. 1. 1.]
[1. 1. 1. 1.]
[1. 1. 1. 1.]] 3 3