0

I have a 2d-array (28 x 28) that has boolean values.

array([[False, False, False, False, False, False, False, False, False,
        False, False, False, False, False, False, False, False, False,
        False, False, False, False, False, False, False, False, False,
        False],
       [False, False, False, False, False, False, False, False, False,
        False, False, False, False, False, False, False, False, False,
        False, False, False, False, False, False, False, False, False,
        False],
       [False, False, False, False, False, False, False, False, False,
        False, False, False, False, False, False, False, False, False,
        False, False, False, False, False, False, False, False, False,
        False],
       [False, False, False, False, False, False, False, False, False,
        False, False, False, False, False, False, False, False, False,
        False, False, False, False, False, False, False, False, False,
        False],
       [False, False, False, False, False, False, False, False, False,
        False, False, False, False, False, False, False,  True,  True,
         True, False, False, False, False, False, False, False, False,
        False],
       [False, False, False, False, False, False, False, False, False,
        False, False, False, False, False, False,  True,  True,  True,
         True,  True, False, False, False, False, False, False, False,
        False],
       [False, False, False, False, False, False, False, False, False,
        False, False, False, False, False,  True,  True,  True,  True,
         True,  True, False, False, False, False, False, False, False,
        False],
       ...

This represents an image of a digit. In order to stretch this image so that the horizontal and vertical range of ink pixels runs the full horizontal/vertical range of the box.

Below are the steps that I am trying to take:

1. Find the leftmost (x_min) and the rightmost (x_max) pixels that have ink (after thresholding). 
2. Find the topmost (y_min) and bottom-most (y_max) pixels similarly. 
3. Find the centerpoint (x,y) by taking the mean of x_min and x_max and y_min and y_max respectively. 
4. Now, the 20x20 bounding is defined as img[y_center-10 : y_center + 10, x_center-10:x_center+10]

I tried to do Step 1 in a naive way, just iterating all pixels, but I know that is not the best way. What is the best way to find the left and rightmost pixel that is True?

Dawn17
  • 7,825
  • 16
  • 57
  • 118

3 Answers3

0

You can use the function index, which returns the first index of the value you search for:

e.g.

array = ([False, False, True, True, False])
print(array.index(True))

Returns

2

You can reverse the array to find the last one, by adding:

array.reverse();
print(array.index(True))

Which returns

1

However, reverse is very expensive operation for what you need.

Michel Keijzers
  • 15,025
  • 28
  • 93
  • 119
0

Will this work for you? not most efficient, but works. the idea is to remove rows and columns that's all False, so you get your 'cropped' digit.

import pandas as pd

img = np.array([[False, False, False, False, False, False, False, False, False,
        False, False, False, False, False, False, False, False, False,
        False, False, False, False, False, False, False, False, False,
        False],
       [False, False, False, False, False, False, False, False, False,
        False, False, False, False, False, False, False, False, False,
        False, False, False, False, False, False, False, False, False,
        False],
       [False, False, False, False, False, False, False, False, False,
        False, False, False, False, False, False, False, False, False,
        False, False, False, False, False, False, False, False, False,
        False],
       [False, False, False, False, False, False, False, False, False,
        False, False, False, False, False, False, False, False, False,
        False, False, False, False, False, False, False, False, False,
        False],
       [False, False, False, False, False, False, False, False, False,
        False, False, False, False, False, False, False,  True,  True,
         True, False, False, False, False, False, False, False, False,
        False],
       [False, False, False, False, False, False, False, False, False,
        False, False, False, False, False, False,  True,  True,  True,
         True,  True, False, False, False, False, False, False, False,
        False],
       [False, False, False, False, False, False, False, False, False,
        False, False, False, False, False,  True,  True,  True,  True,
         True,  True, False, False, False, False, False, False, False,
        False]])

img = pd.DataFrame(img)
img.replace(False,np.nan, inplace = True)
newimage = img.dropna(axis = 0, how = 'all')
newimage = newimage.dropna(axis = 1, how = 'all')
newimage.T.values
Aiden Zhao
  • 633
  • 4
  • 15
0
array = [[False, False, False, False],
         [False, False, False, False],
         [True , False, False, False],
         [False, False, False, False]]

print('left: ')
print(min([x.index(True) if True in x else 100 for x in array]))

print('right: ')
print(min([x[::-1].index(True) if True in x else 100 for x in array]))

print('top')
print([any(x) for x in array].index(True))

print('bottom')    
print([any(x) for x in array[::-1]].index(True))

prints

left: 
0
right: 
3
top
2
bottom
1

Side notes:

  • I used 100 for left/right in case there is no True at all in a row.
  • If there is a chance for no True value at all in the entire matrix, conditions for top and bottom have to be changed slightly.
  • ::-1 iterates the list in reverse order
  • any checks for the occurrence of a non 0/empty/False value.
  • min checks for the minimum value of a list
  • [...] is called list comprehension in case you want to find more about it

With your values I get:

left:
14
right:
8
top:
4
bottom:
0
Michel Keijzers
  • 15,025
  • 28
  • 93
  • 119