Webcam Overlay?

Is there an existing plugin that will add a data overlay onto the webcam streaming feed? Like a timestamp, only with some additional data, like tool/bed temp and such (which could be pulled from API calls).

I've got my webcam streams going into Blue Iris, so I can watch all of my printers, but it would be great to have an at-a-glance idea of temps, layer, and time to completion.

The RTMP streamer recently had an update that added something like this:

It might not be suitable for your use case though. The problem is that OctoPrint doesn't do the webcam streaming, so if anything is adding overlays it has to more trickier processing (and in RTMP case re-encoding). So I don't think there's any others.

1 Like

Well, I tossed some really, really ugly code into Powershell. I mean, it works...

Screenshot 2022-01-26 171245

Here's the code, fill out the variables up top, have Blue Iris (or what ever you're going to use) point to your output files, adjust and let it run.

$octopi = "octoprintserver"
$apikey = "abcdefg"
$UriCorePath = "http://$octopi.local/api"
$outputPath = "OverlayOutput"

Function Get-OctoInfo {
    Param(
        [Parameter(Mandatory=$true)]
        [string]$UriPath
    )
    $RestMethodParams = @{'Method'="Get"}
    $RestMethodParams.Add('URI',"$($UriCorePath)$UriPath")
    $RestMethodParams.Add('Headers',@{'X-Api-Key' = $($apikey)})

    Invoke-RestMethod @RestMethodParams
}

add-type -AssemblyName PresentationFramework

function Convert-TextToImage
{
  param
  (
    [string]
    [Parameter(Mandatory)]
    [Alias("FileOut")]
    $filename,

    [String]
    [Parameter(Mandatory)]
    $Text,
    
    [String]
    $Font = 'Consolas',
    
    [ValidateRange(5,400)]
    [Int]
    $FontSize = 24,
    
    [System.Windows.Media.Brush]
    $Foreground = [System.Windows.Media.Brushes]::Black,
    
    [System.Windows.Media.Brush]
    $Background = [System.Windows.Media.Brushes]::White
  )

  # take a simple XAML template with some text  
  $xaml = @"
<TextBlock
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">$Text</TextBlock>
"@

  Add-Type -AssemblyName PresentationFramework
  
  # turn it into a UIElement
  $reader = [XML.XMLReader]::Create([IO.StringReader]$XAML)
  $result = [Windows.Markup.XAMLReader]::Load($reader)
  
  # refine its properties
  $result.FontFamily = $Font
  $result.FontSize = $FontSize
  $result.Foreground = $Foreground
  $result.Background = $Background
  
  # render it in memory to the desired size
  $result.Measure([System.Windows.Size]::new([Double]::PositiveInfinity, [Double]::PositiveInfinity))
  $result.Arrange([System.Windows.Rect]::new($result.DesiredSize))
  $result.UpdateLayout()
  
  # write it to a bitmap and save it as PNG
  $render = [System.Windows.Media.Imaging.RenderTargetBitmap]::new($result.ActualWidth, $result.ActualHeight, 96, 96, [System.Windows.Media.PixelFormats]::Default)
  $render.Render($result)
  Start-Sleep -Seconds 1
  $encoder = [System.Windows.Media.Imaging.PngBitmapEncoder]::new()
  $encoder.Frames.Add([System.Windows.Media.Imaging.BitmapFrame]::Create($render))
  $filestream = [System.IO.FileStream]::new($filename, [System.IO.FileMode]::Create)
  $encoder.Save($filestream)
  
  # clean up
  $reader.Close() 
  $reader.Dispose()
  
  $filestream.Close()
  $filestream.Dispose()
  
  # return the file name for the generated image
  $filename
}

While ($true) {
    $job = Get-OctoInfo -UriPath "/job"
    $jobend = (Get-Date).add([timespan]::fromseconds($job.progress.printTimeLeft).ToString("hh\:mm\:ss")).ToString("yyyyMMddhhmm")
    Convert-TextToImage -filename "$outputPath\$octopi-jobend.png" -Text $jobend -Font Stencil -FontSize 28 -Foreground White -Background Gray
    $tool = Get-OctoInfo -UriPath "/printer/tool"
    Convert-TextToImage -filename "$outputPath\$octopi-tool.png" -Text "Tool: $($tool.tool0.actual)" -Font Stencil -FontSize 28 -Foreground White -Background Gray
    $bed = Get-OctoInfo -UriPath "/printer/bed"
    Convert-TextToImage -filename "$outputPath\$octopi-bed.png" -Text "Bed: $($bed.bed.actual)" -Font Stencil -FontSize 28 -Foreground White -Background Gray
    Start-Sleep -Seconds 30
}
1 Like

I know it's been a while, but I just implemented your PS1 script. Thank you!!

I did add a bit to bring in DisplayLayerProgress plugin info.

I had to move "api" out of $UriCorePath and put it into the calls at the bottom. but that was the only change.

	$dlp = Get-OctoInfo -UriPath "/plugin/DisplayLayerProgress/values"
    Convert-TextToImage -filename "$outputPath\$octopi-dlp-layers.png" -Text "Layer: $($dlp.layer.current) of $($dlp.layer.total)" -Font Stencil -FontSize 28 -Foreground White -Background Gray
    Convert-TextToImage -filename "$outputPath\$octopi-dlp-filename.png" -Text "$($dlp.currentFilename)" -Font Stencil -FontSize 28 -Foreground White -Background Gray
    Convert-TextToImage -filename "$outputPath\$octopi-dlp-complete.png" -Text "$($dlp.print.progress)% Complete" -Font Stencil -FontSize 28 -Foreground White -Background Gray
    Convert-TextToImage -filename "$outputPath\$octopi-dlp-remaining.png" -Text "$($dlp.print.timeLeft) Remaining" -Font Stencil -FontSize 28 -Foreground White -Background Gray