opencv2-6 图像分割MeanShift

//---------------------------------【头文件、命名空间包含部分】----------------------------
// 描述:包含程序所使用的头文件和命名空间
//------------------------------------------------------------------------------------------------
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
//--------------------------------------【help( )函数】--------------------------------------
// 描述:输出一些帮助信息
//----------------------------------------------------------------------------------------------
static void help()
{
cout << "\n\t此程序演示了OpenCV中MeanShift图像分割的使用。\n"
<< "\n\t程序运行后我们可以通过3个滑动条调节分割效果。调节滑动条后可能会有些许卡顿,请耐心等待\n"
<< "\n\t3个滑动条代表的参数分别为空间窗的半径 (spatialRad)、色彩窗的半径(colorRad)、最大图像金字塔级别(maxPyrLevel)\n"
<< endl;
}
//This colors the segmentations
static void floodFillPostprocess( Mat& img, const Scalar& colorDiff=Scalar::all(1) )
{
CV_Assert( !img.empty() );
RNG rng = theRNG();
Mat mask( img.rows+2, img.cols+2, CV_8UC1, Scalar::all(0) );
for( int y = 0; y < img.rows; y++ )
{
for( int x = 0; x < img.cols; x++ )
{
if( mask.at<uchar>(y+1, x+1) == 0 )
{
Scalar newVal( rng(256), rng(256), rng(256) );
floodFill( img, mask, Point(x,y), newVal, 0, colorDiff, colorDiff );
}
}
}
}
string winName = "meanshift";
int spatialRad, colorRad, maxPyrLevel;
Mat img, res;
static void meanShiftSegmentation( int, void* )
{
cout << "spatialRad=" << spatialRad << "; "
<< "colorRad=" << colorRad << "; "
<< "maxPyrLevel=" << maxPyrLevel << endl;
pyrMeanShiftFiltering( img, res, spatialRad, colorRad, maxPyrLevel );
floodFillPostprocess( res, Scalar::all(2) );
imshow( winName, res );
}
//-----------------------------------【main( )函数】--------------------------------------------
// 描述:控制台应用程序的入口函数,我们的程序从这里开始
//-------------------------------------------------------------------------------------------------
int main(int argc, char** argv)
{
help();
img = imread( "1.jpg" );
if( img.empty() )
return -1;
imshow("原始图",img);
spatialRad = 10;
colorRad = 10;
maxPyrLevel = 1;
namedWindow( winName, WINDOW_AUTOSIZE );
createTrackbar( "spatialRad", winName, &spatialRad, 80, meanShiftSegmentation );
createTrackbar( "colorRad", winName, &colorRad, 60, meanShiftSegmentation );
createTrackbar( "maxPyrLevel", winName, &maxPyrLevel, 5, meanShiftSegmentation );
meanShiftSegmentation(0, 0);
waitKey();
return 0;

}

程序说明:

1)CV_Assert( !img.empty() );  检查出错警告语句。括号内是检测的内容,!img.empty() 的意思是:如果img图像为空,则返回0,否则返回1。
原型是宏定义:#define   CV_Assert( expr )   if((expr)) ; else cv::error( cv::Exception(CV_StsAssert, #expr, "", __FILE__, __LINE__) )

如果条件expr为真,则不用执行什么操作,如果为假,则执行出错函数error()。error()函数调用Exception基类的对象。

而error()的原型是:CV_EXPORTS void error( const Exception& exc );这是出错提示函数,里面的参数是Exception对象的常引用。我们来看exception类。

