Как смешать стереоизображение с EmguCV?

В настоящее время я пытаюсь объединить два отдельных изображения с камеры в одно изображение как анаглиф. Результат должен выглядеть примерно так, как здесь.

Вот мой код, который я написал для захвата двух изображений камеры и преобразования их в черно-белое:

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;
            }
        }

    }

}

У меня вопрос: как преобразовать серые изображения в Cyan и Magenta или Red и Blue (стр. Строки в фрагменте кода, помеченные как TODO:)?


person salocinx    schedule 11.01.2017    source источник


Ответы (2)


Чтобы сделать красно-голубой анаглиф стереоизображение, поместите imgLeft в красный канал imgStereo и imgRight в зеленый и синий каналы imgStereo.

Если предположить, что все три изображения (L, R, S) имеют одинаковый размер, код будет выглядеть так:

for(i=0;i<imgStereo->height;i++)
{
   for(j=0;j<imgStereo->width;j++)
   {
      imgStereo.at<Vec3b>(i,j)[0] = imgRight.at<uchar>(i,j);   // B
      imgStereo.at<Vec3b>(i,j)[1] = imgRight.at<uchar>(i,j);   // G
      imgStereo.at<Vec3b>(i,j)[2] = imgLeft.at<uchar>(i,j);    // R
    }
}
person Hardtack    schedule 11.01.2017
comment
Спасибо за ваше предложение! Я реализовал это в C # / EmguCV, но преобразование изображений в матрицу ›кажется слишком медленным и не успевает за запущенными событиями захвата. Я ищу решение на основе матрицы (см. Мой код в вопросе). Любые идеи? - person salocinx; 12.01.2017
comment
Я не знаком с EmguCV. Но другим решением может быть не доступ к отдельному пикселю, как мой приведенный выше код, а копирование всего канала (например, копирование всего imgLeft в канал R imgStereo). Это могут быть функции mixChannels или слияния, такие как здесь и здесь - person Hardtack; 12.01.2017

Вот мое решение EmguCV для создания анаглифического изображения с двух входов камеры. Два цветных изображения сначала преобразуются в серые изображения, а затем объединяются в соответствующие цветовые каналы окончательного изображения RGB.

Преимущество этого метода заключается в том, что информация не теряется по сравнению с методом, который извлекает только красный канал одного исходного изображения и зеленый / синий каналы другого исходного изображения.

#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();
            }
        }

    }

}
person salocinx    schedule 13.01.2017