当前位置: 代码迷 >> 综合 >> OpenCV(EmguCV)2.1新特性介紹之圖像差異StereoSGBM與設置窗口屬性SetWindowProperty(StereoSGBM Of OpenCV 2.1)
  详细解决方案

OpenCV(EmguCV)2.1新特性介紹之圖像差異StereoSGBM與設置窗口屬性SetWindowProperty(StereoSGBM Of OpenCV 2.1)

热度:62   发布时间:2023-12-16 02:52:47.0

http://www.cnblogs.com/xrwang/archive/2010/04/29/StereoSGBMAndSetWindowProperty.html

作者:王先榮


    上次介紹了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);

}
复制代码

 

感謝您耐心看完本文,希望對您有所幫助。
歡迎轉載,但是請注明出處,保留作者。



  相关解决方案