মিডিয়াপাইপ পাইথন ফ্রেমওয়ার্ক মিডিয়াপাইপ সি++ ফ্রেমওয়ার্কের মূল উপাদান যেমন টাইমস্ট্যাম্প, প্যাকেট এবং ক্যালকুলেটরগ্রাফে সরাসরি অ্যাক্সেস দেয়, যেখানে রেডি-টু-ব্যবহারযোগ্য পাইথন সমাধানগুলি ফ্রেমওয়ার্কের প্রযুক্তিগত বিশদগুলি লুকিয়ে রাখে এবং সহজভাবে পঠনযোগ্য মডেল অনুমান ফলাফল ফিরিয়ে দেয়। কলকারীদের কাছে।
MediaPipe ফ্রেমওয়ার্ক pybind11 লাইব্রেরির উপরে বসে। C++ কোর ফ্রেমওয়ার্ক Python-এ C++/Python ল্যাঙ্গুয়েজ বাইন্ডিংয়ের মাধ্যমে উন্মুক্ত করা হয়। নীচের বিষয়বস্তু অনুমান করে যে পাঠকের ইতিমধ্যেই MediaPipe C++ ফ্রেমওয়ার্ক সম্পর্কে প্রাথমিক ধারণা রয়েছে। অন্যথায়, আপনি ফ্রেমওয়ার্ক ধারণাগুলিতে দরকারী তথ্য পেতে পারেন।
প্যাকেট
প্যাকেটটি মিডিয়াপাইপের মৌলিক ডেটা প্রবাহ ইউনিট। একটি প্যাকেটে একটি সংখ্যাসূচক টাইমস্ট্যাম্প এবং একটি অপরিবর্তনীয় পেলোডের জন্য একটি ভাগ করা পয়েন্টার থাকে। পাইথনে, mp.packet_creator
মডিউলের প্যাকেট নির্মাতা পদ্ধতিগুলির একটিতে কল করে একটি MediaPipe প্যাকেট তৈরি করা যেতে পারে। অনুরূপভাবে, mp.packet_getter
মডিউলে প্যাকেট গেটার পদ্ধতিগুলির একটি ব্যবহার করে প্যাকেট পেলোড পুনরুদ্ধার করা যেতে পারে। নোট করুন যে প্যাকেট তৈরির পরে প্যাকেট পেলোড অপরিবর্তনীয় হয়ে যায়। এইভাবে, পুনরুদ্ধার করা প্যাকেট সামগ্রীর পরিবর্তন প্যাকেটের প্রকৃত পেলোডকে প্রভাবিত করে না। মিডিয়াপাইপ ফ্রেমওয়ার্ক পাইথন এপিআই কোর বাইন্ডিং-এ মিডিয়াপাইপের সর্বাধিক ব্যবহৃত ডেটা প্রকারগুলিকে সমর্থন করে (যেমন, ইমেজফ্রেম, ম্যাট্রিক্স, প্রোটোকল বাফার এবং আদিম ডেটা প্রকার)। নীচের বিস্তৃত সারণীটি মিডিয়াপাইপ পাইথন ফ্রেমওয়ার্ক API দ্বারা সমর্থিত প্রতিটি ডেটা টাইপের জন্য প্যাকেট নির্মাতার সাথে পাইথন এবং C++ ডেটা টাইপের মধ্যে টাইপ ম্যাপিং এবং বিষয়বস্তু গেটার পদ্ধতি দেখায়।
পাইথন ডেটা টাইপ | C++ ডেটা টাইপ | প্যাকেট সৃষ্টিকর্তা | কন্টেন্ট গেটার |
---|---|---|---|
bool | bool | create_bool(সত্য) | get_bool(প্যাকেট) |
int বা np.intc | int_t | create_int(1) | get_int(প্যাকেট) |
int বা np.int8 | int8_t | create_int8(2**7-1) | get_int(প্যাকেট) |
int বা np.int16 | int16_t | create_int16(2**15-1) | get_int(প্যাকেট) |
int বা np.int32 | int32_t | create_int32(2**31-1) | get_int(প্যাকেট) |
int বা np.int64 | int64_t | create_int64(2**63-1) | get_int(প্যাকেট) |
int বা np.uint8 | uint8_t | create_uint8(2**8-1) | get_uint(প্যাকেট) |
int বা np.uint16 | uint16_t | create_uint16(2**16-1) | get_uint(প্যাকেট) |
int বা np.uint32 | uint32_t | create_uint32(2**32-1) | get_uint(প্যাকেট) |
int বা np.uint64 | uint64_t | create_uint64(2**64-1) | get_uint(প্যাকেট) |
float বা np.float32 | ভাসা | তৈরি_ফ্লোট(1.1) | get_float(প্যাকেট) |
float বা np.double | দ্বিগুণ | তৈরি_ডবল(1.1) | get_float(প্যাকেট) |
str (UTF-8) | std::স্ট্রিং | create_string('abc') | get_str(প্যাকেট) |
বাইট | std::স্ট্রিং | create_string(b'\xd0\xd0\xd0') | get_bytes(প্যাকেট) |
mp.প্যাকেট | mp::প্যাকেট | তৈরি_প্যাকেট(পি) | get_packet(প্যাকেট) |
তালিকা [বুল] | std::vector<bool> | create_bool_vector([সত্য, মিথ্যা]) | get_bool_list(প্যাকেট) |
তালিকা [int] বা তালিকা [np.intc] | int[] | তৈরি_ইন্ট_অ্যারে([1, 2, 3]) | get_int_list(প্যাকেট, আকার=10) |
তালিকা [int] বা তালিকা [np.intc] | std::ভেক্টর<int> | Create_int_vector([1, 2, 3]) | get_int_list(প্যাকেট) |
তালিকা [ফ্লোট] বা তালিকা [np.float] | ভাসা [] | তৈরি_ফ্লোট_অ্যারারি([0.1, 0.2]) | get_float_list(প্যাকেট, আকার=10) |
তালিকা [ফ্লোট] বা তালিকা [np.float] | std::ভেক্টর<float> | তৈরি_ফ্লোট_ভেক্টর([0.1, 0.2]) | get_float_list(প্যাকেট, আকার=10) |
তালিকা[str] | std::vector<std::string> | create_string_vector(['a']) | get_str_list(প্যাকেট) |
তালিকা [এমপি প্যাকেট] | std::vector<mp::Packet> | তৈরি_প্যাকেট_ভেক্টর( [প্যাকেট1, প্যাকেট2]) | get_packet_list(p) |
ম্যাপিং [str, প্যাকেট] | std::মানচিত্র | তৈরি_স্ট্রিং_টু_প্যাকেট_ম্যাপ( {'a': packet1, 'b': packet2}) | get_str_to_packet_dict(প্যাকেট) |
np.ndarray (cv.mat এবং PIL.Image) | mp::ইমেজফ্রেম | তৈরি_ছবি_ফ্রেম( format=ImageFormat.SRGB, ডেটা = ম্যাট) | get_image_frame(প্যাকেট) |
np.ndarray | mp::ম্যাট্রিক্স | তৈরি_ম্যাট্রিক্স(ডেটা) | get_matrix(প্যাকেট) |
গুগল প্রোটো বার্তা | গুগল প্রোটো বার্তা | তৈরি_প্রোটো(প্রোটো) | get_proto(প্যাকেট) |
তালিকা[প্রোটো] | std::vector<Proto> | n/a | get_proto_list(প্যাকেট) |
এটি অস্বাভাবিক নয় যে ব্যবহারকারীরা কাস্টম C++ ক্লাস তৈরি করে এবং সেগুলিকে গ্রাফ এবং ক্যালকুলেটরে পাঠায়। মিডিয়াপাইপ ফ্রেমওয়ার্ক সহ পাইথনে কাস্টম ক্লাসগুলি ব্যবহার করার অনুমতি দিতে, আপনি নিম্নলিখিত ধাপে একটি নতুন ডেটা টাইপের জন্য প্যাকেট API প্রসারিত করতে পারেন:
একটি cc ফাইলে কাস্টম টাইপের জন্য 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(...); }
একটি পৃথক সিসি ফাইলে কাস্টম টাইপের একটি নতুন প্যাকেট ক্রিয়েটর এবং গেটার পদ্ধতি তৈরি করুন।
#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" ], )
Bazel দ্বারা pybind এক্সটেনশন টার্গেট (প্রত্যয় .so সহ) তৈরি করুন এবং জেনারেট করা ডায়নামিক লাইব্রেরিগুলিকে $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)
টাইমস্ট্যাম্প
প্রতিটি প্যাকেটে একটি টাইমস্ট্যাম্প থাকে যা মাইক্রোসেকেন্ডের এককে থাকে। পাইথনে, প্যাকেট API একটি প্যাকেটের সংখ্যাসূচক টাইমস্ট্যাম্প সংজ্ঞায়িত করার জন্য একটি সুবিধার পদ্ধতি packet.at()
প্রদান করে। আরও সাধারণভাবে, packet.timestamp
হল অন্তর্নিহিত টাইমস্ট্যাম্প অ্যাক্সেস করার জন্য প্যাকেট শ্রেণীর সম্পত্তি। একটি ইউনিক্স যুগকে একটি MediaPipe টাইমস্ট্যাম্পে রূপান্তর করতে, টাইমস্ট্যাম্প API এই উদ্দেশ্যে একটি পদ্ধতি mp.Timestamp.from_seconds()
অফার করে।
ইমেজ ফ্রেম
ইমেজফ্রেম হল একটি ছবি বা ভিডিও ফ্রেম সংরক্ষণ করার ধারক। ImageFrame দ্বারা সমর্থিত বিন্যাসগুলি ImageFormat enum- এ তালিকাভুক্ত করা হয়েছে। পিক্সেলগুলি ইন্টারলিভড রঙের উপাদানগুলির সাথে সারি-মেজর এনকোড করা হয় এবং ইমেজফ্রেম তার ডেটা প্রকার হিসাবে uint8, uint16 এবং ফ্লোট সমর্থন করে। MediaPipe ImageFrame C++ ক্লাস অ্যাক্সেস করতে একটি ImageFrame Python API প্রদান করে। পাইথনে, পিক্সেল ডেটা পুনরুদ্ধার করার সবচেয়ে সহজ উপায় হল একটি numpy ndarray পেতে image_frame.numpy_view()
কল করা। উল্লেখ্য যে ফিরে আসা numpy ndarray, অভ্যন্তরীণ পিক্সেল ডেটার একটি রেফারেন্স, অলিখিত। কলকারীদের যদি numpy ndarray পরিবর্তন করতে হয়, তাহলে একটি অনুলিপি পাওয়ার জন্য স্পষ্টভাবে একটি কপি অপারেশন কল করতে হবে। যখন MediaPipe একটি ইমেজফ্রেম তৈরি করার জন্য একটি numpy ndarray নেয়, তখন এটি অনুমান করে যে ডেটা সংরক্ষিত হয়। তদনুসারে, একটি ইমেজফ্রেমের পিক্সেল ডেটা যখন পাইথন সাইডে ফিরে আসে তখন এটি সংলগ্ন হতে পুনরায় সাজানো হবে।
গ্রাফ
মিডিয়াপাইপ ফ্রেমওয়ার্কের মধ্যে, সমস্ত প্রক্রিয়াকরণ একটি ক্যালকুলেটর গ্রাফের প্রেক্ষাপটে হয়। ক্যালকুলেটরগ্রাফ পাইথন এপিআই হল C++ ক্যালকুলেটর গ্রাফ ক্লাসের সাথে সরাসরি আবদ্ধ। প্রধান পার্থক্য হল CalculatorGraph Python API একটি ত্রুটি ঘটলে একটি অ-ওকে স্ট্যাটাস ফেরত দেওয়ার পরিবর্তে একটি পাইথন ত্রুটি উত্থাপন করে। অতএব, পাইথন ব্যবহারকারী হিসাবে, আপনি সাধারণত যেমন করেন ব্যতিক্রমগুলি পরিচালনা করতে পারেন। একটি ক্যালকুলেটর গ্রাফের জীবনচক্র তিনটি পর্যায় ধারণ করে: প্রাথমিককরণ এবং সেটআপ, গ্রাফ রান এবং গ্রাফ শাটডাউন।
একটি CalculatorGraphConfig প্রোটোবাফ বা বাইনারি প্রোটোবাফ ফাইল দিয়ে একটি ক্যালকুলেটরগ্রাফ শুরু করুন এবং আউটপুট স্ট্রীম(গুলি) পর্যবেক্ষণ করতে কলব্যাক পদ্ধতি(গুলি) প্রদান করুন।
বিকল্প 1. একটি 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()
পাইথন স্ক্রিপ্ট আপনার স্থানীয় পাইথন রানটাইম দ্বারা চালানো যেতে পারে।