Python'da MediaPipe Çerçevesi

MediaPipe Python çerçevesi, Google Cloud'un temel bileşenlerine Timestamp, Packet ve CalculatorGraph gibi MediaPipe C++ çerçevesini kullanıma hazır Python çözümleri ise çerçevenin teknik ayrıntılarını inceler ve okunabilir modeli döndürür. arayanlara döner.

MediaPipe çerçevesi, pybind11 kitaplığı hakkında daha fazla bilgi edinin. C++ temel çerçevesi, Python'da bir C++/Python dil bağlamasıyla kullanıma sunulur. Aşağıdaki içerikte, okuyucunun Arkadaş Bitkiler projesinin oldukça önemlidir. Aksi takdirde, şurada yararlı bilgiler bulabilirsiniz: Çerçeve Çalışması Kavramları.

Paket

Paket, MediaPipe'teki temel veri akışı birimidir. Paket, bir sayısal zaman damgası ve sabit bir yüke işaret eden paylaşımlı bir işaretçi içerir. Python'da, MediaPipe paketi, "the" mp.packet_creator modülünü kullanabilirsiniz. Buna karşılık, paket yükü paket alıcı yöntemlerinin mp.packet_getter modülünü kullanabilirsiniz. Paket yükünün paketten sonra değişmez hale geleceğini unutmayın çok önemli. Bu nedenle, alınan paket içeriğinin değiştirilmesi, yük olduğunu gösterir. MediaPipe çerçevesi Python API, MediaPipe'in en yaygın kullanılan veri türleri (ör. ImageFrame, Matris, Protokol arabellekler ve temel veri türleri) eklemeniz gerekir. Kapsamlı Aşağıdaki tabloda, Python ile C++ veri türü arasındaki tür eşlemeleri gösterilmektedir ve her bir veri türü için paket oluşturucu ve içerik alıcı yöntemi ile birlikte tarafından desteklenir.

Python Veri Türü C++ Veri Türü Paket oluşturucu İçerik Alıcısı
bool bool create_bool(True) get_bool(packet)
int veya np.intc int_t create_int(1) get_int(packet)
int veya np.int8 int8_t create_int8(2**7-1) get_int(packet)
int veya np.int16 int16_t create_int16(2**15-1) get_int(packet)
int veya np.int32 tam32_t create_int32(2**31-1) get_int(packet)
int veya np.int64 int64_t create_int64(2**63-1) get_int(packet)
int veya np.uint8 uint8_t create_uint8(2**8-1) get_uint(packet)
int veya np.uint16 uint16_t create_uint16(2**16-1) get_uint(packet)
int veya np.uint32 uint32_t create_uint32(2**32-1) get_uint(packet)
int veya np.uint64 uint64_t create_uint64(2**64-1) get_uint(packet)
kayan veya np.float32 kayan noktalı create_float(1.1) get_float(packet)
float veya np.double double create_double(1.1) get_float(packet)
str (UTF-8) std::string create_string('abc') get_str(packet)
bayt std::string create_string(b'\xd0\xd0\xd0') get_bytes(packet)
mp.Packet mp::Packet create_packet(p) get_packet(packet)
Liste[bool] std::vector<bool> create_bool_vector([Doğru, Yanlış]) get_bool_list(packet)
List[int] veya List[np.intc] int[] create_int_array([1; 2; 3]) get_int_list(paket; size=10)
List[int] veya List[np.intc] std::vector<int> create_int_vector([1, 2, 3]) get_int_list(packet)
List[float] veya List[np.float] float[] create_float_arrary([0,1; 0,2]) get_float_list(paket; size=10)
List[float] veya List[np.float] std::vector&lt;float&gt; create_float_vector([0,1, 0,2]) get_float_list(paket; size=10)
Liste[str] std::vector<std::string> create_string_vector(['a']) get_str_list(packet)
Liste[mp.Packet] std::vector&lt;mp::Packet&gt; create_packet_vector(
[paket1, paket2])
get_packet_list(p)
Eşleme[str, Paket] std::map<std::string, paket=""></std::string,> create_string_to_packet_map(
        {&#39;a&#39;: packet1, &#39;b&#39;: packet2})
get_str_to_packet_dict(packet)
np.ndarray
(cv.mat ve 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)
Google Proto Mesajı Google Proto Mesajı create_proto(proto) get_proto(packet)
Liste[Proto] std::vector<Proto> Yok get_proto_list(packet)

Kullanıcıların özel C++ sınıfları oluşturması ve bunları grafikler ve hesaplayıcılar. Python'da özel sınıfların kullanılmasına izin vermek için kullanıyorsanız, Paket API'yi mevcut bir veri türü için şu adımları uygulayın:

  1. pybind11'i yazma sınıf bağlama kodu veya özel türde bir oynatıcı cc dosyasında da kullanabilirsiniz.

    #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(...);
    }
    
  2. ayrı cc dosyası.

    #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
    
  3. Özel tür bağlama ve yeni paket için iki bazel derleme kuralı ekleyin yöntemleri vardır.

    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"
        ],
    )
    
  4. Bazel tarafından oluşturulan pybind uzantı hedeflerini (.so son ekiyle) oluşturun ve oluşturulan dinamik kitaplıkları $LD_LIBRARY_PATH dizinlerinden birine taşıyın.

  5. Python'da bağlama modüllerini kullanın.

    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)
    

