Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .formatter.exs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[
inputs: [
"{lib,test,config}/**/*.{ex,exs}",
"{lib,test,config,examples}/**/*.{ex,exs}",
".formatter.exs",
"*.exs"
],
Expand Down
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
examples/models/*.onnx
examples/outputs/*

compile_commands.json
.gdb_history
bundlex.sh
Expand All @@ -7,7 +10,7 @@ bundlex.bat
/tmp/

# Created by https://www.gitignore.io/api/c,vim,linux,macos,elixir,windows,visualstudiocode
# Edit at https://www.gitignore.io/?templates=c,vim,linux,macos,elixir,windows,visualstudiocode
# Edit at https://www.gitignore.io/?yolos=c,vim,linux,macos,elixir,windows,visualstudiocode
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

xd


### C ###
# Prerequisites
Expand Down
27 changes: 15 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,38 @@
# Membrane Template Plugin
# Membrane YOLO Plugin

[![Hex.pm](https://img.shields.io/hexpm/v/membrane_template_plugin.svg)](https://hex.pm/packages/membrane_template_plugin)
[![API Docs](https://img.shields.io/badge/api-docs-yellow.svg?style=flat)](https://hexdocs.pm/membrane_template_plugin)
[![CircleCI](https://circleci.com/gh/membraneframework/membrane_template_plugin.svg?style=svg)](https://circleci.com/gh/membraneframework/membrane_template_plugin)
[![Hex.pm](https://img.shields.io/hexpm/v/membrane_yolo_plugin.svg)](https://hex.pm/packages/membrane_yolo_plugin)
[![API Docs](https://img.shields.io/badge/api-docs-yellow.svg?style=flat)](https://hexdocs.pm/membrane_yolo_plugin)
[![CircleCI](https://circleci.com/gh/membraneframework/membrane_yolo_plugin.svg?style=svg)](https://circleci.com/gh/membraneframework/membrane_yolo§ §_plugin)

This repository contains a template for new plugins.
Contains 2 Membrane Filters
- `Membrane.YOLO.LiveFilter`
- `Membrane.YOLO.OfflineFilter`
to run YOLO object detection on a video stream in live and offline scaneario.

Check out different branches for other flavors of this template.
Uses under the hood [yolo_elixir](https://github.com/poeticoding/yolo_elixir).

It's a part of the [Membrane Framework](https://membrane.stream).

## Installation

The package can be installed by adding `membrane_template_plugin` to your list of dependencies in `mix.exs`:
The package can be installed by adding `membrane_yolo_plugin` to your list of dependencies in `mix.exs`:

```elixir
def deps do
[
{:membrane_template_plugin, "~> 0.1.0"}
{:membrane_yolo_plugin, "~> 0.1.0"}
]
end
```

## Usage
## Examples

TODO
See `examples/yolo.livemd` or `examples/live_camera_capture.exs`, `examples/live_mp4_processing.exs` and `examples/offline_mp4_processing.exs`

## Copyright and License

Copyright 2020, [Software Mansion](https://swmansion.com/?utm_source=git&utm_medium=readme&utm_campaign=membrane_template_plugin)
Copyright 2025, [Software Mansion](https://swmansion.com/?utm_source=git&utm_medium=readme&utm_campaign=membrane_yolo_plugin)

[![Software Mansion](https://logo.swmansion.com/logo?color=white&variant=desktop&width=200&tag=membrane-github)](https://swmansion.com/?utm_source=git&utm_medium=readme&utm_campaign=membrane_template_plugin)
[![Software Mansion](https://logo.swmansion.com/logo?color=white&variant=desktop&width=200&tag=membrane-github)](https://swmansion.com/?utm_source=git&utm_medium=readme&utm_campaign=membrane_yolo_plugin)

Licensed under the [Apache License, Version 2.0](LICENSE)
Binary file added examples/fixtures/street.mp4
Binary file not shown.
Binary file added examples/fixtures/street_short.mp4
Binary file not shown.
76 changes: 76 additions & 0 deletions examples/live_camera_capture.exs
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should only keep examples in the livebook. It's basically duplicated in this and other .exs scripts, not great for maintenance

Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
hardware_acceleration =
case :os.type() do
{:unix, :darwin} -> :coreml
{:unix, :linux} -> :cuda
end

Mix.install(
[
{:membrane_yolo_plugin,
github: "membraneframework/membrane_yolo_plugin", branch: "implementation"},
{:membrane_core, "~> 1.0"},
{:membrane_camera_capture_plugin, "~> 0.7.3"},
{:membrane_ffmpeg_swscale_plugin, "~> 0.16.3"},
{:membrane_raw_video_format,
github: "membraneframework/membrane_raw_video_format", branch: "to_image", override: true},
{:boombox, github: "membraneframework/boombox"},
{:kino_yolo, github: "poeticoding/kino_yolo"},
{:exla, "~> 0.10"}
],
config: [
ortex: [
{Ortex.Native, [features: [hardware_acceleration]]}
],
nx: [
default_backend: EXLA.Backend
]
]
)

Logger.configure(level: :info)

model_name = "yolox_l.onnx"
model_path = Path.join("examples/models", model_name)

if not File.exists?(model_path) do
model_url =
"https://github.com/Megvii-BaseDetection/YOLOX/releases/download/0.1.1rc0/#{model_name}"

%{body: data} = Req.get!(model_url)
File.write!(model_path, data)
end

defmodule YOLOCameraCapturePipeline do
use Membrane.Pipeline

@impl true
def handle_init(_ctx, _opts) do
spec =
child(:camera_capture, Membrane.CameraCapture)
|> child(:swscale_converter, %Membrane.FFmpeg.SWScale.Converter{
format: :RGB,
output_width: 640
})
|> child(:yolo_live_filter, %Membrane.YOLO.LiveFilter{
yolo_model:
YOLO.load(
model_impl: YOLO.Models.YOLOX,
model_path: "examples/models/yolox_l.onnx",
classes_path: "examples/models/coco_classes.json",
eps: [unquote(hardware_acceleration)]
),
draw_boxes: &KinoYOLO.Draw.draw_detected_objects/2
})
|> via_in(:input, options: [kind: :video])
|> child(:boombox_sink, %Boombox.Bin{output: :player})

{[spec: spec], %{}}
end
end

{:ok, _supervisor, pipeline} = Membrane.Pipeline.start_link(YOLOCameraCapturePipeline, [])
Process.monitor(pipeline)

receive do
{:DOWN, _ref, :process, _pid, _reason} -> :ok
end
83 changes: 83 additions & 0 deletions examples/live_mp4_processing.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
hardware_acceleration =
case :os.type() do
{:unix, :darwin} -> :coreml
{:unix, :linux} -> :cuda
end

Mix.install(
[
{:membrane_yolo_plugin,
github: "membraneframework/membrane_yolo_plugin", branch: "implementation"},
{:membrane_core, "~> 1.0"},
{:membrane_camera_capture_plugin, "~> 0.7.3"},
{:membrane_ffmpeg_swscale_plugin, "~> 0.16.3"},
{:membrane_raw_video_format,
github: "membraneframework/membrane_raw_video_format", branch: "to_image", override: true},
{:boombox, github: "membraneframework/boombox"},
{:kino_yolo, github: "poeticoding/kino_yolo"},
{:exla, "~> 0.10"}
],
config: [
ortex: [
{Ortex.Native, [features: [hardware_acceleration]]}
],
nx: [
default_backend: EXLA.Backend
]
]
)

Logger.configure(level: :info)

model_name = "yolox_l.onnx"
model_path = Path.join("examples/models", model_name)

if not File.exists?(model_path) do
model_url =
"https://github.com/Megvii-BaseDetection/YOLOX/releases/download/0.1.1rc0/#{model_name}"

%{body: data} = Req.get!(model_url)
File.write!(model_path, data)
end

defmodule YOLOMP4Pipeline do
use Membrane.Pipeline

@impl true
def handle_init(_ctx, _opts) do
spec =
child(:mp4_source, %Boombox.Bin{input: "examples/fixtures/street.mp4"})
|> via_out(:output, options: [kind: :video])
|> child(:transcoder, %Membrane.Transcoder{output_stream_format: Membrane.RawVideo})
|> child(:swscale_converter, %Membrane.FFmpeg.SWScale.Converter{
format: :RGB,
output_width: 640
})
|> child(:yolo_live_filter, %Membrane.YOLO.LiveFilter{
yolo_model:
YOLO.load(
model_impl: YOLO.Models.YOLOX,
model_path: "examples/models/yolox_l.onnx",
classes_path: "examples/models/coco_classes.json",
eps: [unquote(hardware_acceleration)]
),
draw_boxes: &KinoYOLO.Draw.draw_detected_objects/2
})
|> via_in(:input, options: [kind: :video])
|> child(:boombox_sink, %Boombox.Bin{output: :player})

{[spec: spec], %{}}
end

@impl true
def handle_child_notification(:processing_finished, :boombox_sink, ctx, state) do
{[terminate: :normal], state}
end
end

{:ok, supervisor, _pipeline} = Membrane.Pipeline.start_link(YOLOMP4Pipeline, [])
Process.monitor(supervisor)

receive do
{:DOWN, _ref, :process, _pid, _reason} -> :ok
end
82 changes: 82 additions & 0 deletions examples/models/coco_classes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
[
"person",
"bicycle",
"car",
"motorcycle",
"airplane",
"bus",
"train",
"truck",
"boat",
"traffic light",
"fire hydrant",
"stop sign",
"parking meter",
"bench",
"bird",
"cat",
"dog",
"horse",
"sheep",
"cow",
"elephant",
"bear",
"zebra",
"giraffe",
"backpack",
"umbrella",
"handbag",
"tie",
"suitcase",
"frisbee",
"skis",
"snowboard",
"sports ball",
"kite",
"baseball bat",
"baseball glove",
"skateboard",
"surfboard",
"tennis racket",
"bottle",
"wine glass",
"cup",
"fork",
"knife",
"spoon",
"bowl",
"banana",
"apple",
"sandwich",
"orange",
"broccoli",
"carrot",
"hot dog",
"pizza",
"donut",
"cake",
"chair",
"couch",
"potted plant",
"bed",
"dining table",
"toilet",
"tv",
"laptop",
"mouse",
"remote",
"keyboard",
"cell phone",
"microwave",
"oven",
"toaster",
"sink",
"refrigerator",
"book",
"clock",
"vase",
"scissors",
"teddy bear",
"hair drier",
"toothbrush"
]
Loading