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
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE
m1_orientation_client
m1_mathematics
juce_libvlc
m1_objectdetection
)

# definitions to replace the `JucePluginDefines.h`
Expand Down
3 changes: 2 additions & 1 deletion Modules/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/juce_libvlc/cmake")
juce_add_modules(
juce_murka
m1_orientation_client
juce_libvlc)
juce_libvlc
m1_objectdetection)

# Mach1 Spatial SDK
# Use these options to block dependencies we do not need
Expand Down
41 changes: 41 additions & 0 deletions Modules/m1_objectdetection/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Prerequisites
*.d

# Compiled Object files
*.slo
*.lo
*.o
*.obj

# Precompiled Headers
*.gch
*.pch

# Linker files
*.ilk

# Debugger Files
*.pdb

# Compiled Dynamic libraries
*.so
*.dylib
*.dll

# Fortran module files
*.mod
*.smod

# Compiled Static libraries
*.lai
*.la
*.a
*.lib

# Executables
*.exe
*.out
*.app

# debug information files
*.dwo
43 changes: 43 additions & 0 deletions Modules/m1_objectdetection/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# m1_objectdetection
Dependency for JUCE projects to add image or video object detection for auto-panning use cases after a user has supplied a reference object image for the target object to be detected and tracked.

## Implementation
This module provides a JUCE-compatible object detection system using template matching algorithms. The implementation includes:

### Core Classes
- `Mach1::ObjectDetector`: Main detection class
- `Mach1::DetectedObject`: Structure representing a detected object with position, bounds, and confidence

### Key Features
- **Template Matching**: Uses normalized cross-correlation for object detection
- **Proximity-Based Tracking**: Weights detections based on proximity to last known position
- **JUCE Integration**: Native support for `juce::Image` and JUCE data structures
- **Configurable Parameters**: Adjustable confidence threshold and proximity weighting
- **Multi-Object Detection**: Support for detecting multiple instances of the reference object

### Usage
```cpp
#include "m1_objectdetection.h"

// Create detector
Mach1::ObjectDetector detector;

// Set reference object from user selection
juce::Rectangle<int> selection(100, 100, 50, 50);
juce::Image referenceObject = videoFrame.getClippedImage(selection);
detector.setReferenceObject(referenceObject);

// Process video frames
for (auto& frame : videoFrames) {
auto objectCenter = detector.detectObjectCenter(frame);
if (!objectCenter.isOrigin()) {
// Use objectCenter for auto-panning
float panPosition = (objectCenter.getX() / frame.getWidth() - 0.5f) * 2.0f;
}
}
```

### Configuration
- `setConfidenceThreshold(float)`: Set minimum confidence for valid detections (0.0-1.0)
- `setProximityWeight(float)`: Set weight for proximity-based tracking (0.0-1.0)
- `resetTracking()`: Reset tracking state
151 changes: 151 additions & 0 deletions Modules/m1_objectdetection/example_usage.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/*******************************************************************************
Example usage of M1 Object Detection module
This file demonstrates how to use the ObjectDetector class for auto-panning
*******************************************************************************/

#include "m1_objectdetection.h"
#include <juce_core/juce_core.h>
#include <juce_graphics/juce_graphics.h>

// Example of how to use the ObjectDetector in a video player context
class VideoPlayerWithObjectDetection
{
public:
VideoPlayerWithObjectDetection()
{
// Initialize the object detector
detector = std::make_unique<Mach1::ObjectDetector>();

// Set detection parameters
detector->setConfidenceThreshold(0.6f); // 60% confidence threshold
detector->setProximityWeight(0.4f); // 40% weight for proximity-based tracking
}

void setReferenceObjectFromSelection(const juce::Image& frameImage,
juce::Rectangle<int> selection)
{
// Extract the selected region as reference object
if (selection.isEmpty() || !frameImage.isValid())
return;

// Create a sub-image from the selection
juce::Image referenceObject = frameImage.getClippedImage(selection);

// Set as reference object for detection
if (detector->setReferenceObject(referenceObject))
{
juce::Logger::writeToLog("Reference object set successfully");
}
else
{
juce::Logger::writeToLog("Failed to set reference object");
}
}

juce::Point<float> processVideoFrame(const juce::Image& currentFrame)
{
if (!currentFrame.isValid())
return juce::Point<float>();

// Detect the object in the current frame
auto objectCenter = detector->detectObjectCenter(currentFrame);

if (!objectCenter.isOrigin())
{
// Convert to normalized coordinates (0.0 to 1.0)
float normalizedX = objectCenter.getX() / currentFrame.getWidth();
float normalizedY = objectCenter.getY() / currentFrame.getHeight();

// Log the detection
juce::Logger::writeToLog(
"Object detected at: (" +
juce::String(normalizedX, 3) + ", " +
juce::String(normalizedY, 3) + ")"
);

return juce::Point<float>(normalizedX, normalizedY);
}

return juce::Point<float>();
}

std::vector<Mach1::DetectedObject> findMultipleObjects(const juce::Image& currentFrame,
int maxObjects = 3)
{
if (!currentFrame.isValid())
return {};

// Find multiple instances of the object
auto detectedObjects = detector->detectObjects(currentFrame, maxObjects);

// Log all detections
for (size_t i = 0; i < detectedObjects.size(); ++i)
{
const auto& obj = detectedObjects[i];
juce::Logger::writeToLog(
"Object " + juce::String(i + 1) +
" detected at: (" +
juce::String(obj.centerPosition.getX(), 1) + ", " +
juce::String(obj.centerPosition.getY(), 1) +
") with confidence: " +
juce::String(obj.confidence, 3)
);
}

return detectedObjects;
}

void resetObjectTracking()
{
detector->resetTracking();
juce::Logger::writeToLog("Object tracking reset");
}

bool hasReferenceObject() const
{
return detector->hasReferenceObject();
}

private:
std::unique_ptr<Mach1::ObjectDetector> detector;
};

// Example of how to integrate with audio panning
class AutoPanningController
{
public:
AutoPanningController(VideoPlayerWithObjectDetection& videoPlayer)
: videoPlayer(videoPlayer)
{
}

void updatePanningFromVideoFrame(const juce::Image& frame)
{
if (!videoPlayer.hasReferenceObject())
return;

// Get the object position
auto objectPos = videoPlayer.processVideoFrame(frame);

if (!objectPos.isOrigin())
{
// Convert normalized position to pan value (-1.0 to 1.0)
float panValue = (objectPos.getX() - 0.5f) * 2.0f;
panValue = juce::jlimit(-1.0f, 1.0f, panValue);

// Apply panning (this would connect to your audio engine)
applyAudioPanning(panValue);
}
}

private:
VideoPlayerWithObjectDetection& videoPlayer;

void applyAudioPanning(float panValue)
{
// This would connect to your Mach1 Spatial System or audio engine
juce::Logger::writeToLog(
"Auto-panning audio to: " + juce::String(panValue, 3)
);
}
};
Loading