C# OpenCV VideoWriter saves in unexpected colors

695 Views Asked by At

I am using Intel Realsense RGB camera to show live stream on WPF window as well as save the stream into a file. What I am showing on window has correct colors but when I save it, the video colors are off (more purple). Please see screenshot: https://ibb.co/txy9Sgd

I am using a EmguCV video writer to save the video. I don't have much knowledge about formats. I am guessing I am doing something wrong with Format24bppRgb format?

private Pipeline pipeline = new Pipeline(); // Create and config the pipeline to strem color and depth frames.
private CancellationTokenSource tokenSource;
private VideoWriter writer = null;

public StartTests()
{
    InitializeComponent();
}

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    tokenSource = new CancellationTokenSource();
    int fcc = VideoWriter.Fourcc('M', 'P', '4', 'V'); //'M', 'J', 'P', 'G'
    float fps = 15F;
    writer = new VideoWriter("testttt.mp4", fcc, fps, new System.Drawing.Size(640, 480), true);

    Config cfg = new Config();
    cfg.EnableStream(Stream.Color, 640, 480, format: Format.Rgb8);
    PipelineProfile pp = pipeline.Start(cfg);
    StartRenderFrames(pp);
}

private void StartRenderFrames(PipelineProfile pp)
{
    // Allocate bitmaps for rendring. Since the sample aligns the depth frames to the color frames, both of the images will have the color resolution
    using (VideoStreamProfile p = pp.GetStream(Stream.Color) as VideoStreamProfile)
    {
        imgColor.Source = new WriteableBitmap(p.Width, p.Height, 96d, 96d, PixelFormats.Rgb24, null);
    }
    Action<VideoFrame> updateColor = UpdateImage(imgColor);

    Task.Factory.StartNew(() =>
    {
        while (!tokenSource.Token.IsCancellationRequested)
        {
            using (FrameSet frames = pipeline.WaitForFrames()) // Wait for the next available FrameSet
            {
                VideoFrame colorFrame = frames.ColorFrame.DisposeWith(frames);

                // Save frames to file here...
                System.Drawing.Bitmap ColorImg = new System.Drawing.Bitmap(colorFrame.Width, colorFrame.Height, colorFrame.Stride, System.Drawing.Imaging.PixelFormat.Format24bppRgb, colorFrame.Data);
                Image<Bgr, Byte> imageCV = new Image<Bgr, byte>(ColorImg); //Image Class from Emgu.CV
                Mat matFrame = imageCV.Mat;
                writer.Write(matFrame);

                // Render to WPF window here...
                Dispatcher.Invoke(DispatcherPriority.Render, updateColor, colorFrame);
            }
        }
    }, tokenSource.Token);
}

static Action<VideoFrame> UpdateImage(Image img)
{
    WriteableBitmap wbmp = img.Source as WriteableBitmap;
    return new Action<VideoFrame>(frame =>
    {
        using (frame)
        {
            var rect = new Int32Rect(0, 0, frame.Width, frame.Height);
            wbmp.WritePixels(rect, frame.Data, frame.Stride * frame.Height, frame.Stride);
        }
    });
}

private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
    tokenSource.Cancel();
    tokenSource.Dispose();
    pipeline.Stop();
    writer.Dispose();
    tokenSource = new CancellationTokenSource();
}

I want to see consistent colors in the saved .mp4 file but I am seeing weird colors.

Note - My code is based on this example: https://github.com/IntelRealSense/librealsense/blob/master/wrappers/csharp/cs-tutorial-2-capture/Window.xaml.cs

1

There are 1 best solutions below

1
jb455 On

OpenCV assumes BGR colour format, so if you change the RealSense stream format to Format.Bgra8 and the WriteableBitmap format to PixelFormats.Bgr24, you should be alright.

So you should have:

cfg.EnableStream(Stream.Color, 640, 480, format: Format.Bgr8);

and

new WriteableBitmap(p.Width, p.Height, 96d, 96d, PixelFormats.Bgr24, null);

I don't think you'll need to change the System.Drawing.Bitmap pixelformat as you're only using it to feed the OpenCV mat.