Zaman damgası

Her paket, mikrosaniye cinsinden bir zaman damgası içerir. Python'da, Paket API'si, sayısal değeri tanımlamak için packet.at() kolaylık yöntemi sunar zaman damgasıdır. Daha genel olarak, packet.timestamp paket sınıfıdır özelliğini kullanmanızı öneririz. Unix dönemini MediaPipe zaman damgası Timestamp API'si bu amaç için bir mp.Timestamp.from_seconds() yöntemi sunar.

ImageFrame

ImageFrame, görüntülerin veya video karelerinin depolandığı kapsayıcıdır. Biçimler ImageFrame tarafından desteklenenler şurada listelenmiştir: ImageFormat sıralaması. Pikseller, boşluk eklenen renk bileşenleri ve ImageFrame ile satır-ana şeklinde kodlanır uint8, uint16 ve float'ı destekler. MediaPipe, ImageFrame Python API ImageFrame C++ sınıfına erişmek için gereklidir. Python'da, komut dosyasını almanın en kolay yolu piksel verisi, numpy ndarray elde etmek için image_frame.numpy_view() işlevini çağırmaktır. Not dahili piksel verilerine referans olarak döndürülen numpy ndarray yazılamaz. Arayanların numpy ndarray'i değiştirmesi gerekiyorsa bir kopyasını almak için kopyalama işlemini açıkça çağırmalıdır. MediaPipe bir numara aldığında bir ImageFrame oluşturmak için verilerin ardışık olarak depolandığını varsayar. Buna karşılık, ImageFrame'in piksel verileri, yeni bir resim tekrarlandığından emin olur.

Grafik

MediaPipe Çerçevesi'nde tüm işleme, Hesap Makinesi Grafiği. HesaplayıcıGraph Python API , C++ CalculatorGraph sınıfı için doğrudan bir bağlayıcıdır. Aradaki en önemli fark hesaplayıcıGraph Python API, JavaScript hatası döndürüyor ve "sorunsuz" durumuna sahip olmayan bir hata oluştuğunda durumu. Bu nedenle, Python kullanıcısı olarak, her zaman olduğu gibi kullanın. Bir hesaplayıcıGrafiği'nin yaşam döngüsü, üç aşama: başlatma ve kurulum, grafik çalıştırma ve grafik kapatma.

  1. hesaplayıcıGraphConfig protobuf veya ikili program ile bir CalculatorGraph'i başlatma protobuf dosyası oluşturabilir ve çıkışı gözlemlemek için geri çağırma yöntemleri sunabilirsiniz. akışlar.

    1. Seçenek: Hesap MakinesiGraphConfig protobuf'u kullanarak CalculatorGraph'i başlatma veya metin temsilini inceleyin ve çıkış akışlarını gözlemleyin:

    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. Seçenek İkili protobuf dosyasıyla bir CalculatorGraph'i başlatmak ve çıkış akışlarını gözlemleyin.

    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}'))
    
  2. Grafik çalıştırmayı başlatın ve paketleri grafiğe aktarın.

    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))
    
  3. Sonlandıktan sonra grafiği kapatın. Başka bir grafik için grafiği yeniden başlatabilirsiniz close() çağrısından sonra çalıştırılır.

    graph.close()
    

Python komut dosyası, yerel Python çalışma zamanınız tarafından çalıştırılabilir.