python - كشف الذروة في مجموعة ثنائية الأبعاد




image-processing (14)

حل

ملف البيانات: paw.txt . مصدر الرمز:

from scipy import *
from operator import itemgetter

n = 5  # how many fingers are we looking for

d = loadtxt("paw.txt")
width, height = d.shape

# Create an array where every element is a sum of 2x2 squares.

fourSums = d[:-1,:-1] + d[1:,:-1] + d[1:,1:] + d[:-1,1:]

# Find positions of the fingers.

# Pair each sum with its position number (from 0 to width*height-1),

pairs = zip(arange(width*height), fourSums.flatten())

# Sort by descending sum value, filter overlapping squares

def drop_overlapping(pairs):
    no_overlaps = []
    def does_not_overlap(p1, p2):
        i1, i2 = p1[0], p2[0]
        r1, col1 = i1 / (width-1), i1 % (width-1)
        r2, col2 = i2 / (width-1), i2 % (width-1)
        return (max(abs(r1-r2),abs(col1-col2)) >= 2)
    for p in pairs:
        if all(map(lambda prev: does_not_overlap(p,prev), no_overlaps)):
            no_overlaps.append(p)
    return no_overlaps

pairs2 = drop_overlapping(sorted(pairs, key=itemgetter(1), reverse=True))

# Take the first n with the heighest values

positions = pairs2[:n]

# Print results

print d, "\n"

for i, val in positions:
    row = i / (width-1)
    column = i % (width-1)
    print "sum = %f @ %d,%d (%d)" % (val, row, column, i)
    print d[row:row+2,column:column+2], "\n"

Output دون تراكب المربعات. يبدو أنه تم اختيار المناطق نفسها كما في المثال الخاص بك.

بعض التعليقات

الجزء الصعب هو حساب مبالغ جميع مربعات 2x2. لقد افترضت أنك بحاجة إلى كل هؤلاء ، لذلك قد يكون هناك بعض التداخل. استخدمت الشرائح لقطع الأعمدة والصفوف الأولى / الأخيرة من الصفيف ثنائي الأبعاد الأصلي ، ثم تراكبتهم معًا وحساب المبالغ.

لفهمه بشكل أفضل ، يمكنك تصوير صفيف 3 × 3:

>>> a = arange(9).reshape(3,3) ; a
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])

ثم يمكنك أخذ شرائحه:

>>> a[:-1,:-1]
array([[0, 1],
       [3, 4]])
>>> a[1:,:-1]
array([[3, 4],
       [6, 7]])
>>> a[:-1,1:]
array([[1, 2],
       [4, 5]])
>>> a[1:,1:]
array([[4, 5],
       [7, 8]])

الآن تخيل أنك تكدس أحدهما فوق الآخر وتجمع العناصر في نفس المواضع. ستكون هذه المبالغ بالضبط نفس المبالغ الموجودة على مربعات 2 × 2 مع الزاوية العلوية اليسرى في نفس الموضع:

>>> sums = a[:-1,:-1] + a[1:,:-1] + a[:-1,1:] + a[1:,1:]; sums
array([[ 8, 12],
       [20, 24]])

عندما يكون لديك مبالغ تزيد على مربعين × 2 ، يمكنك استخدام max للعثور على الحد الأقصى ، أو sort ، أو sorted للعثور على القمم.

لنتذكر مواقف القمم ، فأنا أزواج كل قيمة (المجموع) مع وضعه الترتيبي في مصفوفة مسطحة (انظر zip ). ثم أقوم بحساب موضع الصف / العمود مرة أخرى عند طباعة النتائج.

ملاحظات

سمحت للمربعات 2X2 للتداخل. تعمل النسخة المعدلة على تصفية بعض منها بحيث تظهر المربعات غير المتراكبة فقط في النتائج.

اختيار الأصابع (فكرة)

مشكلة أخرى هي كيفية اختيار ما هو المرجح أن تكون أصابع من جميع القمم. لدي فكرة قد تعمل أو لا تعمل. ليس لدي الوقت الكافي لتطبيقه الآن ، لذلك فقط رمز زائف.

