Вопрос по python – Найдите скользящее окно размером 3х3 над изображением

6

У меня есть изображение.

Я хочу получить окно 3х3 (соседние пиксели) для каждого пикселя изображения.

У меня есть этот код Python:

for x in range(2,r-1,1):
    for y in range(2,c-1,1):
        mask5=numpy.array([cv.Get2D(copy_img,x-1,y-1),cv.Get2D(copy_img,x-1,y),cv.Get2D(copy_img,x-1,y+1),cv.Get2D(copy_img,x,y-1),cv.Get2D(copy_img,x,y),cv.Get2D(copy_img,x,y+1),cv.Get2D(copy_img,x+1,y-1),cv.Get2D(copy_img,x+1,y),cv.Get2D(copy_img,x+1,y+1)])
        cent=[cv.Get2D(copy_img,x,y)]

mask5 - окно 3х3. цент - это центральный пиксель.

Есть ли более эффективный способ сделать это - то есть использовать карты, итераторы - что-нибудь кроме двух вложенных циклов, которые я использовал?

Без полного понимания того, что вы делаете, это лучшее, что я могу сделать! :) fraxel
@fraxel: после того, как я получу окно, мне нужно отсортировать пиксели в окне 3x3 по интенсивности и создать другое (одномерное) скользящее окно над этим списком, и на основе сложного условия на средства пикселей в этих (1-d), измените исходный центральный пиксель соответственно. Velvet Ghost
Каково ваше намерение? Вероятно, вы хотите выполнить свертку? Расскажи нам, что ты собираешься делатьmask5тогда мы можем помочь вам лучше, ура. fraxel
@frexel: не совсем. Есть ли способ просто оптимизировать вышеприведенные циклы, как показано - с помощью карт или итераторов - что-нибудь, чтобы избежать использования для циклов? Velvet Ghost
Похоже, вы пытаетесь сделатьadaptive threshold? Посмотрите на это, оно может делать то, что вы хотите. fraxel

Ваш Ответ

3   ответа
2

изменив форму и поменяв местами оси, а затем повторив все элементы ядра, например:

im = np.arange(81).reshape(9,9)
print np.swapaxes(im.reshape(3,3,3,-1),1,2)

Это дает вам массив из 3 * 3 плиток, которые растекаются по поверхности:

[[[[ 0  1  2]   [[ 3  4  5]   [[ 6  7  8]
   [ 9 10 11]    [12 13 14]    [15 16 17]
   [18 19 20]]   [21 22 23]]   [24 25 26]]]

 [[[27 28 29]   [[30 31 32]   [[33 34 35]
   [36 37 38]    [39 40 41]    [42 43 44]
   [45 46 47]]   [48 49 50]]   [51 52 53]]]

 [[[54 55 56]   [[57 58 59]   [[60 61 62]
   [63 64 65]    [66 67 68]    [69 70 71]
   [72 73 74]]   [75 76 77]]   [78 79 80]]]]

