كاميرا الأحداث GENX320¶
وحدة كاميرا الأحداث GENX320 هي مستشعر رؤية قائم على الأحداث من Prophesee بدقة 320x320 ودقة زمنية بالميكروثانية.
للاطلاع على ورقة البيانات الكاملة والصور ومعلومات الطلب، راجع صفحة منتج كاميرا الأحداث GENX320.
ملاحظة
مدعومة على OpenMV H7 Plus و RT1062 و N6.
أبرز الميزات¶
مستشعر رؤية قائم على الأحداث بدقة 320x320
نطاق ديناميكي 140 dB، بلا تشويش حركة
معدل إخراج مدرج أحداث تكراري بأكثر من 375 Hz
تتناسب الطاقة مع نشاط المشهد — تبدأ من نحو 3 mW
تعمل من أقل من 5 lux حتى ضوء الشمس الساطع دون تعريض تلقائي
تُخرج إطارات تدرج رمادي أو تدفقات أحداث خام
الاستخدام¶
GENX320 هو مستشعر رؤية قائم على الأحداث — فبدلاً من قراءة مصفوفة 320x320 بأكملها على ساعة إطار ثابتة، يبلّغ كل بكسل عن "أحداث" غير متزامنة لحظة اكتشافه تغيراً في السطوع. يحمل كل حدث إحداثي X/Y، وقطبية ON/OFF (من فاتح إلى داكن أو من داكن إلى فاتح)، وطابعاً زمنياً بالميكروثانية. من هنا تأتي الدقة الزمنية بالميكروثانية للمستشعر، وانعدام تشويش الحركة، والنطاق الديناميكي العالي جداً، واستهلاك الطاقة المتناسب مع النشاط. المشاهد الساكنة لا تولّد أي بيانات.
يعرض برنامج OpenMV الثابت المستشعر GENX320 عبر csi.CSI مع cid= csi.GENX320. يتوفر وضعا تشغيل:
وضع المدرج التكراري (الافتراضي) — تُجمَّع الأحداث على الشريحة في صناديق لكل بكسل وتُبلَّغ كإطار تدرج رمادي بدقة 320x320 بمعدل قابل للضبط (نحو 20-350 FPS). يتصرف المستشعر مثل كاميرا عادية، لذا تعمل جميع روتينات معالجة الصور القياسية (
Image.find_blobsواللوحات اللونية وغيرها) مباشرة.وضع الأحداث — تتدفق الأحداث الخام إلى
ndarrayمن numpy مع طوابع زمنية كاملة بالميكروثانية، للتطبيقات التي تحتاج التفصيل الزمني بدلاً من إطار مُجمَّع مسبقاً.
وضع المدرج التكراري¶
في وضع المدرج التكراري، يُخرج GENX320 إطارات تدرج رمادي حيث يرمّز كل بكسل نشاط الأحداث الأخير في ذلك الموضع. البكسلات فوق خط أساس السطوع هي أحداث ON (السطوع يرتفع)، وتلك تحته هي أحداث OFF (السطوع ينخفض). خط أساس السطوع الافتراضي هو 128 وخطوة التباين لكل حدث هي 16 — ارفع التباين لجعل الأحداث تبرز:
import csi
import time
csi0 = csi.CSI(cid=csi.GENX320)
csi0.reset()
csi0.pixformat(csi.GRAYSCALE)
csi0.framesize((320, 320))
csi0.brightness(128) # baseline (default 128)
csi0.contrast(16) # per-event step
csi0.framerate(50) # 20-350 FPS
clock = time.clock()
while True:
clock.tick()
img = csi0.snapshot()
print(clock.fps())
csi.CSI.brightness و csi.CSI.contrast و csi.CSI.framerate هي المقابض الثلاثة التي تشكّل إخراج المدرج التكراري.
الإخراج الملوّن¶
اضبط csi.CSI.color_palette على image.PALETTE_EVT_LIGHT لخلفية فاتحة أو image.PALETTE_EVT_DARK لخلفية داكنة — يُصدر المشغّل إطارات RGB565 باستخدام اللوحة اللونية مباشرة:
csi0.color_palette(image.PALETTE_EVT_LIGHT)
معايرة البكسلات الساخنة¶
تتراكم لدى مستشعرات الأحداث "بكسلات ساخنة" تُطلق إشارات زائفة. شغّل csi.IOCTL_GENX320_CALIBRATE على مشهد ساكن لتعطيلها. يبني المشغّل عدّ إصابات لكل بكسل بدقة 320x320، ويحسب المتوسط والانحراف المعياري، ويعطّل أي بكسل يتجاوز عدّه mean + sigma * stddev — عندئذٍ تتوقف البكسلات المعطّلة عن إصدار أحداث على مستوى المستشعر.
يتحكم في المعايرة معاملان:
event_count— عدد الأحداث المطلوب إحصاؤها قبل حساب الإحصاءات. تلتقط الحلقة الإطارات حتى يتجاوز إجمالي الأحداث الجاري هذه الميزانية. الأعداد الأعلى تعطي تقديراً أكثر موثوقية على حساب زمن معايرة أطول.10000نقطة بداية معقولة.sigma— مضاعِف العتبة على الانحراف المعياري. القيم الأدنى أكثر عدوانية (تعطيل بكسلات أكثر)؛ والقيم الأعلى أكثر تحفظاً.0.5قيمة افتراضية جيدة.
وجّه المستشعر أولاً نحو مشهد ساكن حتى لا تُحتسب أي أحداث ناتجة عن الحركة ضد بكسلات سليمة في الواقع:
csi0.snapshot(time=5000) # let the user steady the camera
disabled = csi0.ioctl(csi.IOCTL_GENX320_CALIBRATE, 10000, 0.5)
print(f"disabled {disabled} hot pixels")
مرشّح مكافحة الوميض (AFK)¶
تولّد مصادر الضوء الدورية (الفلورسنت، الشاشات المُدارة بـ LED) أحجاماً هائلة من الأحداث المتكررة. يرفض مرشّح AFK الأحداث التي يتبدّل فيها البكسل بتردد داخل نطاق معين — فعّله عبر csi.IOCTL_GENX320_SET_AFK مع حدّي النطاق بالهرتز:
csi0.ioctl(csi.IOCTL_GENX320_SET_AFK, 1, 130, 160) # 130-160 Hz
csi0.ioctl(csi.IOCTL_GENX320_SET_AFK, 0) # disable
إعدادات الانحياز المسبقة¶
يشغّل كل بكسل في GenX320 واجهة أمامية تناظرية بعدة انحيازات قابلة للضبط. تحكم هذه الانحيازات مجتمعةً الحساسية والضوضاء وعرض نطاق البكسل ومعدل الأحداث — ويعتمد التوليف الصحيح على المشهد. الانحيازات الفردية هي:
DIFF_ON — عتبة تباين المقارِن الموجبة. يُصدر البكسل حدث ON عندما يرتفع لوغاريتم الإضاءة لديه بهذا المقدار. الأقل = حساسية أعلى للانتقالات الفاتحة.
DIFF_OFF — عتبة تباين المقارِن السالبة (النظير المتماثل لأحداث OFF). الأقل = حساسية أعلى للانتقالات الداكنة.
FO — تردد القطع للترشيح منخفض التمرير في البكسل. الأعلى = عرض نطاق بكسل أوسع (استجابة أسرع، زمن استجابة أقل) لكن مع نشاط ضوضاء خلفية أكبر.
HPF — تردد القطع للترشيح عالي التمرير. الأعلى = رفض أقوى لتغيرات السطوع البطيئة؛ فلا تصل إلى المقارِنات سوى الانتقالات السريعة. مفيد لتجاهل الانحراف المحيطي.
REFR — فترة الخمول. بعد إطلاق البكسل، يبقى في حالة إعادة تعيين لهذه المدة قبل أن يتمكن من الإطلاق مجدداً. الأعلى = زمن خمول أطول، مفيد لتحديد سقف معدل الأحداث لكل بكسل.
بعد csi.CSI.reset يطبّق المشغّل csi.GENX320_BIASES_LOW_NOISE وليس csi.GENX320_BIASES_DEFAULT — فالإعدادات الافتراضية في ورقة البيانات تُصدر معدل أحداث خلفية أعلى بكثير، لذا يُستخدم LOW_NOISE كنقطة بداية لإبقاء التدفق هادئاً. استدعِ csi.IOCTL_GENX320_SET_BIASES بإعداد مسبق مختلف عندما يحتاج التطبيق حساسية أو عرض نطاق أكبر.
يطبّق csi.IOCTL_GENX320_SET_BIASES أحد خمسة إعدادات مسبقة:
csi.GENX320_BIASES_DEFAULT— الإعدادات الافتراضية لورقة بيانات GenX320. حساسية وضوضاء وعرض نطاق متوازنة للمشاهد العامة.csi.GENX320_BIASES_LOW_LIGHT— تُرخى كلتا عتبتي التباين لحساسية أعلى، ويُخفض FO لإبقاء الضوضاء منخفضة، ويُضبط HPF على 0 بحيث تظل تغيرات السطوع البطيئة مسجَّلة — فالمشهد منخفض الإضاءة يولّد قليلاً من الأحداث بمفرده، لذا نريد أن يصل أكبر عدد ممكن منها.csi.GENX320_BIASES_ACTIVE_MARKER— مُولَّف لتتبع مصابيح LED الوامضة عالية التباين. تُرفع عتبات التباين بحيث لا تُطلق سوى الانتقالات الحادة؛ ويُرفع FO و HPF عالياً لتعظيم عرض نطاق البكسل ورفض أي انحراف محيطي بطيء؛ ويُسحب REFR إلى 0 بحيث تُلتقط كل حافة وميض تباعاً. والنتيجة: تدفق يكاد يكون كله حواف LED، سهل التتبع.csi.GENX320_BIASES_LOW_NOISE— الإعداد الافتراضي للمشغّل. تُرفع كلتا عتبتي التباين مقارنةً بـDEFAULT(حساسية أقل) ويُخفض FO (بكسل أبطأ = بكسل أهدأ). الأفضل للمشاهد الساكنة أو البطيئة حيث ستهيمن الأحداث الزائفة لولا ذلك.csi.GENX320_BIASES_HIGH_SPEED— يُرفع FO بحيث يستجيب كل بكسل أسرع، ويُرفع HPF لرفض انحراف السطوع البطيء، ويُرفع REFR بحيث لا تغمر حافة سريعة الحركة عملية القراءة — فزمن الخمول الأطول يبقي حجم الأحداث محدوداً تحت الحركة الكثيفة.
تجاوز الانحيازات الفردية بـ csi.IOCTL_GENX320_SET_BIAS مع أحد csi.GENX320_BIAS_DIFF_ON أو csi.GENX320_BIAS_DIFF_OFF أو csi.GENX320_BIAS_FO أو csi.GENX320_BIAS_HPF أو csi.GENX320_BIAS_REFR وقيمة DAC. يُضبط كل انحياز على حدة — اختر إعداداً مسبقاً كنقطة بداية، ثم عدّل أي انحيازات يحتاجها مشهدك:
csi0.ioctl(csi.IOCTL_GENX320_SET_BIASES, csi.GENX320_BIASES_LOW_LIGHT)
csi0.ioctl(csi.IOCTL_GENX320_SET_BIAS, csi.GENX320_BIAS_HPF, 20)
التتبع¶
بما أن إخراج وضع المدرج التكراري هو مجرد صورة تدرج رمادي، فإن تتبع الكتل العادي يعمل مباشرة. لتتبع مصباح LED كعلامة نشطة، حمّل الإعداد المسبق للانحياز الخاص بالعلامة النشطة وابحث عن الكتل عند الطرف الساطع من المدرج التكراري:
import csi
import time
csi0 = csi.CSI(cid=csi.GENX320)
csi0.reset()
csi0.pixformat(csi.GRAYSCALE)
csi0.framesize((320, 320))
csi0.brightness(128)
csi0.contrast(16)
csi0.framerate(200)
csi0.ioctl(csi.IOCTL_GENX320_SET_BIASES, csi.GENX320_BIASES_ACTIVE_MARKER)
clock = time.clock()
while True:
clock.tick()
img = csi0.snapshot()
for blob in img.find_blobs([(120, 140)], invert=True,
pixels_threshold=2, area_threshold=4,
merge=True):
img.draw_detection(blob)
print(clock.fps())
وضع الأحداث¶
يتجاوز وضع الأحداث المدرج التكراري على الشريحة ويتدفق بالأحداث الخام إلى ndarray من numpy. كل حدث هو صف من ستة أعمدة من نوع uint16:
[0]نوع الحدث — انظر أدناه[1]الطابع الزمني بالثواني[2]الطابع الزمني بالميلي ثانية[3]الطابع الزمني بالميكروثانية[4]إحداثي X، من 0 إلى 319[5]إحداثي Y، من 0 إلى 319
يُصدر المشغّل ستة أنواع أحداث في العمود [0]:
csi.PIX_OFF_EVENT— اكتشف بكسل انخفاضاً في السطوع (تم تجاوز عتبة المقارِنDIFF_OFF). يشير X/Y إلى البكسل الذي أطلق.csi.PIX_ON_EVENT— اكتشف بكسل ارتفاعاً في السطوع (تم تجاوز عتبةDIFF_ON). يشير X/Y إلى البكسل.csi.EXT_TRIGGER_FALLING— رصد دبوس المشغّل الخارجي للمستشعر حافة هابطة. X/Y غير مستخدمين.csi.EXT_TRIGGER_RISING— رصد دبوس المشغّل الخارجي للمستشعر حافة صاعدة. X/Y غير مستخدمين.csi.RST_TRIGGER_FALLING— مشغّل إعادة تعيين البكسل، حافة هابطة. X/Y غير مستخدمين. لا يولّده البرنامج الثابت في الوقت الحالي.csi.RST_TRIGGER_RISING— مشغّل إعادة تعيين البكسل، حافة صاعدة. X/Y غير مستخدمين. لا يولّده البرنامج الثابت في الوقت الحالي.
إدخال المشغّل الخارجي لـ GENX320 موصول بخط مزامنة الإطارات في الكاميرا، وهو موجَّه أيضاً إلى P10 على كل من المعالج وصف الدبابيس — ادفع P10 لحقن حواف المزامنة في تدفق الأحداث والتقاطها كأحداث EXT_TRIGGER_RISING / EXT_TRIGGER_FALLING إلى جانب بيانات البكسل.
تهتم معظم التطبيقات فقط بـ PIX_OFF_EVENT و PIX_ON_EVENT؛ بينما تتيح لك أنواع المشغّل ربط الأحداث بإشارات التوقيت الخارجية.
خصّص مخزن الأحداث المؤقت بالشكل (EVT_res, 6) حيث يكون EVT_res قوة للعدد اثنين بين 1024 و 65536، ثم ادخل وضع الأحداث عبر csi.IOCTL_GENX320_SET_MODE مع csi.GENX320_MODE_EVENT وحجم المخزن المؤقت. اقرأ الأحداث بـ csi.IOCTL_GENX320_READ_EVENTS، الذي يملأ المخزن المؤقت حتى سعته ويعيد عدد الصفوف الصالحة.
يحوّل Image.draw_event_histogram الأحداث إلى صورة تدرج رمادي — فلكل حدث ON يضيف contrast إلى الصندوق؛ ولكل حدث OFF يطرحه. clear=True يعيد ضبط الصورة إلى brightness أولاً؛ و clear=False يراكم عبر استدعاءات متعددة:
import csi
import image
import time
from ulab import numpy as np
img = image.Image(320, 320, image.GRAYSCALE)
events = np.zeros((2048, 6), dtype=np.uint16)
csi0 = csi.CSI(cid=csi.GENX320)
csi0.reset()
csi0.ioctl(csi.IOCTL_GENX320_SET_MODE, csi.GENX320_MODE_EVENT, events.shape[0])
clock = time.clock()
while True:
clock.tick()
n = csi0.ioctl(csi.IOCTL_GENX320_READ_EVENTS, events)
img.draw_event_histogram(events[:n], clear=True, brightness=128, contrast=64)
img.flush()
print(n, clock.fps())
تعمل الإعدادات المسبقة للانحياز الخاصة بوضع المدرج التكراري، ومرشّح AFK، وأوامر ioctl لمعايرة البكسلات الساخنة جميعها بالطريقة نفسها في وضع الأحداث — استدعِها بعد csi.IOCTL_GENX320_SET_MODE.
الترشيح حسب القطبية¶
قطّع مصفوفة الأحداث باستخدام ulab للإبقاء على أحداث ON فقط (الحركة نحو حالة أكثر سطوعاً) أو أحداث OFF فقط:
TARGET = csi.PIX_ON_EVENT # or csi.PIX_OFF_EVENT
events_slice = events[:n]
indices = np.nonzero(events_slice[:, 0] == TARGET)[0]
if len(indices):
target_events = np.take(events_slice, indices, axis=0)
img.draw_event_histogram(target_events, clear=True,
brightness=128, contrast=64)
تراكم التعريض الطويل¶
اضبط clear=False لمواصلة تكديس الأحداث في الصورة نفسها عبر إطارات متعددة — والنتيجة هي تصوّر لأثر الحركة. أعد الضبط دورياً لبدء تعريض جديد:
EXPOSURE_FRAMES = 30
i = 0
while True:
n = csi0.ioctl(csi.IOCTL_GENX320_READ_EVENTS, events)
clear = (i % EXPOSURE_FRAMES) == 0
img.draw_event_histogram(events[:n], clear=clear, brightness=128, contrast=64)
img.flush()
i += 1
المعالجة عالية السرعة¶
أسقط التصوّر لتحرير المعالج لمعالجة الأحداث. اطبع الإحصاءات في كل تكرار رقمه N فقط — فدفع سطر طباعة في كل تكرار يصبح عنق الزجاجة عند معدلات الأحداث العالية:
csi0 = csi.CSI(cid=csi.GENX320)
csi0.reset()
csi0.ioctl(csi.IOCTL_GENX320_SET_MODE, csi.GENX320_MODE_EVENT, events.shape[0])
clock = time.clock()
i = 0
while True:
clock.tick()
n = csi0.ioctl(csi.IOCTL_GENX320_READ_EVENTS, events)
i += 1
if not i % 10:
print(f"{n} events {clock.fps()} fps")
مرشّح التباين المكاني الزماني (STC)¶
تميل حافة التباين المتحركة الحقيقية إلى إطلاق دفقة ضوضائية من الأحداث على البكسل نفسه ضمن نافذة زمنية قصيرة — فعدم تطابق البكسلات والضوضاء التناظرية يولّدان أحداثاً إضافية حول الانتقال الحقيقي لا فائدة منها للتطبيق. مرشّح STC هو معالجة لاحقة على الشريحة تُبقي حدثاً واحداً (أو عدداً قليلاً) لكل دفقة وتُسقط الباقي.
يطبّق ثلاث استراتيجيات، تُختار عبر csi.IOCTL_GENX320_SET_STC وثابت GENX320_STC_*. يُعرَّف كل وضع بالأحداث التي يمرّرها من الدفقة:
الوضع |
يُبقي |
يُسقط |
|---|---|---|
كل حدث |
لا شيء |
|
الحدث الثاني من الدفقة |
الحدث الأول + الأحداث اللاحقة |
|
الحدث الأول من الدفقة |
الأحداث اللاحقة |
|
الحافة الأولى + الحواف اللاحقة |
الضوضاء المتكررة فقط |
بالتفصيل:
csi.GENX320_STC_DISABLE— المرشّح متوقف، كل حدث يمرّ (الافتراضي).csi.GENX320_STC_ONLY— يُبقي على الحدث الثاني من الدفقة. المعامل:stc_threshold(بالميلي ثانية). إذا وصل حدث جديد على بكسل خلالstc_thresholdمن حدث سابق، فيُعتبر "الثاني" من الدفقة ويُمرَّر — ويُرشَّح الحدث الأول وأي أحداث لاحقة في الدفقة نفسها. الأفضل عندما تريد انتقالاً مؤكداً من الضوضاء بدلاً من أول إصابة على الإطلاق.csi.GENX320_STC_TRAIL_ONLY— يُبقي على الحدث الأول من الدفقة. المعامل:trail_threshold(بالميلي ثانية). بعد إطلاق البكسل، تُسقط الأحداث اللاحقة على البكسل نفسه حتى ينقضيtrail_threshold. يحافظ على التوقيت الدقيق للحافة الأمامية — مفيد عندما تكون لحظة تبديل القطبية أهم من تأكيد الدفقة.csi.GENX320_STC_TRAIL— يجمع بين الاثنين. المعاملان:stc_thresholdوtrail_threshold(كلاهما بالميلي ثانية). يُبقي على الحافة الأمامية وفق وضع Trail بالإضافة إلى الحواف اللاحقة وفق وضع STC، بحيث لا تزال أحداث متعددة من الدفقة تمرّ — إنتاجية أحداث أعلى من المرشّحات أحادية الوضع لكن بأغنى إشارة.
يجب أن تبقى العتبتان ضمن نسبة 13:1 تقريباً — فالمستشعر يرفض الإعدادات التي تكون فيها إحداهما أكبر من الأخرى بنحو 13 مرة:
csi0.ioctl(csi.IOCTL_GENX320_SET_STC, csi.GENX320_STC_TRAIL, 1, 2)
csi0.ioctl(csi.IOCTL_GENX320_SET_STC, csi.GENX320_STC_DISABLE)
عمق المخزن المؤقت¶
عندما ترتفع معدلات الأحداث، يفضّل خط أنابيب المخزن المؤقت الثلاثي الافتراضي أحدث إطار ويتخلص من القديمة. ارفع عمق FIFO عبر csi.CSI.framebuffers لإدراج الأحداث في طابور بدلاً من ذلك — على حساب معالجة بيانات أقدم قليلاً عندما يتأخر المضيف:
csi0.framebuffers(10) # FIFO depth, > 3 enables queueing
البث والتصوّر على الحاسوب المكتبي¶
للتصوّر بواجهة رسومية في الوقت الحقيقي على حاسوب مضيف، تقرن أداة بث أحداث GenX320 في مستودع openmv-projects الكاميرا بواجهة DearPyGui. تشغّل الواجهة الرسومية على الحاسوب تصوّرين جنباً إلى جنب: لوحة تراكم الأحداث (الفكرة نفسها كـ Image.draw_event_histogram لكن مع لوحات لونية قابلة للاختيار وأوضاع نافذة منزلقة مقابل المسح التلقائي)، وخريطة تردد لكل بكسل مدفوعة بمرشّح تمرير نطاقي من نوع IIR — مفيدة لرصد الإشارات الدورية (المراوح الدوارة، مصابيح LED الوامضة، وغيرها) مباشرة في تدفق الأحداث.
تأتي معها برنامجان نصيان للبث على الكاميرا:
الوضع المُعالَج (
genx320_event_mode_streaming_on_cam.py) — تفك الكاميرا ترميز الأحداث بـcsi.IOCTL_GENX320_READ_EVENTSوتبث كل صف كـ 12 بايت عبر USB ([0]النوع،[1]الثواني،[2]الميلي ثانية،[3]الميكروثانية،[4]x،[5]y). سهل الاستهلاك على الحاسوب لأن صيغة البث تطابق صيغة ndarray على الكاميرا.الوضع الخام (
genx320_raw_event_mode_streaming_on_cam.py) — تبث الكاميرا كلمات أحداث الشريحة الأصلية المعبّأة بـ 32 بت عبرcsi.IOCTL_GENX320_READ_EVENTS_RAW. وهذا 4 بايت لكل حدث مقابل 12 في الوضع المُعالَج (نحو ثلث البيانات عبر USB)، فيتيح معدل أحداث أعلى بنحو 3 أضعاف عندما يكون الرابط هو عنق الزجاجة. يفك الحاسوب ترميز الكلمات المعبّأة إلى تخطيط الأحداث ذي الأعمدة الستة نفسه باستخدام numpy المتجّه، بحيث يكون كود المصوّر اللاحق متطابقاً.
الوضع الخام هو الافتراضي في الواجهة الرسومية لأن إنتاجية USB هي القيد الحاكم عند المعدلات التي يستطيع GenX320 إنتاجها؛ بدّل إلى الوضع المُعالَج إذا احتجت إدراج منطق معالجة في برنامج الكاميرا النصي.