لاحظت أنه إذا بقيت الأصابع الأمامية على دائرة كاملة تقريبًا ، فيجب أن يكون الإصبع الخلفي بداخل تلك الدائرة. أيضا ، الأصابع الأمامية هي أكثر أو أقل متساوية. قد نحاول استخدام هذه الخصائص الكشفية لكشف الأصابع.

رمز زائف:

select the top N finger candidates (not too many, 10 or 12)
consider all possible combinations of 5 out of N (use itertools.combinations)
for each combination of 5 fingers:
    for each finger out of 5:
        fit the best circle to the remaining 4
        => position of the center, radius
        check if the selected finger is inside of the circle
        check if the remaining four are evenly spread
        (for example, consider angles from the center of the circle)
        assign some cost (penalty) to this selection of 4 peaks + a rear finger
        (consider, probably weighted:
             circle fitting error,
             if the rear finger is inside,
             variance in the spreading of the front fingers,
             total intensity of 5 peaks)
choose a combination of 4 peaks + a rear peak with the lowest penalty

هذا هو نهج القوة الغاشمة. إذا كانت N صغيرة نسبيًا ، فأعتقد أنها قابلة للتنفيذ. بالنسبة لـ N = 12 ، هناك تركيبات C_12 ^ 5 = 792 ، وأحيانًا 5 طرق لتحديد إصبع خلفي ، بحيث يتم تقييم 3960 حالة لكل مخلب.

أنا أساعد عيادة بيطرية في قياس الضغط تحت مخلب الكلاب. أستخدم بايثون لتحليل بياناتي ، وأنا الآن عالق في محاولة تقسيم الكفوف إلى مناطق فرعية (تشريحية).

لقد صنعت مصفوفة ثنائية الأبعاد لكل مخلب ، والتي تتكون من القيم القصوى لكل جهاز استشعار تم تحميله بواسطة مخلب مع مرور الوقت. إليك مثالاً على مخلب واحد ، حيث استخدمت برنامج Excel لرسم المناطق التي أريد أن "أكتشفها". هذه هي 2 من 2 صناديق حول أجهزة الاستشعار مع ماكسيما المحلية ، التي لديها معا أكبر مبلغ.

لذلك جربت بعض التجارب وقررت البحث عن الحد الأقصى لكل عمود وعمود (لا يمكن أن ننظر في اتجاه واحد بسبب شكل المخلب). يبدو أن هذا "يكتشف" موقع أصابع منفصلة بشكل جيد إلى حد ما ، ولكنه أيضًا يميز المجسات المجاورة.

إذن ، ما هي أفضل طريقة لإخبار بايثون بأي من هذه الحدود القصوى التي أريدها؟

ملاحظة: لا يمكن أن تتداخل المربعات 2x2 ، حيث يجب أن تكون أصابع منفصلة!

كما أنني أخذت 2X2 كوسيلة راحة ، أي حل أكثر تقدمًا موضع ترحيب ، ولكن أنا ببساطة عالمة حركة بشرية ، لذا فأنا لست مبرمجًا حقيقيًا أو رياضيًا ، لذا يرجى إبقائه بسيطًا.

هنا نسخة يمكن تحميلها مع np.loadtxt

النتائج

لذلك حاولت حل jextee @ (انظر النتائج أدناه). كما ترون ، فإنه يعمل بشكل جيد على الكفوف الأمامية ، لكنه يعمل بشكل جيد بالنسبة للساقين الخلفيتين.

وبشكل أكثر تحديدًا ، لا يمكن التعرف على القمة الصغيرة التي هي إصبع القدم الرابع. ومن الواضح أن هذا متأصل في حقيقة أن الحلقة تبدو أعلى لأسفل نحو أدنى قيمة ، دون الأخذ بعين الاعتبار أين هذا.

هل يمكن لأي شخص معرفة كيفية تعديل خوارزمية jextee @ ، حتى يتمكن من العثور على الإصبع الرابع أيضًا؟