Exception(异常处理机制),早期的C语言的异常处理机制,通常是人为的对返回结果加一些标志来进行判定。C语言的异常处理机制全是人为的定义,这样就会造成业务逻辑的主线受到异常处理的牵制,或者说是难免会将注意力转移,并且造成业务逻辑与异常处理之间有很大程度上的缠绕。
为什么要自定义自己的Exception ,Java Exception机制与传统的C语言的异常处理机制有什么不同,这种Exception机制的意义在什么地方?接下来咱就来和你一起探讨Exception 的优缺点。
早期的C语言的异常处理机制,通常是我们人为的对返回结果加一些标志来进行判定,比如发生错误返回什么标志,正常情况下我们又是返回什么标记,而这些都不是语言本身所赋予我们的,而对于C语言这种机制又有什么问题哩?为什么新一代的语言 Java Ruby C# 等都用Exception机制而不是维持C语言的老样子?这些都是我们需要思考的问题。
C语言的异常处理机制全是我们人为的定义,这样就会造成业务逻辑的主线受到异常处理的牵制,或者说是我们难免会将注意力转移,并且造成业务逻辑与异常处理之间有很大程度上的缠绕。
中止模型
假设错误非常严重,已至你无法在回到错误发生的地方,也就是说,这段程序经过判断认为,他已经没有办法挽回,于是就抛出异常,希望这个异常不要在回来,这也是Java 当前所采用的模式。
继续模型
这种模型的主旨是恢复当前的运行环境,然后希望能够重新回到错误的发生地,并希望第二次的尝试能够获得成功,这种模型通常为操作系统所应用。

Exception类是从基类exception派生出来的派生类。

class CV_EXPORTS Exception : public std::exception
{
public:
    /*!Default constructor*/
    Exception();
    /*!
     Full constructor. Normally the constuctor is not called explicitly.
     Instead, the macros CV_Error(), CV_Error_() and CV_Assert()are used.
    */
    Exception(int _code, const string& _err, const string& _func, const string& _file, int _line);
    virtual ~Exception()   throw();
    /*!\return the error description and the context as a text string.*/ 
    virtual const char *what() const throw();
    void formatMessage();
    string msg; ///< the formatted error message
    int code; ///< error code @see CVStatus
    string err; ///< error description
    string func; ///< function name. Available only when the compiler supports __func__ macro
    string file; ///< source file name where the error has occured
    int line; ///< line number in the source file where the error has occured 
};

class _CRTIMP_PURE exception
    {   // base of all library exceptions
public:
    _EXCEPTION_INLINE __CLR_OR_THIS_CALL exception();
    _EXCEPTION_INLINE explicit __CLR_OR_THIS_CALL exception(const char * const &);
    _EXCEPTION_INLINE __CLR_OR_THIS_CALL exception(const char * const &, int);
    _EXCEPTION_INLINE __CLR_OR_THIS_CALL exception(const exception&);
    _EXCEPTION_INLINE exception& __CLR_OR_THIS_CALL operator=(const exception&);
    _EXCEPTION_INLINE virtual __CLR_OR_THIS_CALL ~exception();
    _EXCEPTION_INLINE virtual const char * __CLR_OR_THIS_CALL what() const;
private:
    _EXCEPTION_INLINE void __CLR_OR_THIS_CALL _Copy_str(const char *);
    _EXCEPTION_INLINE void __CLR_OR_THIS_CALL _Tidy();
    const char * _Mywhat;
    bool _Mydofree;
    };

2)mask.at<uchar>(y+1, x+1) == 0。运用at方式来操作像素元素,详细关于at函数原型如下:

template<typename _Tp> inline _Tp& Mat::at(Point pt)
{
    CV_DbgAssert( dims <= 2 && data && (unsigned)pt.y < (unsigned)size.p[0] &&
        (unsigned)(pt.x*DataType<_Tp>::channels) < (unsigned)(size.p[1]*channels()) &&
        CV_ELEM_SIZE1(DataType<_Tp>::depth) == elemSize1());
    return ((_Tp*)(data + step.p[0]*pt.y))[pt.x];
}
关键来看最后一句,return ((_Tp*)(data + step.p[0]*pt.y))[pt.x]。data是图像数据的首地址。data+的是地址的偏移量,step是步长,即是行与行像素之间的间距;而step.p[0]是一行像素元素的首地址。step.p[0]*pt.y则是每一行像素元素的首地址。括号外面的则是用于控制列变量的pt.x,其中pt.x和pt.y是at函数的Point类型的参数。分别用于控制列和行像素。


3)





你可能感兴趣的:(opencv)