#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)
andminima.shape
и andlen(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
вычисляется путем индексации максимумов с помощью логического массива (значения, где расстояние ниже предела)
Если векторы длинные, это может замедлиться. Если нет спешки, это простой фрагмент кода.