بما أنني لم أجهز أي تجارب أخرى حتى الآن ، لا يمكنني تقديم أي عينات أخرى. لكن البيانات التي قدمتها من قبل كانت متوسطات كل مخلب. هذا الملف عبارة عن مصفوفة تحتوي على بيانات قصوى لـ 9 مخالب بالترتيب الذي أجروه مع اللوحة.

تُظهر هذه الصورة كيف تم توزيعها مكانيًا على اللوحة.

تحديث:

لقد أعددت مدونة لأي شخص مهتم وأعددت SkyDrive مع جميع القياسات الخام. لذلك لأي شخص يطلب المزيد من البيانات: المزيد من القوة لك!

تحديث جديد:

حتى بعد المساعدة التي حصلت عليها مع أسئلتي فيما يتعلق بالكشف عن مخلب وكشف الفرز ، تمكنت أخيرا من التحقق من الكشف عن إصبع القدم لكل مخلب! تبين ، أنه لا يعمل بشكل جيد في أي شيء ولكن الكفوف الحجم مثل واحد في المثال الخاص بي. خارج مسار في بعد فوات الأوان ، انها خطأي الخاص لاختيار 2x2 ذلك تعسفيا.

إليكم مثالاً لطيفاً على أين تسير الأمور بشكل خاطئ: يتم التعرف على مسمار على شكل إصبع القدم و "الكعب" واسع جداً ، يتم التعرف عليه مرتين!

إن حجم المخلب كبير للغاية ، لذا فإن أخذ حجم 2 × 2 بدون أي تداخل ، يؤدي إلى اكتشاف بعض الأصابع مرتين. على العكس ، في الكلاب الصغيرة غالباً ما تفشل في العثور على إصبع قدم خامس ، والذي أظن أنه ناجم عن مساحة 2x2 كونها كبيرة جدًا.

بعد تجربة الحل الحالي على جميع قياساتي ، توصلت إلى نتيجة مذهلة مفادها أنه بالنسبة إلى كل ما عندي من الكلاب الصغيرة ، لم أجد إصبع قدم خامس ، وأنه في أكثر من 50٪ من التأثيرات على الكلاب الكبيرة سيجد المزيد!

من الواضح أنني بحاجة لتغييرها. كان تخميني هو تغيير حجم neighborhood إلى شيء أصغر للكلاب الصغيرة وأكبر للكلاب الكبيرة. لكن generate_binary_structure لن يسمح لي بتغيير حجم الصفيف.

لذلك ، آمل أن يكون لدى أي شخص آخر اقتراح أفضل لتحديد موقع أصابع القدم ، وربما يكون له نطاق منطقة اصبع القدم بحجم الفك؟


أنا متأكد من أن لديك ما يكفي للاستمرار الآن ، ولكن لا يسعني إلا أن أقترح استخدام طريقة التجميع k-means. k-means هي خوارزمية تجميع غير خاضعة للرقابة والتي ستأخذك البيانات (بأي عدد من الأبعاد - أنا أفعل ذلك في 3D) وترتيبها إلى مجموعات k ذات حدود مميزة. من الجميل هنا لأنك تعرف بالضبط عدد أصابع القدم التي يجب أن تحتويها هذه الأنياب.

