Search code examples
opencvemgucvstereo-3dstereoscopy

How to mix up a stereo image with EmguCV?


I am currently trying to merge two separate camera images into one image as Anaglyph. The result should look something like this image here.

Here's my code that I wrote to capture the two camera images and converting them to black&white:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using Emgu.Util;

namespace CameraStereoCapture {

    public partial class CameraStereoCapture : Form {

        private bool captureInProgress;

        private VideoCapture cameraLeft = null;
        private VideoCapture cameraRight = null;

        private Mat leftRawFrame;
        private Mat rightRawFrame;

        private Mat leftGrayFrame;
        private Mat rightGrayFrame;

        private Mat stereoFrame;

        public CameraStereoCapture() {
            InitializeComponent();
            CvInvoke.UseOpenCL = false;
            try {
                cameraLeft = new VideoCapture(1);
                cameraLeft.ImageGrabbed += ProcessFrame;
                cameraRight = new VideoCapture(0);
                cameraRight.ImageGrabbed += ProcessFrame;
            } catch (NullReferenceException ex) {
                MessageBox.Show(ex.Message);
            }
            leftRawFrame = new Mat();
            rightRawFrame = new Mat();
            leftGrayFrame = new Mat();
            rightGrayFrame = new Mat();
            stereoFrame = new Mat();
        }

        private void cmdCapture_Click(object sender, EventArgs e) {
            if (cameraLeft != null) {
                if (captureInProgress) {
                    // stop the capture
                    cmdCapture.Text = "Start Capture";
                    cameraLeft.Pause();
                    cameraRight.Pause();
                } else {
                    // start the capture
                    cmdCapture.Text = "Stop Capture";
                    cameraLeft.Start();
                    cameraRight.Start();
                }
                captureInProgress = !captureInProgress;
            }
        }

        private void ProcessFrame(object sender, EventArgs arg) {
            // capture and cache image from left camera
            if (cameraLeft != null && cameraLeft.Ptr != IntPtr.Zero) {
                cameraLeft.Retrieve(leftRawFrame, 0);
                imgLeft.Image = leftRawFrame;
            }
            // capture and cache image from right camera
            if (cameraRight != null && cameraRight.Ptr != IntPtr.Zero) {
                cameraRight.Retrieve(rightRawFrame, 0);
                imgRight.Image = rightRawFrame;
            }
            // calculate stereo image by combining the left and right image
            if (leftRawFrame != null && rightRawFrame!=null) {
                CvInvoke.CvtColor(leftRawFrame, leftGrayFrame, ColorConversion.Bgr2Gray);
                CvInvoke.CvtColor(rightRawFrame, rightGrayFrame, ColorConversion.Bgr2Gray);
                // TODO: how to convert 'leftRawImage to Cyan' ???
                // TODO: how to convert 'rightRawImage to Magenta' ???
                CvInvoke.AddWeighted(leftGrayFrame, 0.5, rightGrayFrame, 0.5, 1.0, stereoFrame);
                imgStereo.Image = stereoFrame;
            }
        }

    }

}

My question is, how to I convert the gray images to a Cyan and Magenta or Red and Blue (cp. lines in the code snippet that are marked as TODO:) ?


Solution

  • Here's my EmguCV solution to produce an Anaglyph image from two camera inputs. The two colour images are first converted to gray images and then merged together to the appropriate colour channels of the final RGB image.

    The advantage of this method is, that no information is lost compared to the method which extracts only the red channel of one source image and the green/blue channels of the other source image.

    #region Usings
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Emgu.CV;
    using Emgu.CV.CvEnum;
    using Emgu.CV.Structure;
    using Emgu.CV.Util;
    using Emgu.Util;
    #endregion
    
    namespace WallECtrl {
    
        public delegate void ImageAvailable(Mat leftFrame, Mat rightFrame, Mat stereoFrame);
    
        public class StereoEngine {
    
            public event ImageAvailable ImageAvailableEvent;
    
            private bool capturing;
            private bool colorPreview;
    
            private VideoCapture cameraLeft = null;
            private VideoCapture cameraRight = null;
    
            private Mat matLeftColourFrame;
            private Mat matRightColourFrame;
            private Mat matLeftGrayFrame;
            private Mat matRightGrayFrame;
            private Mat matStereoFrame;
    
            public StereoEngine() {
                CvInvoke.UseOpenCL = false;
                cameraLeft = new VideoCapture(0);
                cameraLeft.ImageGrabbed += ProcessFrame;
                cameraRight = new VideoCapture(1);
                cameraRight.ImageGrabbed += ProcessFrame;
                matLeftColourFrame = new Mat();
                matRightColourFrame = new Mat();
                matLeftGrayFrame = new Mat();
                matRightGrayFrame = new Mat();
                matStereoFrame = new Mat();
            }
    
            public bool Capturing {
                get {
                    return capturing;
                }
            }
    
            public bool ColorPreview {
                get {
                    return colorPreview;
                }
                set {
                    colorPreview = value;
                }
            }
    
            public void startCapture() {
                if (cameraLeft != null && cameraRight != null) {
                    if (!capturing) {
                        cameraLeft.Start();
                        cameraRight.Start();
                        capturing = !capturing;
                    }
                }
            }
    
            public void stopCapture() {
                if (cameraLeft != null && cameraRight != null) {
                    if (capturing) {
                        cameraLeft.Pause();
                        cameraRight.Pause();
                        capturing = !capturing;
                    }
                }
            }
    
            private void ProcessFrame(object sender, EventArgs arg) {
    
                // capture and cache image from left camera
                if (cameraLeft != null && cameraLeft.Ptr != IntPtr.Zero) {
                    cameraLeft.Retrieve(matLeftColourFrame, 0);
                }
    
                // capture and cache image from right camera
                if (cameraRight != null && cameraRight.Ptr != IntPtr.Zero) {
                    cameraRight.Retrieve(matRightColourFrame, 0);
                }
    
                // calculate stereo image by combining the left and right image
                if (matLeftColourFrame != null && matRightColourFrame!=null) {
    
                    CvInvoke.CvtColor(matLeftColourFrame, matLeftGrayFrame, ColorConversion.Bgr2Gray);
                    CvInvoke.CvtColor(matRightColourFrame, matRightGrayFrame, ColorConversion.Bgr2Gray);
    
                    using (VectorOfMat vm = new VectorOfMat(matRightGrayFrame, matRightGrayFrame, matLeftGrayFrame)) {
                        CvInvoke.Merge(vm, matStereoFrame);
                    }
    
                    // inform gui + network about new stereo image available
                    if(ImageAvailableEvent != null) {
                        if (colorPreview) {
                            ImageAvailableEvent(matLeftColourFrame, matRightColourFrame, matStereoFrame);
                        } else {
                            ImageAvailableEvent(matLeftGrayFrame, matRightGrayFrame, matStereoFrame);
                        }
                    }
    
                }
    
            }
    
            public void exit() {
                if(cameraLeft != null) {
                    cameraLeft.Stop();
                    cameraLeft.Dispose();
                }
                if (cameraRight != null) {
                    cameraRight.Stop();
                    cameraRight.Dispose();
                }
            }
    
        }
    
    }