Поиск последовательности в двух массивах Numpy

#python #arrays #algorithm #numpy #sequence

#python #массивы #алгоритм #numpy #последовательность

Вопрос:

У меня есть два массива Numpy, которые содержат индексы максимумов и минимумов из другого массива.

Например, для одного вывода массивы максимумов и минимумов выглядят следующим образом:

 Maxima indices are (array([ 4, 10, 14, 37, 43, 51, 59, 67, 81, 89, 95]),)
Minima indices are (array([ 7, 12, 25, 33, 40, 49, 56, 63, 76, 92]),)
  

Эти индексы берутся из значений интенсивности в строке изображения.

Мне нужно найти, сколько раз максимумы встречаются в четырех позициях индекса между двумя минимумами — другими словами:

 minima   4   maxima   4   minima
  

Как я могу сделать это эффективно на Python? Как я могу сравнить значения индекса в обоих массивах, чтобы найти экземпляры этой последовательности, а затем подсчитать, сколько всего экземпляров?

Большое спасибо за любую помощь.

РЕДАКТИРОВАТЬ: каждый максимум должен находиться в пределах 4 позиций от ближайших минимумов слева и справа. По сути, я пытаюсь определить пунктирную линию внутри изображения на основе значений интенсивности.

Комментарии:

1. Должен ли максимум находиться в пределах 4 позиций от ближайших минимумов слева и справа? Или достаточно, чтобы он находился в пределах 4 позиций от одного минимума?

2. Максимум должен быть в пределах 4 позиций от ближайших минимумов слева и справа — да. Я отредактирую вопрос, чтобы отразить это. Спасибо, что спросили.

3. Хорошо, код в моем ответе должен учитывать это. Это просто делает невозможным односторонний обход.

Ответ №1:

Давайте попробуем.

 import numpy

# create a vector for distances from the nearest leftmost minimum
# img_len is the length of the image row

# first we create an integer vector with 1 at each minimum
b = numpy.zeros(img_len, dtype='int')

# then we create an integer vector for the distances
d = numpy.zeros(img_len, dtype='int')

# we mark leftmost distances up to the first minimum to be largest possible
d[:minima[0]] = minima[0] - numpy.arange(minima[0])

# then we iterate through the vector and calculate the distances
for i in range(len(minima) - 1):
    prev = minima[i]
    next = minima[i 1]
    # now we have a gap between the two minima
    # let's fill it with a triangle 0,1,2,...,2,1,0
    k = (next-prev   1) // 2
    d[prev:prev k 1] = numpy.arange(k 1)
    d[next-k 1:next] = k -1 - numpy.arange(k-1)

# fill in the space after the last minimum:
d[minima[-1]:] = numpy.arange(img_len - minima[-1])

# all maxima whose distance is less than D from the closest minimum
results = [ m for m in maxima if d[m] < D ]
  

Если это не очевидно из кода, идея состоит в том, чтобы создать вектор d , который соответствует расстоянию от ближайшего минимума. Результирующий вектор имеет вид, например, 4,3,2,1,0,1,2,3,2,1,0,1,2,1,0,… где нули соответствуют минимальным позициям. Самое сложное — правильно составить треугольник в цикле. (Надеюсь, я очистил все по отдельности …)

Конечно, теперь вы также можете составить список кортежей для максимальных позиций:

 [ (m, d[m]) for m in maxima ]
  

Для данных в вопросе это возвращает:

 [(4, 3),
 (10, 2),
 (14, 2),
 (37, 3),
 (43, 3),
 (51, 2),
 (59, 3),
 (67, 4),
 (81, 5),
 (89, 3),
 (95, 3)]
  

Код работает, даже если между двумя минимумами имеется более одного максимума, как в вопросе. (Если бы был только один максимум, тогда код был бы почти полностью другим.)

Комментарии:

1. Спасибо за подробный ответ. Я получаю сообщение об ошибке с кодом: d[:minima[0]] = minima[0] — np.arange(minima[0]) — только массивы длиной 1 могут быть преобразованы в скаляры Python. Массив минимумов является результатом minima = argrelextrema(img_row, np.less), где img_row — это массив значений интенсивности пикселей Numpy для горизонтальной линии рассматриваемого изображения. Вы можете помочь?

2. Что говорит ваш python, если вы спросите type(minima[0]) ? И что это говорит для type(minima) and minima.shape и and len(minima) ?

3. type(minima[0]) = <type ‘numpy.ndarray’> type(minima) = <type ‘tuple’> minima.shape = AttributeError: объект ‘tuple’ не имеет атрибута ‘shape’ len(minima) = 1

4. Ага. Попробуйте: minima = argrelexrema(img_row, np.less)[0] (и аналогичный [0] для максимумов). Это потому argrelextrema , что возвращает список выходных данных. Из документа argrelextrema : «Обратите внимание, что возвращаемое значение является кортежем, даже если данные являются одномерными».

5. Пробовал это. Теперь я получаю сообщение об ошибке — results = [ m для m в максимумах, если d[m] < 5 ] ValueError: значение истинности массива с более чем одним элементом неоднозначно. Используйте.any() или.all()

Ответ №2:

Я приведу это в качестве другого ответа, поскольку это совершенно другой метод. Не очень экономичный, но очень короткий код и очень глупый.

 import numpy

# let's assume minima and maxima are 1-d arrays
# then the distance matrix for distances between any maximum to any minimum is:
md = numpy.amin(numpy.abs(maxima[:,None]-minima[None,:]), axis=1)

# the maxima which are at most D pixels away form the closest minima:
cm = maxima[md < D]
  

И, конечно, их можно объединить в однострочный текст, который очень сложно понять.

Краткое объяснение:

  • вычисляется матрица расстояний между всеми минимумами (столбцами) и максимумами (строками) (полная избыточной и нерелевантной информации)
  • абсолютное значение матрицы дает расстояние между каждым максимумом и каждым минимумом
  • кратчайшее расстояние от каждого максимума до любого минимума берется с amin помощью операции вдоль строки
  • cm вычисляется путем индексации максимумов с помощью логического массива (значения, где расстояние ниже предела)

Если векторы длинные, это может замедлиться. Если нет спешки, это простой фрагмент кода.