بالإضافة إلى ذلك ، تم تنفيذه في Scipy وهو لطيف بالفعل ( http://docs.scipy.org/doc/scipy/reference/cluster.vq.html ).

في ما يلي مثال لما يمكن القيام به لحل التجمعات ثلاثية الأبعاد بشكل مكاني:

ما تريد القيام به هو مختلف قليلاً (ثنائي الأبعاد ويتضمن قيم الضغط) ، ولكن ما زلت أعتقد أنه يمكن أن يعطيها لقطة.


حسنًا ، إليك بعض التعليمات البرمجية البسيطة وغير الفعالة ، ولكن بالنسبة إلى هذا الحجم من مجموعة البيانات ، فلا بأس.

import numpy as np
grid = np.array([[0,0,0,0,0,0,0,0,0,0,0,0,0,0],
              [0,0,0,0,0,0,0,0,0.4,0.4,0.4,0,0,0],
              [0,0,0,0,0.4,1.4,1.4,1.8,0.7,0,0,0,0,0],
              [0,0,0,0,0.4,1.4,4,5.4,2.2,0.4,0,0,0,0],
              [0,0,0.7,1.1,0.4,1.1,3.2,3.6,1.1,0,0,0,0,0],
              [0,0.4,2.9,3.6,1.1,0.4,0.7,0.7,0.4,0.4,0,0,0,0],
              [0,0.4,2.5,3.2,1.8,0.7,0.4,0.4,0.4,1.4,0.7,0,0,0],
              [0,0,0.7,3.6,5.8,2.9,1.4,2.2,1.4,1.8,1.1,0,0,0],
              [0,0,1.1,5,6.8,3.2,4,6.1,1.8,0.4,0.4,0,0,0],
              [0,0,0.4,1.1,1.8,1.8,4.3,3.2,0.7,0,0,0,0,0],
              [0,0,0,0,0,0.4,0.7,0.4,0,0,0,0,0,0]])

arr = []
for i in xrange(grid.shape[0] - 1):
    for j in xrange(grid.shape[1] - 1):
        tot = grid[i][j] + grid[i+1][j] + grid[i][j+1] + grid[i+1][j+1]
        arr.append([(i,j),tot])

best = []

arr.sort(key = lambda x: x[1])

for i in xrange(5):
    best.append(arr.pop())
    badpos = set([(best[-1][0][0]+x,best[-1][0][1]+y)
                  for x in [-1,0,1] for y in [-1,0,1] if x != 0 or y != 0])
    for j in xrange(len(arr)-1,-1,-1):
        if arr[j][0] in badpos:
            arr.pop(j)


for item in best:
    print grid[item[0][0]:item[0][0]+2,item[0][1]:item[0][1]+2]

I basically just make an array with the position of the upper-left and the sum of each 2x2 square and sort it by the sum. I then take the 2x2 square with the highest sum out of contention, put it in the best array, and remove all other 2x2 squares that used any part of this just removed 2x2 square.

It seems to work fine except with the last paw (the one with the smallest sum on the far right in your first picture), it turns out that there are two other eligible 2x2 squares with a larger sum (and they have an equal sum to each other). One of them is still selects one square from your 2x2 square, but the other is off to the left. Fortunately, by luck we see to be choosing more of the one that you would want, but this may require some other ideas to be used to get what you actually want all of the time.


حل الفيزيائي:
حدد 5 علامات لتحديد المواقع التي تم تحديدها من خلال مواضع X_i وقم X_i عشوائية. تحديد بعض وظيفة الطاقة التي تجمع بين بعض الجوائز لتحديد موقع العلامات في مواقف الكفوف مع بعض العقوبة للتداخل بين العلامات ؛ دعنا نقول:

E(X_i;S)=-Sum_i(S(X_i))+alfa*Sum_ij (|X_i-Xj|<=2*sqrt(2)?1:0)

( S(X_i) هي القوة المتوسطة في مربع 2x2 حول X_i ، alfa هي معلمة يجب أن تصل إلى ذروتها تجريبياً)

الآن الوقت للقيام ببعض سحر متروبوليس هاستينغز:
1. حدد علامة عشوائية وحركها بمقدار بكسل واحد في اتجاه عشوائي.
2. حساب DE ، الفرق من الطاقة التي تسببت هذه الحركة.
3. الحصول على رقم عشوائي موحد من 0-1 ويسميها ص.
4. إذا كان dE<0 أو exp(-beta*dE)>r ، قم بقبول النقل والانتقال إلى 1 ؛ إذا لم يكن كذلك ، فقم بإلغاء الخطوة والانتقال إلى 1.
يجب تكرار هذا حتى تتقارب علامات إلى الكفوف. يتحكم Beta في المسح لتحسين عملية المقايضة ، لذا يجب أيضًا تحسينه تجريبيًا ؛ يمكن أيضا أن يزداد باستمرار مع وقت المحاكاة (محاكاة الصلب).



شكرا على البيانات الخام. أنا في القطار وهذا هو بقدر ما حصلت (توقف بلدي هو الخروج). لقد قمت بتدليك ملف txt الخاص بك مع regexps وقمت بسحبه إلى صفحة html مع بعض javascript للتصور. أنا أشاركه هنا لأن البعض ، مثلي ، قد يجدون أنه يمكن اختراقه بسهولة أكثر من بايثون.

أعتقد أن المقاربة الجيدة ستكون مقياسًا ودورانًا ثابتًا ، وستكون الخطوة التالية هي التحري عن مزيج من الغاوس. (كل وسادة باو هي مركز غاوسي).

    <html>
<head>
    <script type="text/javascript" src="http://vis.stanford.edu/protovis/protovis-r3.2.js"></script> 
    <script type="text/javascript">
    var heatmap = [[[0,0,0,0,0,0,0,4,4,0,0,0,0],
[0,0,0,0,0,7,14,22,18,7,0,0,0],
[0,0,0,0,11,40,65,43,18,7,0,0,0],
[0,0,0,0,14,61,72,32,7,4,11,14,4],
[0,7,14,11,7,22,25,11,4,14,65,72,14],
[4,29,79,54,14,7,4,11,18,29,79,83,18],
[0,18,54,32,18,43,36,29,61,76,25,18,4],
[0,4,7,7,25,90,79,36,79,90,22,0,0],
[0,0,0,0,11,47,40,14,29,36,7,0,0],
[0,0,0,0,4,7,7,4,4,4,0,0,0]
],[
[0,0,0,4,4,0,0,0,0,0,0,0,0],
[0,0,11,18,18,7,0,0,0,0,0,0,0],
[0,4,29,47,29,7,0,4,4,0,0,0,0],
[0,0,11,29,29,7,7,22,25,7,0,0,0],
[0,0,0,4,4,4,14,61,83,22,0,0,0],
[4,7,4,4,4,4,14,32,25,7,0,0,0],
[4,11,7,14,25,25,47,79,32,4,0,0,0],
[0,4,4,22,58,40,29,86,36,4,0,0,0],
[0,0,0,7,18,14,7,18,7,0,0,0,0],
[0,0,0,0,4,4,0,0,0,0,0,0,0],
],[
[0,0,0,4,11,11,7,4,0,0,0,0,0],
[0,0,0,4,22,36,32,22,11,4,0,0,0],
[4,11,7,4,11,29,54,50,22,4,0,0,0],
[11,58,43,11,4,11,25,22,11,11,18,7,0],
[11,50,43,18,11,4,4,7,18,61,86,29,4],
[0,11,18,54,58,25,32,50,32,47,54,14,0],
[0,0,14,72,76,40,86,101,32,11,7,4,0],
[0,0,4,22,22,18,47,65,18,0,0,0,0],
[0,0,0,0,4,4,7,11,4,0,0,0,0],
],[
[0,0,0,0,4,4,4,0,0,0,0,0,0],
[0,0,0,4,14,14,18,7,0,0,0,0,0],
[0,0,0,4,14,40,54,22,4,0,0,0,0],
[0,7,11,4,11,32,36,11,0,0,0,0,0],
[4,29,36,11,4,7,7,4,4,0,0,0,0],
[4,25,32,18,7,4,4,4,14,7,0,0,0],
[0,7,36,58,29,14,22,14,18,11,0,0,0],
[0,11,50,68,32,40,61,18,4,4,0,0,0],
[0,4,11,18,18,43,32,7,0,0,0,0,0],
[0,0,0,0,4,7,4,0,0,0,0,0,0],
],[
[0,0,0,0,0,0,4,7,4,0,0,0,0],
[0,0,0,0,4,18,25,32,25,7,0,0,0],
[0,0,0,4,18,65,68,29,11,0,0,0,0],
[0,4,4,4,18,65,54,18,4,7,14,11,0],
[4,22,36,14,4,14,11,7,7,29,79,47,7],
[7,54,76,36,18,14,11,36,40,32,72,36,4],
[4,11,18,18,61,79,36,54,97,40,14,7,0],
[0,0,0,11,58,101,40,47,108,50,7,0,0],
[0,0,0,4,11,25,7,11,22,11,0,0,0],
[0,0,0,0,0,4,0,0,0,0,0,0,0],
],[
[0,0,4,7,4,0,0,0,0,0,0,0,0],
[0,0,11,22,14,4,0,4,0,0,0,0,0],
[0,0,7,18,14,4,4,14,18,4,0,0,0],
[0,4,0,4,4,0,4,32,54,18,0,0,0],
[4,11,7,4,7,7,18,29,22,4,0,0,0],
[7,18,7,22,40,25,50,76,25,4,0,0,0],
[0,4,4,22,61,32,25,54,18,0,0,0,0],
[0,0,0,4,11,7,4,11,4,0,0,0,0],
],[
[0,0,0,0,7,14,11,4,0,0,0,0,0],
[0,0,0,4,18,43,50,32,14,4,0,0,0],
[0,4,11,4,7,29,61,65,43,11,0,0,0],
[4,18,54,25,7,11,32,40,25,7,11,4,0],
[4,36,86,40,11,7,7,7,7,25,58,25,4],
[0,7,18,25,65,40,18,25,22,22,47,18,0],
[0,0,4,32,79,47,43,86,54,11,7,4,0],
[0,0,0,14,32,14,25,61,40,7,0,0,0],
[0,0,0,0,4,4,4,11,7,0,0,0,0],
],[
[0,0,0,0,4,7,11,4,0,0,0,0,0],
[0,4,4,0,4,11,18,11,0,0,0,0,0],
[4,11,11,4,0,4,4,4,0,0,0,0,0],
[4,18,14,7,4,0,0,4,7,7,0,0,0],
[0,7,18,29,14,11,11,7,18,18,4,0,0],
[0,11,43,50,29,43,40,11,4,4,0,0,0],
[0,4,18,25,22,54,40,7,0,0,0,0,0],
[0,0,4,4,4,11,7,0,0,0,0,0,0],
],[
[0,0,0,0,0,7,7,7,7,0,0,0,0],
[0,0,0,0,7,32,32,18,4,0,0,0,0],
[0,0,0,0,11,54,40,14,4,4,22,11,0],
[0,7,14,11,4,14,11,4,4,25,94,50,7],
[4,25,65,43,11,7,4,7,22,25,54,36,7],
[0,7,25,22,29,58,32,25,72,61,14,7,0],
[0,0,4,4,40,115,68,29,83,72,11,0,0],
[0,0,0,0,11,29,18,7,18,14,4,0,0],
[0,0,0,0,0,4,0,0,0,0,0,0,0],
]
];
</script>
</head>
<body>
    <script type="text/javascript+protovis">    
    for (var a=0; a < heatmap.length; a++) {
    var w = heatmap[a][0].length,
    h = heatmap[a].length;
var vis = new pv.Panel()
    .width(w * 6)
    .height(h * 6)
    .strokeStyle("#aaa")
    .lineWidth(4)
    .antialias(true);
vis.add(pv.Image)
    .imageWidth(w)
    .imageHeight(h)
    .image(pv.Scale.linear()
        .domain(0, 99, 100)
        .range("#000", "#fff", '#ff0a0a')
        .by(function(i, j) heatmap[a][j][i]));
vis.render();
}
</script>
  </body>
</html>


لقد اكتشفت القمم باستخدام فلتر أقصى محلي . إليك النتيجة في مجموعة البيانات الأولى من 4 كفوف:

أنا أيضا ركض على مجموعة البيانات الثانية من 9 الكفوف وأنها عملت كذلك .

هنا كيف تفعلها:

import numpy as np
from scipy.ndimage.filters import maximum_filter
from scipy.ndimage.morphology import generate_binary_structure, binary_erosion
import matplotlib.pyplot as pp

#for some reason I had to reshape. Numpy ignored the shape header.
paws_data = np.loadtxt("paws.txt").reshape(4,11,14)

#getting a list of images
paws = [p.squeeze() for p in np.vsplit(paws_data,4)]


def detect_peaks(image):
    """
    Takes an image and detect the peaks usingthe local maximum filter.
    Returns a boolean mask of the peaks (i.e. 1 when
    the pixel's value is the neighborhood maximum, 0 otherwise)
    """

    # define an 8-connected neighborhood
    neighborhood = generate_binary_structure(2,2)

    #apply the local maximum filter; all pixel of maximal value 
    #in their neighborhood are set to 1
    local_max = maximum_filter(image, footprint=neighborhood)==image
    #local_max is a mask that contains the peaks we are 
    #looking for, but also the background.
    #In order to isolate the peaks we must remove the background from the mask.

    #we create the mask of the background
    background = (image==0)

    #a little technicality: we must erode the background in order to 
    #successfully subtract it form local_max, otherwise a line will 
    #appear along the background border (artifact of the local maximum filter)
    eroded_background = binary_erosion(background, structure=neighborhood, border_value=1)

    #we obtain the final mask, containing only peaks, 
    #by removing the background from the local_max mask (xor operation)
    detected_peaks = local_max ^ eroded_background

    return detected_peaks


#applying the detection and plotting results
for i, paw in enumerate(paws):
    detected_peaks = detect_peaks(paw)
    pp.subplot(4,2,(2*i+1))
    pp.imshow(paw)
    pp.subplot(4,2,(2*i+2) )
    pp.imshow(detected_peaks)

pp.show()

كل ما عليك القيام به بعد استخدام scipy.ndimage.measurements.label على القناع لتسمية جميع الكائنات المميزة. ثم ستتمكن من اللعب معهم بشكل فردي.

لاحظ أن الطريقة تعمل بشكل جيد لأن الخلفية ليست صاخبة. إذا كان الأمر كذلك ، فستكتشف مجموعة من القمم الأخرى غير المرغوب فيها في الخلفية. عامل مهم آخر هو حجم الحي . ستحتاج إلى تعديلها إذا تغير حجم الذروة (يجب أن تظل متناسبة تقريبًا).


مخطط تقريبي ...

ربما كنت ترغب في استخدام خوارزمية المكونات المتصلة لعزل كل منطقة ببو. ويكي لديه وصف لائق لهذا (مع بعض التعليمات البرمجية) هنا: http://en.wikipedia.org/wiki/Connected_Component_Labeling

سيكون عليك اتخاذ قرار حول ما إذا كنت ستستخدم 4 أو 8 اتصال. شخصيا ، بالنسبة لمعظم المشاكل أنا أفضل 6 - Connectness. على أي حال ، بمجرد أن تفصل كل "مخلب الطباعة" كمنطقة متصلة ، يجب أن يكون الأمر سهلاً بما يكفي للتكرار عبر المنطقة والعثور على الحد الأقصى. بمجرد العثور على الحد الأقصى ، يمكنك تكبير المنطقة بشكل متكرر حتى تصل إلى عتبة محددة سلفا من أجل تحديدها على أنها "إصبع القدم".

مشكلة واحدة دقيقة هنا هي أنه بمجرد بدء استخدام تقنيات رؤية الكمبيوتر للتعرف على شيء ما كمخلب يمين / يسار / أمامي / خلفي وتبدأ في النظر في أصابع القدم الفردية ، يجب عليك البدء في أخذ التناوب ، والخيول ، والترجمات في الاعتبار. يتم تحقيق ذلك من خلال تحليل ما يسمى ب "لحظات". هناك عدة لحظات مختلفة يجب مراعاتها في تطبيقات الرؤية:

لحظات مركزية: ترجمة لحظات طبيعية ثابتة: التحجيم والترجمة لحظات ثابتة: الترجمة والمقياس والدوران الثابت

يمكن العثور على مزيد من المعلومات حول اللحظات من خلال البحث عن "لحظات الصور" على موقع wiki.


هنا فكرة: يمكنك حساب Laplacian (منفصلة) من الصورة. أتوقع أن تكون (سلبيًا) كبيرًا عند الحد الأقصى ، بطريقة أكثر دراماتيكية من الصور الأصلية. وبالتالي ، قد يكون من الأسهل العثور على الحد الأقصى.

إليك فكرة أخرى: إذا كنت تعرف الحجم النموذجي لمناطق الضغط المرتفع ، فيمكنك أولاً تحسين صورتك عن طريق دمجها مع غوسي من نفس الحجم. هذا قد يعطيك صور أبسط للمعالجة.


هيريس طريقة أخرى استخدمتها عند القيام بشيء مماثل لتلسكوب كبير:

1) البحث عن أعلى بكسل. وبمجرد الانتهاء من ذلك ، ابحث عن ذلك للحصول على أفضل ملاءمة لـ 2 × 2 (ربما زيادة مجموع 2x2) ، أو قم بعمل 2 gaussian مناسب داخل المنطقة الفرعية من قول 4x4 متمركزًا على أعلى بكسل.

