• OpenCV(EmguCV)2.1新特性介绍之图像差异StereoSGBM与设置窗口属性SetWindowProperty(StereoSGBM Of OpenCV 2.1)


    作者:王先荣


        上次介绍了OpenCV2.1中新增的图像分割算法GrabCut,本文将介绍StereoSGBM与SetWindowProperty。其中StereoSGBM用于计算两幅图像间的差异图,跟已有的StereoBM和StereoGC作用一样,算法不同而已;SetWindowProperty用于设置窗口的属性,目前仅可用于设置全屏属性。

    比较图像间的差异StereoSGBM
        StereoSGBM用于计算两幅图像间的差异图,在OpenCV的在线文档中有非常详细的介绍,地址是:“http://opencv.willowgarage.com/documentation/cpp/camera_calibration_and_3d_reconstruction.html#stereosgbm”。参数非常多,如果不使用默认的参数,需要仔细查看每个参数的说明,以免出错。OpenCV的具体实现在命名空间cv中的StereoSGBM类,目前还没有对应的C风格封装;EmguCV将其封装在StereoSGBM类中。
        StereoSGBM除了参数很多之外,使用起来蛮简单的,如下所示:

    //创建StereoSGBM对象
    StereoSGBM sgbm = new StereoSGBM((int)nudMinDisparity.Value, (int)nudNumDisparities.Value, (int)nudSADWindowSize.Value, (int)nudP1.Value,
    (
    int)nudP2.Value, (int)nudDisp12MaxDiff.Value, (int)nudPreFilterCap.Value, (int)nudUniquenessRatio.Value,
    (
    int)nudSpeckleWindowSize.Value, (int)nudSpeckleRange.Value, chkFullDP.Checked);
    //查找两幅图像间的相关性(差异)
    sgbm.FindStereoCorrespondence(leftImage, rightImage, disparityImage);
    //显示结果
    pbDisparity.Image = disparityImage.Bitmap;
    //释放资源
    sgbm.Dispose();

    完整的示例(附带了StereoBM和StereoGC的示例)请看:

    StereoSGBM完整示例
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    using Emgu.CV;
    using Emgu.CV.CvEnum;
    using Emgu.CV.Structure;

    namespace NewFeaturesOfOpenCV2._1
    {
    public partial class FormStereoCorrespondence : Form
    {
    //私有成员
    private string leftImageFileName = "wky_sls_2272x1704.jpg"; //左边的图像文件名
    private string rightImageFileName = "wky_sls_2272x1704_2.jpg"; //右边的图像文件名
    private Image<Gray, Byte> leftImage = null; //左边的灰度图像
    private Image<Gray, Byte> rightImage = null; //右边的灰度图像
    private Image<Gray, Int16> disparityImage = null; //差异图像
    private Stopwatch sw = new Stopwatch(); //计时器

    public FormStereoCorrespondence()
    {
    InitializeComponent();
    }

    //设置SGBM的默认参数
    private void btnFillDefaultParameters_Click(object sender, EventArgs e)
    {
    nudSADWindowSize.Value
    = 3;
    nudP1.Value
    = 0;
    nudP2.Value
    = 0;
    nudDisp12MaxDiff.Value
    = 0;
    nudPreFilterCap.Value
    = 0;
    nudUniquenessRatio.Value
    = 0;
    nudSpeckleWindowSize.Value
    = 0;
    nudSpeckleRange.Value
    = 0;
    chkFullDP.Checked
    = false;
    }

    //设置SGBM的推荐参数
    private void btnFillRecommendedParameters_Click(object sender, EventArgs e)
    {
    nudUniquenessRatio.Value
    = 5;
    nudSpeckleWindowSize.Value
    = 50;
    nudSpeckleRange.Value
    = 16;
    }

    //窗体加载时
    private void FormStereoCorrespondence_Load(object sender, EventArgs e)
    {
    //设置提示
    toolTip.SetToolTip(nudNumDisparities, "必须大于0,且能被16除尽");
    toolTip.SetToolTip(nudSADWindowSize,
    "缺省为0;如果指定则必须是正奇数,推荐值为3~11");
    toolTip.SetToolTip(nudP1,
    "缺省为0;推荐值为8*number_of_image_channels*SADWindowSize*SADWindowSize");
    toolTip.SetToolTip(nudP2,
    "缺省为0;如果指定则P2>P1,推荐值为32*number_of_image_channels*SADWindowSize*SADWindowSize");
    toolTip.SetToolTip(nudDisp12MaxDiff,
    "如果设置为负值,则跳过左右差异检查");
    toolTip.SetToolTip(nudUniquenessRatio,
    "缺省为0,推荐值为5~15");
    toolTip.SetToolTip(nudSpeckleWindowSize,
    "缺省为0,推荐值为50~200");
    toolTip.SetToolTip(nudSpeckleRange,
    "缺省为0;如果指定则必须是能被16整除的正数,推荐值为16或者32");
    //初始化图像
    InitImage(true);
    InitImage(
    false);
    }

    //加载图像1
    private void btnLoadLeftImage_Click(object sender, EventArgs e)
    {
    LoadImage(
    true);
    }

    //加载图像2
    private void btnLoadRightImage_Click(object sender, EventArgs e)
    {
    LoadImage(
    false);
    }

    /// <summary>
    /// 加载图像
    /// </summary>
    /// <param name="isLeft">是左边的图像吗?</param>
    private void LoadImage(bool isLeft)
    {
    OpenFileDialog ofd
    = new OpenFileDialog();
    ofd.CheckFileExists
    = true;
    ofd.DefaultExt
    = "jpg";
    ofd.Filter
    = "图片文件|*.jpg;*.png;*.bmp|所有文件|*.*";
    if (ofd.ShowDialog(this) == DialogResult.OK)
    {
    if (ofd.FileName != "")
    {
    if (isLeft)
    leftImageFileName
    = ofd.FileName;
    else
    rightImageFileName
    = ofd.FileName;
    InitImage(isLeft);
    }
    }
    ofd.Dispose();
    }

    /// <summary>
    /// 初始化图像
    /// </summary>
    /// <param name="isLeft">是左边的图像吗?</param>
    private void InitImage(bool isLeft)
    {
    if (isLeft)
    {
    Image
    <Bgr, Byte> image = new Image<Bgr, byte>(leftImageFileName);
    pbLeft.Image
    = image.Bitmap;
    if (leftImage != null)
    leftImage.Dispose();
    leftImage
    = image.Convert<Gray, Byte>();
    if (disparityImage != null)
    disparityImage.Dispose();
    disparityImage
    = new Image<Gray, short>(leftImage.Size);
    image.Dispose();
    }
    else
    {
    Image
    <Bgr, Byte> image = new Image<Bgr, byte>(rightImageFileName);
    pbRight.Image
    = image.Bitmap;
    if (rightImage != null)
    rightImage.Dispose();
    rightImage
    = image.Convert<Gray, Byte>();
    image.Dispose();
    }
    }

    //开始计算
    private void btnCalc_Click(object sender, EventArgs e)
    {
    if (leftImage.Size != rightImage.Size)
    {
    MessageBox.Show(
    this, "两幅图像的尺寸不一致,不能比较。", "错误提示");
    return;
    }
    if (tcStereo.SelectedTab == tpStereoSGBM)
    {
    StereoSGBM sgbm
    = new StereoSGBM((int)nudMinDisparity.Value, (int)nudNumDisparities.Value, (int)nudSADWindowSize.Value, (int)nudP1.Value,
    (
    int)nudP2.Value, (int)nudDisp12MaxDiff.Value, (int)nudPreFilterCap.Value, (int)nudUniquenessRatio.Value,
    (
    int)nudSpeckleWindowSize.Value, (int)nudSpeckleRange.Value, chkFullDP.Checked);
    sw.Stop();
    sw.Start();
    sgbm.FindStereoCorrespondence(leftImage, rightImage, disparityImage);
    sw.Stop();
    pbDisparity.Image
    = disparityImage.Bitmap;
    sgbm.Dispose();
    lblStatus.Text
    = string.Format("SGBM比较耗时{0:F04}毫秒。", sw.ElapsedMilliseconds);
    }
    else if (tcStereo.SelectedTab == tpStereoBM)
    {
    STEREO_BM_TYPE type
    = cbBMType.Text == "BASIC" ? STEREO_BM_TYPE.BASIC : (cbBMType.Text == "FISH_EYE" ? STEREO_BM_TYPE.FISH_EYE : STEREO_BM_TYPE.NARROW);
    StereoBM bm
    = new StereoBM(type, (int)nudBMNumberOfDisparities.Value);
    sw.Stop();
    sw.Start();
    bm.FindStereoCorrespondence(leftImage, rightImage, disparityImage);
    sw.Stop();
    pbDisparity.Image
    = disparityImage.Bitmap;
    bm.Dispose();
    lblStatus.Text
    = string.Format("BM比较耗时{0:F04}毫秒。", sw.ElapsedMilliseconds);
    }
    else if (tcStereo.SelectedTab == tpStereoGC)
    {
    StereoGC gc
    = new StereoGC((int)nudGCNumberOfDisparities.Value, (int)nudGCMaxIters.Value);
    Image
    <Gray, Int16> rightDisparityImage = new Image<Gray, short>(leftImage.Size);
    sw.Stop();
    sw.Start();
    gc.FindStereoCorrespondence(leftImage, rightImage, disparityImage, rightDisparityImage);
    sw.Stop();
    CvInvoke.cvConvertScale(rightDisparityImage.Ptr, rightDisparityImage.Ptr, 16d, 0d);
    CvInvoke.cvConvertScale(disparityImage.Ptr, disparityImage.Ptr,
    -16d, 0d);
    pbDisparity.Image
    = rightDisparityImage.Bitmap;
    rightDisparityImage.Dispose();
    gc.Dispose();
    lblStatus.Text
    = string.Format("GC比较耗时{0:F04}毫秒。", sw.ElapsedMilliseconds);
    }
    }

    //关闭窗口时
    private void FormStereoCorrespondence_FormClosed(object sender, FormClosedEventArgs e)
    {
    //释放资源
    if (leftImage != null)
    leftImage.Dispose();
    if (rightImage != null)
    rightImage.Dispose();
    if (disparityImage != null)
    disparityImage.Dispose();
    }
    }
    }

    设置窗口属性SetWindowProperty
        目前只能用SetWindowProperty来设置窗口的全屏属性——全屏或者普通窗口。其实OpenCV2.1中还增加了一个名为cvGetWindowProperty的函数,用于获取窗口的属性,更新说明中没有提到而已。由于目前还没有这个函数的相关文档,我就详细点说说。
    1.函数原型、参数说明及提示
    void cvSetWindowProperty(const char* name, int prop_id, double prop_value)
    作用:设置窗口的属性
    返回值:无
    参数:
    name——窗口名称,对应于用cvNamedWindow创建窗口时使用的名称;
    prop_id——属性id,目前有两种属性:CV_WND_PROP_FULLSCREEN    (=0)和CV_WND_PROP_AUTOSIZE(=1),但是仅CV_WND_PROP_FULLSCREEN有用;
    prop_value——属性值,如果设置全屏属性,则该值可能有:CV_WINDOW_NORMAL(=0)和CV_WINDOW_FULLSCREEN    (=1)。
    备注:(1)cvSetWindowProperty目前只能用于设置窗口的全屏属性;(2)在设置该属性前,要求窗口不能是AUTOSIZE的,否则设置无效;(3)基于第2点原因,在创建窗口时不能省略flag参数(即不能使用其默认值CV_WINDOW_AUTOSIZE);(4)由于EmguCV封装的CvInvoke.cvNamedWindow强制使用了AUTOSIZE参数,因此不能使用它来创建窗口,需要自行进行P/Invoke调用;(5)OpenCV2.1更新文档中的使用示例是错误的,不要模仿。

    double cvGetWindowProperty(const char* name, int prop_id)
    作用:获取窗口的属性
    返回值:返回窗口的属性值
    参数:同cvSetWindowProperty

    2.示例
    您可以按如下所示使用cvSetWindowProperty:

    cvSetWindowProperty(windowName, CV_WND_PROP_FULLSCREEN, CV_WINDOW_FULLSCREEN);

    完整的示例请看:

    完整的cvSetWindowProperty示例
    //全屏窗口
    private void btnSetWindowProperty_Click(object sender, EventArgs e)
    {
    Image
    <Bgr, Byte> image = new Image<Bgr, byte>("wky_qiao_2272x1704.jpg");
    string windowName = "stereoGC left disparity";
    cvNamedWindow(windowName,
    0);
    cvResizeWindow(windowName,
    640, 480);
    cvMoveWindow(windowName,
    100, 100);
    cvSetWindowProperty(windowName, CV_WND_PROP_FULLSCREEN, CV_WINDOW_FULLSCREEN);
    CvInvoke.cvShowImage(windowName, image.Ptr);
    CvInvoke.cvWaitKey(
    0);
    CvInvoke.cvDestroyWindow(windowName);
    image.Dispose();
    }

    //定义跟窗口相关的常量
    public const int CV_WND_PROP_FULLSCREEN = 0;
    public const int CV_WND_PROP_AUTOSIZE = 1;
    public const double CV_WINDOW_NORMAL = 0;
    public const double CV_WINDOW_FULLSCREEN = 1;
    public const int CV_WINDOW_AUTOSIZE = 1;
    //跟窗口有关的P/Invoke调用
    //设置窗口属性,目前只能设置CV_WND_PROP_FULLSCREEN
    [System.Runtime.InteropServices.DllImportAttribute("highgui210.dll", EntryPoint = "cvSetWindowProperty")]
    public static extern void cvSetWindowProperty([System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] string name, int prop_id, double prop_value);
    //调整窗口的尺寸
    [System.Runtime.InteropServices.DllImportAttribute("highgui210.dll", EntryPoint = "cvResizeWindow")]
    public static extern void cvResizeWindow([System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] string name, int width, int height);
    //移动窗口
    [System.Runtime.InteropServices.DllImportAttribute("highgui210.dll", EntryPoint = "cvMoveWindow")]
    public static extern void cvMoveWindow([System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] string name, int x, int y);
    //创建指定名称的窗口
    [System.Runtime.InteropServices.DllImportAttribute("highgui210.dll", EntryPoint = "cvNamedWindow")]
    public static extern int cvNamedWindow([System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] string name, int flags);
    //获取窗口对应的句柄HWnd
    [System.Runtime.InteropServices.DllImportAttribute("highgui210.dll", EntryPoint = "cvGetWindowHandle")]
    public static extern System.IntPtr cvGetWindowHandle([System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] string name);
    //获取指定句柄对应的窗口名称
    [System.Runtime.InteropServices.DllImportAttribute("highgui210.dll", EntryPoint = "cvGetWindowName")]
    public static extern System.IntPtr cvGetWindowName(System.IntPtr windowHandle);
    //获取窗口的属性
    [System.Runtime.InteropServices.DllImportAttribute("highgui210.dll", EntryPoint = "cvGetWindowProperty")]
    public static extern double cvGetWindowProperty([System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] string name, int prop_id);

    }

    感谢您耐心看完本文,希望对您有所帮助。
    欢迎转载,但是请注明出处,保留作者。

  • 相关阅读:
    Jmeter 指令记录
    做100个用户的并发测试时是不是得要100个用户的账号呀?
    以后可能会遇到的问题记录 .send_keys 无法输入的情况
    Appscan安装问题记录 + 最后问题解决的方法 和安装步骤
    fiddler工具能干啥
    Appscan_web安全测试工具 (含修改启动浏览器的方法)
    解决需要断言多个,其中有断言错误还要继续往下断言其他的方法
    (unittest之装饰器(@classmethod)) 让多个测试用例在一个浏览器里面跑 的方法
    unittest笔记
    另外一种结尾展示方法
  • 原文地址:https://www.cnblogs.com/xrwang/p/StereoSGBMAndSetWindowProperty.html
Copyright © 2020-2023  润新知