يمنح إطار عمل MediaPipe Python الوصول المباشر إلى المكونات الأساسية إطار عمل MediaPipe C++ مثل الطابع الزمني والحزمة وCalculatorGraph، في حين أن حلول بايثون الجاهزة للاستخدام تخفي التفاصيل الفنية لإطار العمل وعرض النموذج القابل للقراءة ببساطة نتائج الاستنتاج إلى المتصلين.
يرتكز إطار عمل MediaPipe على مكتبة pybind11. يتعرض إطار العمل الأساسي C++ في بايثون من خلال ربط لغة C++/Python. يفترض المحتوى أدناه أن القارئ لديه بالفعل فهم أساسي إطار عمل MediaPipe C++. خلاف ذلك، يمكنك العثور على معلومات مفيدة في مفاهيم إطار العمل:
الحزمة
الحزمة هي وحدة تدفق البيانات الأساسية في MediaPipe. تتكون الحزمة من
طابع زمني رقمي ومؤشر مشترك يشير إلى حمولة غير قابلة للتغيير في بايثون،
يمكن إنشاء حزمة MediaPipe من خلال استدعاء إحدى طرق إنشاء الحزم في
الـ
mp.packet_creator
واحدة. وفي المقابل، يمكن استرداد حمولة الحزمة باستخدام أحد
طرق الحصول على حزم البيانات في
mp.packet_getter
واحدة. تجدر الإشارة إلى أنّ حمولة الحزمة تصبح غير قابلة للتغيير بعد إضافة الحزمة
الإنشاء. وبالتالي، لا يؤثر تعديل محتوى الحزمة المستردة في
الحمولة الفعلية في الحزمة. تتيح واجهة Python API الخاصة بإطار عمل MediaPipe
أنواع البيانات الأكثر استخدامًا من MediaPipe (على سبيل المثال، إطار الصورة، المصفوفة، بروتوكول
الموارد الاحتياطية وأنواع البيانات الأولية) في الربط الأساسي. خريطة الموقع الشاملة
في الجدول أدناه، تعيينات الأنواع بين نوعي بيانات Python وC++
بالإضافة إلى منشئ الحزمة وطريقة الحصول على المحتوى لكل نوع بيانات
التي تتوافق معها واجهة برمجة تطبيقات إطار عمل MediaPipe Python.
نوع بيانات Python | نوع بيانات C++ | أداة إنشاء حِزم البيانات | منشئ المحتوى |
---|---|---|---|
قيمة منطقية | قيمة منطقية | create_bool(True) | get_bool(packet) |
int أو np.intc | int_t | create_int(1) | get_int(packet) |
int أو np.int8 | int8_t | create_int8(2**7-1) | get_int(packet) |
int أو np.int16 | int16_t | create_int16(2**15-1) | get_int(packet) |
int أو np.int32 | int32_t | create_int32(2**31-1) | get_int(packet) |
int أو np.int64 | int64_t | create_int64(2**63-1) | get_int(packet) |
int أو np.uint8 | uint8_t | create_uint8(2**8-1) | get_uint(packet) |
int أو np.uint16 | uint16_t | create_uint16(2**16-1) | get_uint(packet) |
int أو np.uint32 | uint32_t | create_uint32(2**32-1) | get_uint(packet) |
int أو np.uint64 | uint64_t | create_uint64(2**64-1) | get_uint(packet) |
float أو np.float32 | عدد عائم | create_float(1.1) | get_float(packet) |
float أو np.double | مزدوج | create_double(1.1) | get_float(packet) |
str (UTF-8) | std::string | create_string('abc') | get_str(packet) |
بايت | std::string | create_string(b'\xd0\xd0\xd0') | get_bytes(packet) |
mp.Packet | mp::Packet | create_packet(p) | get_packet(packet) |
القائمة[قيمة منطقية] | std::ect<bool> | create_bool_ موسيقية([صحيح, خطأ]) | get_bool_list(packet) |
List[int] أو List[np.intc] | int[] | create_int_array([1, 2, 3]) | get_int_list(packet, size=10) |
List[int] أو List[np.intc] | std::ect<int> | create_int_vector([1, 2, 3]) | get_int_list(packet) |
List[float] أو List[np.float] | float[] | create_float_arrary([0.1, 0.2]) | get_float_list(packet, size=10) |
List[float] أو List[np.float] | std::vector<float> | create_float_ect([0.1, 0.2]) | get_float_list(packet, size=10) |
القائمة[str] | std::ect<std::string> | إنشاء_سلسلة_متّجه(['a']) | get_str_list(packet) |
القائمة[mp.Packet] | std::vector<mp::Packet> | create_packet_ للحفاظ على النشاط( ) [packet1, package2]) |
get_packet_list(p) |
تصميم الخرائط[str, Packet] | std::map<std::string, package=""></std::string,> | create_string_to_packet_map( {'a': packet1, 'b': packet2}) |
get_str_to_packet_dict(packet) |
np.ndarray (cv.mat وPIL.Image) |
mp::ImageFrame | create_image_frame( format=ImageFormat.SRGB, data=mat) |
get_image_frame(packet) |
np.ndarray | mp::Matrix | create_matrix(data) | get_matrix(packet) |
رسالة Proto من Google | رسالة Proto من Google | create_proto(proto) | get_proto(packet) |
القائمة [Proto] | std::ect<Proto> | timing fixed in amara | get_proto_list(packet) |
من الشائع أن ينشئ المستخدمون فئات C++ مخصصة ويرسلونها إلى الرسوم البيانية والآلات الحاسبة. للسماح باستخدام الفئات المخصصة في بايثون باستخدام إطار عمل MediaPipe، يمكنك توسيع واجهة برمجة تطبيقات الحزم لنوع جديد من البيانات الخطوات التالية:
كتابة pybind11 رمز ربط الصف أو عجلة هيكلية مخصّصة للنوع المخصص في ملف نسخة إلى.
#include "path/to/my_type/header/file.h" #include "pybind11/pybind11.h" namespace py = pybind11; PYBIND11_MODULE(my_type_binding, m) { // Write binding code or a custom type caster for MyType. py::class_<MyType>(m, "MyType") .def(py::init<>()) .def(...); }
إنشاء منشئ حزم جديد وطريقة الحصول على النوع المخصص في ملف cc منفصل.
#include "path/to/my_type/header/file.h" #include "mediapipe/framework/packet.h" #include "pybind11/pybind11.h" namespace mediapipe { namespace py = pybind11; PYBIND11_MODULE(my_packet_methods, m) { m.def( "create_my_type", [](const MyType& my_type) { return MakePacket<MyType>(my_type); }); m.def( "get_my_type", [](const Packet& packet) { if(!packet.ValidateAsType<MyType>().ok()) { PyErr_SetString(PyExc_ValueError, "Packet data type mismatch."); return py::error_already_set(); } return packet.Get<MyType>(); }); } } // namespace mediapipe
إضافة قاعدتَي إصدار من البازل لربط النوع المخصّص والحزمة الجديدة في ملف BUILD.
load("@pybind11_bazel//:build_defs.bzl", "pybind_extension") pybind_extension( name = "my_type_binding", srcs = ["my_type_binding.cc"], deps = [":my_type"], ) pybind_extension( name = "my_packet_methods", srcs = ["my_packet_methods.cc"], deps = [ ":my_type", "//mediapipe/framework:packet" ], )
أنشِئ أهداف إضافة pybind (مع اللاحقة .so) من Bazel وانقل المكتبات الديناميكية التي تم إنشاؤها إلى إحدى البرامج $LD_LIBRARY_PATH.
استخدم وحدات الربط في بايثون.
import my_type_binding import my_packet_methods packet = my_packet_methods.create_my_type(my_type_binding.MyType()) my_type = my_packet_methods.get_my_type(packet)
الطابع الزمني
تحتوي كل حزمة على طابع زمني بوحدات الميكرو ثانية. في لغة بايثون،
توفر واجهة برمجة تطبيقات الحزم طريقة ملائمة packet.at()
لتعريف القيم الرقمية
الطابع الزمني للحزمة. بشكل عام، packet.timestamp
هي فئة الحزمة
للوصول إلى الطابع الزمني الأساسي. لتحويل حقبة يونكس إلى
الطابع الزمني لـ MediaPipe،
واجهة برمجة التطبيقات للطابع الزمني
توفر الطريقة mp.Timestamp.from_seconds()
لهذا الغرض.
ImageFrame
ImageFrame هو حاوية لتخزين صورة أو إطار فيديو. التنسيقات
التي يدعمها ImageFrame مُدرجة في
تعداد ImageFormat.
تكون وحدات البكسل مشفرة بشكل رئيسي مع عناصر ألوان متداخلة وImageFrame
تدعم uint8 وuint16 وfloat كأنواع بيانات لها. يوفّر MediaPipe
واجهة برمجة تطبيقات ImageFrame Python
للوصول إلى فئة ImageFrame C++. في بايثون، تعد أسهل طريقة لاسترداد
بيانات pixel هي الاتصال بـ image_frame.numpy_view()
للحصول على مكتبة numpy ndarray. ملاحظة
أن numpy ndarray المعروضة، إشارة إلى بيانات البكسل الداخلية،
وغير قابل للكتابة. إذا احتاج المتصلون إلى تعديل numpy ndarray، يجب
بعملية النسخ للحصول على نسخة بشكل صريح. عندما يأخذ MediaPipe numpy
لإنشاء ImageFrame، يفترض أن يتم تخزين البيانات بشكل متبادل.
وفي المقابل، ستتم إعادة محاذاة بيانات البكسل لإطار ImageFrame لتكون
متجاورة عند إعادتها إلى جانب بايثون.
رسم بياني للدالة
في إطار عمل MediaPipe، تتم جميع عمليات المعالجة في سياق عملية الرسم البياني للآلة الحاسبة. واجهة برمجة تطبيقات CalculatorGraph Python هو ربط مباشر بفئة C++ CalculatorGraph. الاختلاف الرئيسي هو تعرض واجهة برمجة تطبيقات CalculatorGraph Python خطأ Python بدلاً من عرض حالة غير جيدة عند حدوث خطأ. وبالتالي، وبصفتك مستخدم بايثون، يمكنك التعامل مع الاستثناءات كما تفعل عادةً. تحتوي دورة حياة الرسم البياني للآلة الحاسبة على ثلاث مراحل: الإعداد والإعداد، وتشغيل الرسم البياني، وإيقاف الرسم البياني.
إعداد CalculatorGraph باستخدام النموذج الأوّلي للأداة CalculatorGraphConfig أو البرنامج الثنائي وتوفير طرق معاودة الاتصال لمراقبة الناتج مصادر البيانات
الخيار رقم 1. إعداد CalculatorGraph باستخدام النموذج الأوّلي للأداة CalculatorGraphConfig أو تمثيله النصي، ومراقبة مصادر الإخراج:
import mediapipe as mp config_text = """ input_stream: 'in_stream' output_stream: 'out_stream' node { calculator: 'PassThroughCalculator' input_stream: 'in_stream' output_stream: 'out_stream' } """ graph = mp.CalculatorGraph(graph_config=config_text) output_packets = [] graph.observe_output_stream( 'out_stream', lambda stream_name, packet: output_packets.append(mp.packet_getter.get_str(packet)))
الخيار رقم 2. تهيئة الرسم البياني للآلة الحاسبة باستخدام ملف نموذج أولي ثنائي مراقبة مصادر الإخراج.
import mediapipe as mp # resources dependency graph = mp.CalculatorGraph( binary_graph=os.path.join( resources.GetRunfilesDir(), 'path/to/your/graph.binarypb')) graph.observe_output_stream( 'out_stream', lambda stream_name, packet: print(f'Get {packet} from {stream_name}'))
ابدأ تنفيذ الرسم البياني وحزم الخلاصة في الرسم البياني.
graph.start_run() graph.add_packet_to_input_stream( 'in_stream', mp.packet_creator.create_string('abc').at(0)) rgb_img = cv2.cvtColor(cv2.imread('/path/to/your/image.png'), cv2.COLOR_BGR2RGB) graph.add_packet_to_input_stream( 'in_stream', mp.packet_creator.create_image_frame(image_format=mp.ImageFormat.SRGB, data=rgb_img).at(1))
إغلاق الرسم البياني بعد الانتهاء يمكنك إعادة تشغيل الرسم البياني لرسم بياني آخر يتم التنفيذ بعد الاتصال بـ
close()
.graph.close()
يمكن تشغيل نص Python البرمجي من خلال بيئة تشغيل Python المحلية.