ثم قم بتعيين تلك البكسلات 2 × 2 التي وجدتها صفر (أو ربما 3x3) حول مركز الذروة

ارجع إلى 1) وكرر حتى تصل أعلى قمة تحت عتبة الضوضاء ، أو لديك جميع أصابع القدم التي تحتاجها


I am not sure this answers the question, but it seems like you can just look for the n highest peaks that don't have neighbors.

Here is the gist. Note that it's in Ruby, but the idea should be clear.

require 'pp'

NUM_PEAKS = 5
NEIGHBOR_DISTANCE = 1

data = [[1,2,3,4,5],
        [2,6,4,4,6],
        [3,6,7,4,3],
       ]

def tuples(matrix)
  tuples = []
  matrix.each_with_index { |row, ri|
    row.each_with_index { |value, ci|
      tuples << [value, ri, ci]
    }
  }
  tuples
end

def neighbor?(t1, t2, distance = 1)
  [1,2].each { |axis|
    return false if (t1[axis] - t2[axis]).abs > distance
  }
  true
end

# convert the matrix into a sorted list of tuples (value, row, col), highest peaks first
sorted = tuples(data).sort_by { |tuple| tuple.first }.reverse

# the list of peaks that don't have neighbors
non_neighboring_peaks = []

sorted.each { |candidate|
  # always take the highest peak
  if non_neighboring_peaks.empty?
    non_neighboring_peaks << candidate
    puts "took the first peak: #{candidate}"
  else
    # check that this candidate doesn't have any accepted neighbors
    is_ok = true
    non_neighboring_peaks.each { |accepted|
      if neighbor?(candidate, accepted, NEIGHBOR_DISTANCE)
        is_ok = false
        break
      end
    }
    if is_ok
      non_neighboring_peaks << candidate
      puts "took #{candidate}"
    else
      puts "denied #{candidate}"
    end
  end
}

pp non_neighboring_peaks

Interesting problem. The solution I would try is the following.

  1. Apply a low pass filter, such as convolution with a 2D gaussian mask. This will give you a bunch of (probably, but not necessarily floating point) values.

  2. Perform a 2D non-maximal suppression using the known approximate radius of each paw pad (or toe).

This should give you the maximal positions without having multiple candidates which are close together. Just to clarify, the radius of the mask in step 1 should also be similar to the radius used in step 2. This radius could be selectable, or the vet could explicitly measure it beforehand (it will vary with age/breed/etc).

Some of the solutions suggested (mean shift, neural nets, and so on) probably will work to some degree, but are overly complicated and probably not ideal.


Maybe a naive approach is sufficient here: Build a list of all 2x2 squares on your plane, order them by their sum (in descending order).

First, select the highest-valued square into your "paw list". Then, iteratively pick 4 of the next-best squares that don't intersect with any of the previously found squares.


What if you proceed step by step: you first locate the global maximum, process if needed the surrounding points given their value, then set the found region to zero, and repeat for the next one.







image-processing