Чтобы получить перекрывающиеся тайлы, нам нужно повторить это еще 8 раз, но «оборачивая» массив, используя комбинациюvstack а такжеcolumn_stack. Обратите внимание на то, что правый и нижний массивы мозаики оборачиваются (что может или не может быть тем, что вы хотите, в зависимости от того, как вы обрабатываете краевые условия

im =  np.vstack((im[1:],im[0]))
im =  np.column_stack((im[:,1:],im[:,0]))
print np.swapaxes(im.reshape(3,3,3,-1),1,2)

#Output:
[[[[10 11 12]   [[13 14 15]   [[16 17  9]
   [19 20 21]    [22 23 24]    [25 26 18]
   [28 29 30]]   [31 32 33]]   [34 35 27]]]

 [[[37 38 39]   [[40 41 42]   [[43 44 36]
   [46 47 48]    [49 50 51]    [52 53 45]
   [55 56 57]]   [58 59 60]]   [61 62 54]]]

 [[[64 65 66]   [[67 68 69]   [[70 71 63]
   [73 74 75]    [76 77 78]    [79 80 72]
   [ 1  2  3]]   [ 4  5  6]]   [ 7  8  0]]]]

Делая это таким образом, вы получаете 9 наборов массивов, так что вам нужно затем собрать их вместе. Это и все изменения формы обобщаются на это (для массивов, где размеры делятся на 3):

def new(im):
    rows,cols = im.shape
    final = np.zeros((rows, cols, 3, 3))
    for x in (0,1,2):
        for y in (0,1,2):
            im1 = np.vstack((im[x:],im[:x]))
            im1 = np.column_stack((im1[:,y:],im1[:,:y]))
            final[x::3,y::3] = np.swapaxes(im1.reshape(rows/3,3,cols/3,-1),1,2)
    return final

Сравнение этогоnewункция @ для циклического прохождения всех срезов (ниже), используяtimeit, это примерно в 4 раза быстрее, для массива 300 * 300.

def old(im):
    rows,cols = im.shape
    s = []
    for x in xrange(1,rows):
        for y in xrange(1,cols):
            s.append(im[x-1:x+2,y-1:y+2])
    return s
Благодарность. Мне удалось свести все это к одной короткой строке кода - к сожалению, в MATLAB (функция im2col). Есть ли у этой функции прямой эквивалент в Pytho Velvet Ghost
@ VelvetGhost im2col - это просто функция, которая оборачивает реализациюкак у мен или тот, что выше (хотя и с немного большей полировкой). Реализация MATLAB волшебным образом не удаляет код. Если вы можете использовать свою собственную функцию, тем лучше, поскольку вы не полагаетесь на дорогой набор инструментов для ее работы (такова радость MATLAB). Кроме того, не думайте, что, поскольку он находится в наборе инструментов, он быстрый или эффективный. Henry Gomersall
@ HenryGomersall: Спасибо! Да, я знаю, что MATLAB волшебным образом не удаляет код. Я просто нашел это проще и быстрее, когда пишу код в срок. Большое спасибо за вашу реализацию Python. Это поможет мне узнать больше о Python, когда у меня будет немного времени. Velvet Ghost
Вот вопрос: как мы могли бы изменить этот метод для работы с произвольными (вместо нескольких-3) размерами изображения? Magsol
@ Magsol, я создал какой-то код Cython для "оконного" 3D-объемных изображений, который работает для любого размера окна. Вы можете легко изменить это для работы с 2D-изображениями. Matt Hancock
1

что следующее делает то, что ты после. Цикл только по 9 элементам. Я уверен, что есть способ векторизации, но это, вероятно, не стоит усилий.

import numpy

im = numpy.random.randint(0,50,(5,7))

# idx_2d contains the indices of each position in the array
idx_2d = numpy.mgrid[0:im.shape[0],0:im.shape[1]]

# We break that into 2 sub arrays
x_idx = idx_2d[1]
y_idx = idx_2d[0]

# The mask is used to ignore the edge values (or indeed any values).
mask = numpy.ones(im.shape, dtype='bool')
mask[0, :] = False
mask[:, 0] = False
mask[im.shape[0] - 1, :] = False
mask[:, im.shape[1] - 1] = False

# We create and fill an array that contains the lookup for every
# possible 3x3 array.
idx_array = numpy.zeros((im[mask].size, 3, 3), dtype='int64')

# Compute the flattened indices for each position in the 3x3 grid
for n in range(0, 3):
    for m in range(0, 3):
        # Compute the flattened indices for each position in the 
        # 3x3 grid
        idx = (x_idx + (n-1)) + (y_idx  + (m-1)) * im.shape[1]

        # mask it, and write it to the big array
        idx_array[:, m, n] = idx[mask]


# sub_images contains every valid 3x3 sub image
sub_images = im.ravel()[idx_array]

# Finally, we can flatten and sort each sub array quickly
sorted_sub_images = numpy.sort(sub_images.reshape((idx[mask].size, 9)))
1

Попробуйте следующий код как функцию matlab im2col (...)

import numpy as np

def im2col(Im, block, style='sliding'):
    """block = (patchsize, patchsize)
        first do sliding
    """
    bx, by = block
    Imx, Imy = Im.shape
    Imcol = []
    for j in range(0, Imy):
        for i in range(0, Imx):
            if (i+bx <= Imx) and (j+by <= Imy):
                Imcol.append(Im[i:i+bx, j:j+by].T.reshape(bx*by))
            else:
                break
    return np.asarray(Imcol).T

if __name__ == '__main__':
    Im = np.reshape(range(6*6), (6,6))
    patchsize = 3
    print Im
    out =  im2col(Im, (patchsize, patchsize))
    print out
    print out.shape
    print len(out)

Похожие вопросы