美文网首页OpenCv
与OpenCV的第三天

与OpenCV的第三天

作者: Code_r_Wang | 来源:发表于2017-01-18 21:21 被阅读317次

    第一件事:HighGUI 模块学习

    1. OpenCV 命名空间

    之前的代码每一个 OpenCV 类和函数之前都会加上 cv:: ,这是因为 OpenCV 的代码都是定义在命名空间 cv 之内的,需要通过在类和函数之前加上 cv::cv 命名空间内的类和函数进行调用。但是还有一种更方便的用法,是在代码开头的适当位置加上 using namespace cv; 这句代码。规定之后的程序都位于此命名空间之内。
    比如:

    #include <opencv2/opencv.cpp>
    using namespace cv;
    

    这样,之后的程序都不需要再加 cv:: 前缀。

    2. 图像载入: imread 函数

    imread 函数用于读取文件中的图片到 OpenCV 中。原型如下:

    Mat imread(const string& filename, int flags = 1);
    
    • 第一个参数,const string& 类型的变量,需要填入图片的路径名。
      支持如下类型的图像输入:
    类型 后缀
    位图 *.bmp,*.dib
    JPEG文件 *.jpeg,*.jpg,*.jpe
    JPEG 2000 文件 *.jp2
    PNG图片 *.png
    便携文件格式 *.pbm,*.pgm,*ppm
    Sun rasters 光栅文件 *.sr,*.ras
    TIFF 文件 *.tiff,*.tif
    • 第二个参数,int 类型的变量,指定一个加载图像的显示颜色类型。默认值为 1,表示载入三通道的彩色图。我们可以在 imgcodecs_c.hOpenCV2 中,被定义在 higui_c.h 文件中) 文件中找到这个枚举的定义:
    enum
    {
    /* 8bit, color or not */
        CV_LOAD_IMAGE_UNCHANGED  =-1,
    /* 8bit, gray */
        CV_LOAD_IMAGE_GRAYSCALE  =0,
    /* ?, color */
        CV_LOAD_IMAGE_COLOR      =1,
    /* any depth, ? */
        CV_LOAD_IMAGE_ANYDEPTH   =2,
    /* ?, any color */
        CV_LOAD_IMAGE_ANYCOLOR   =4,
    /* ?, no rotate */
        CV_LOAD_IMAGE_IGNORE_ORIENTATION  =128
    };
    
    参数名 介绍
    CV_LOAD_IMAGE_UNCHANGED CV_LOAD_IMAGE_ANYCOLOR 相比,除了会载入Alpha通道外基本是同等效果的,所以这个参数渐渐使用的很少了。
    CV_LOAD_IMAGE_GRAYSCALE 将图像转为灰度再返回。
    CV_LOAD_IMAGE_COLOR 将图像转换为3通道彩色再返回。
    CV_LOAD_IMAGE_ANYDEPTH 若载入图像深度为 16 位 或 32 位,就返回对应深度的图像,否则将图像深度转为8位再返回。
    CV_LOAD_IMAGE_ANYCOLOR 保持颜色通道不变
    CV_LOAD_IMAGE_IGNORE_ORIENTATION 忽略图片文件中的 orientation 旋转参数载入

    注意:如果输入的参数之间有冲突,则会采用较小的值。如 CV_LOAD_IMAGE_COLOR | CV_LOAD_IMAGE_ANYCOLOR 将按照 CV_LOAD_IMAGE_COLOR 载入三通道图。

    若这个参数不取这个枚举值,那么将会按照:

    • flags > 0 返回 3 通道彩色图(CV_LOAD_IMAGE_COLOR);
    • flags = 0 返回灰度图(CV_LOAD_IMAGE_GRAYSCALE);
    • flags < 0 返回包含Alpha通道的彩色图(CV_LOAD_IMAGE_UNCHANGED);

    这个规则载入图像。

    3.图像显示: imshow 函数

    imshow 用于在指定窗口显示图像,原型如下:

    void imshow(const string& winname, InputArray Mat);
    
    • 第一个参数:const string& 类型的变量,需要显示的窗口名。
    • 第二个参数:InputArray 类型的变量,需要显示的图像。如果窗口是用 CV_WINDOW_AUTOSIZE(默认值) 创建的,那么就按图像原始大小显示(窗口会自动适应图片大小)。否则缩放图像适应窗口大小。而 imshow 函数对图像深度的缩放会规范到[0,255] 区间,即 8 位深度。
    InputArray 类型:

    opencv_core 模块中的 mat.hpp 头文件中可以找到该类型定义:

    typedef const _InputArray& InputArray;
    
    class CV_EXPORTS _InputArray
    {
    public:
        enum {
            KIND_SHIFT = 16,
            FIXED_TYPE = 0x8000 << KIND_SHIFT,
            FIXED_SIZE = 0x4000 << KIND_SHIFT,
            KIND_MASK = 31 << KIND_SHIFT,
    
            NONE              = 0 << KIND_SHIFT,
            MAT               = 1 << KIND_SHIFT,
            MATX              = 2 << KIND_SHIFT,
            STD_VECTOR        = 3 << KIND_SHIFT,
            STD_VECTOR_VECTOR = 4 << KIND_SHIFT,
            STD_VECTOR_MAT    = 5 << KIND_SHIFT,
            EXPR              = 6 << KIND_SHIFT,
            OPENGL_BUFFER     = 7 << KIND_SHIFT,
            CUDA_HOST_MEM     = 8 << KIND_SHIFT,
            CUDA_GPU_MAT      = 9 << KIND_SHIFT,
            UMAT              =10 << KIND_SHIFT,
            STD_VECTOR_UMAT   =11 << KIND_SHIFT,
            STD_BOOL_VECTOR   =12 << KIND_SHIFT,
            STD_VECTOR_CUDA_GPU_MAT = 13 << KIND_SHIFT
        };
    
        _InputArray();
        _InputArray(int _flags, void* _obj);
        _InputArray(const Mat& m);
        _InputArray(const MatExpr& expr);
        _InputArray(const std::vector<Mat>& vec);
        template<typename _Tp> _InputArray(const Mat_<_Tp>& m);
        template<typename _Tp> _InputArray(const std::vector<_Tp>& vec);
        _InputArray(const std::vector<bool>& vec);
        template<typename _Tp> _InputArray(const std::vector<std::vector<_Tp> >& vec);
        template<typename _Tp> _InputArray(const std::vector<Mat_<_Tp> >& vec);
        template<typename _Tp> _InputArray(const _Tp* vec, int n);
        template<typename _Tp, int m, int n> _InputArray(const Matx<_Tp, m, n>& matx);
        _InputArray(const double& val);
        _InputArray(const cuda::GpuMat& d_mat);
        _InputArray(const std::vector<cuda::GpuMat>& d_mat_array);
        _InputArray(const ogl::Buffer& buf);
        _InputArray(const cuda::HostMem& cuda_mem);
        template<typename _Tp> _InputArray(const cudev::GpuMat_<_Tp>& m);
        _InputArray(const UMat& um);
        _InputArray(const std::vector<UMat>& umv);
    
        Mat getMat(int idx=-1) const;//常成员函数,不能改变成员变量值的函数
        Mat getMat_(int idx=-1) const;
        UMat getUMat(int idx=-1) const;
        void getMatVector(std::vector<Mat>& mv) const;
        void getUMatVector(std::vector<UMat>& umv) const;
        void getGpuMatVector(std::vector<cuda::GpuMat>& gpumv) const;
        cuda::GpuMat getGpuMat() const;
        ogl::Buffer getOGlBuffer() const;
    
        int getFlags() const;
        void* getObj() const;
        Size getSz() const;
    
        int kind() const;
        int dims(int i=-1) const;
        int cols(int i=-1) const;
        int rows(int i=-1) const;
        Size size(int i=-1) const;
        int sizend(int* sz, int i=-1) const;
        bool sameSize(const _InputArray& arr) const;
        size_t total(int i=-1) const;
        int type(int i=-1) const;
        int depth(int i=-1) const;
        int channels(int i=-1) const;
        bool isContinuous(int i=-1) const;
        bool isSubmatrix(int i=-1) const;
        bool empty() const;
        void copyTo(const _OutputArray& arr) const;
        void copyTo(const _OutputArray& arr, const _InputArray & mask) const;
        size_t offset(int i=-1) const;
        size_t step(int i=-1) const;
        bool isMat() const;
        bool isUMat() const;
        bool isMatVector() const;
        bool isUMatVector() const;
        bool isMatx() const;
        bool isVector() const;
        bool isGpuMatVector() const;
        ~_InputArray();
    
    protected:
        int flags;
        void* obj;
        Size sz;
    
        void init(int _flags, const void* _obj);
        void init(int _flags, const void* _obj, Size _sz);
    };
    

    可以看出这是一个代理类并通过 c++ 的转换构造函数机制,实现传入 Mat 类型并转为 InputArray 的相应构造函数 _InputArray(const Mat& m);,构造出一个 InputArray 类型的对象。
    代理类:目标类(可多个)为其内部的 private、protected 类型成员变量,并通过创建同名方法以及对目标类相应方法的调用,完成对目标类的代理行为。
    简而言之,就是替目标类传话的一个类。

    4. 创建窗口:namedWindow 函数

    namedWindow 的函数原型如下:

    void namedWindow(const string& winname, int flags=WINDOW_AUTOSIZE);
    
    • 第一个参数,const string& 类型的变量,窗口标识符。
    • 第二个参数,int 类型的变量,窗口类型。
    类型 介绍
    WINDOW_NORMAL 用户可以改变窗口的大小
    WINDOW_AUTOSIZE 窗口自动调整,以显示所显示的图像。用户不可以手动设置。
    WINDOW_OPENGL 使创建的窗口支持OpenGL

    5. 输出图像到文件:imwrite 函数

    imwrite 函数原型如下:

    bool imwrite(const string& filename,InputArray img, vector<int> params=vector<int>());
    
    • 第一个参数:const string& 类型的变量,文件名(需要后缀)。
    • 第二个参数:InputArray 类型的数据,一般是 Mat 类型的图像数据。
    • 第三个参数:vector<int> 类型的变量,特定格式保存的参数编码。它有默认值。
    图片格式 介绍
    JPEG 这个参数表示从 0 到 100 的图片质量,默认值95。
    PNG 这个参数表示压缩级别(CV_IMWRITE_PNG)从 0 到 9。值越高意味着,尺寸越小,压缩时间越长。 默认值是 3
    PPM,PGM,PBM 表示二进制格式标志(CV_IMWRITE_PXM_BINARY),取值为 0 或者 1。

    支持保存的几种图片格式与支持读取的几种图片格式一致。

    6. 图像载入、显示与输出的综合程序

    #include <iostream>
    #include <opencv2/opencv.hpp>
    int main(int argc, const char * argv[]) {
    //载入图像
        cv::Mat image = cv::imread("1.jpg");
        cv::Mat logo = cv::imread("Code_r_Wang.jpg");
        
        //显示原图像
        cv::namedWindow("1.jpg");
        cv::imshow("1.jpg", image);
        
        //显示logo图像
        cv::namedWindow("Code_r_Wang.jpg");
        cv::imshow("Code_r_Wang.jpg", logo);
        
        //选取部分图像
        cv::Mat imageROI;
        imageROI = image(cv::Rect(image.cols - logo.cols - 10, image.rows - logo.rows - 10, logo.cols, logo.rows));
    
        //混合图像(这个函数放到后面学)
        cv::addWeighted(imageROI, 0.5, logo, 0.5, 0.0, imageROI);
        
        //展示结果图
        cv::namedWindow("result");
        cv::imshow("result", image);
        
        //图像输出到文件
        cv::imwrite("叠加的结果图像.jpg", image);
    
        cv::waitKey();
    
    return 0;
    }
    
    运行效果图【原图】 运行效果图【logo图】 运行效果图【原图+logo图】 右击 **Products** 目录下生成的可运行的程序点击 **show in finder** 即可查看生成的图片 生成的图像

    7. 滑动条

    • 创建滑动条
      createTrackbar 函数,用于创建一个可以调整数值的滑动条,并将滑动条依附至指定窗口。函数原型如下:
    int createTrackbar(const String& trackbarname, const String& winname, int *value, int count, TrackbarCallback onChange = 0, void* userdata = 0);
    

    第一个参数:const String& 类型变量,滑动条的标识符。
    第二个参数:const String& 类型变量,要依附的窗口的标识符。
    第三个参数:int* 类型变量,一个指向整型的指针,表示滑块的位置。
    第四个参数:int 类型变量,表示滑块滑块可以到达的最大位置。滑块最小位置为 0。
    第五个参数:TrackbarCallback 类型的 onChange,默认值为 0。一个指向回调函数的指针。每次滑动条位置改变,都会回调这个函数。可以在 highgui.hpp 头文件中找到定义 typedef void (*TrackbarCallback)(int pos, void* userdata); 指向的指针必须为 void (int ,void*)类型。第一个参数为滑块的位置,第二个参数为用户想要传递的数据。
    第六个参数:void* 类型的变量,默认值为 0。这个参数会作为回调函数的第二个参数。

    • 测试程序
    #include <iostream>
    #include <opencv2/opencv.hpp>
    //窗口宏
    #define WINDOW_NAME "Trackbar Demo"
    
    //滑动条最大值
    const int g_nMaxAlphaValue = 100;
    
    //滑动条对应变量
    int g_nAlphaValueSlider;
    double g_dAlphaValue;
    double g_dBetaValue;
    
    //图像
    cv::Mat g_srcImage1;
    cv::Mat g_srcImage2;
    cv::Mat g_dstImage;
    
    void on_Trackbar(int count, void* userdata){
        //计算 alpha 值
        g_dAlphaValue = (double) g_nAlphaValueSlider/g_nMaxAlphaValue;
    
        //计算 beta 值
        g_dBetaValue = 1 - g_dAlphaValue;
        
        //线性混合(这个函数放到后面学)
        cv::addWeighted(g_srcImage1, g_dAlphaValue, g_srcImage2, g_dBetaValue, 0.0, g_dstImage);
        
        //显示效果图
        cv::imshow(WINDOW_NAME, g_dstImage);
    }
    
    int main(int argc, const char * argv[]) {
    
        //载入图像
        g_srcImage1 = cv::imread("1.jpg");
        g_srcImage2 = cv::imread("2.jpg");
        
        //判断是否载入成功,失败返回 -1
        if ( !g_srcImage1.data || !g_srcImage2.data) {
            return -1;
        }
        
        //赋最大参数值
        g_nAlphaValueSlider = 70;
        
        //创建窗口
        cv::namedWindow(WINDOW_NAME);
        
        //创建滑动条
        cv::createTrackbar("TrackBar", WINDOW_NAME, &g_nAlphaValueSlider, g_nMaxAlphaValue, on_Trackbar);
        
        //初次混合
        on_Trackbar(g_nAlphaValueSlider, NULL);
        
        cv::waitKey();
        
        return 0;
    }
    
    透明值 70 效果图 透明值 100 效果图 透明值 0 效果图

    8. 鼠标操作:setMouseCallback 函数

    鼠标操作的消息传递和滑动条的消息传递方式很类似。setMouseCallback 函数原型如下:

    void setMouseCallback(const String &winname, MouseCallBack onMouse, void* userdata);
    
    • 第一个参数窗口标识符。
    • 第二个参数 MouseCallback 类型函数指针
    //highgui.hpp 头文件中
    /** @brief Callback function for mouse events. see cv::setMouseCallback
    @param event one of the cv::MouseEventTypes constants.
    @param x The x-coordinate of the mouse event.
    @param y The y-coordinate of the mouse event.
    @param flags one of the cv::MouseEventFlags constants.
    @param userdata The optional parameter.
     */
    typedef void (*MouseCallback)(int event, int x, int y, int flags, void* userdata);
    

    第一个参数:int 类型变量对应枚举值

    enum MouseEventTypes {
           EVENT_MOUSEMOVE      = 0, //!< indicates that the mouse pointer has moved over the window.
           EVENT_LBUTTONDOWN    = 1, //!< indicates that the left mouse button is pressed.
           EVENT_RBUTTONDOWN    = 2, //!< indicates that the right mouse button is pressed.
           EVENT_MBUTTONDOWN    = 3, //!< indicates that the middle mouse button is pressed.
           EVENT_LBUTTONUP      = 4, //!< indicates that left mouse button is released.
           EVENT_RBUTTONUP      = 5, //!< indicates that right mouse button is released.
           EVENT_MBUTTONUP      = 6, //!< indicates that middle mouse button is released.
           EVENT_LBUTTONDBLCLK  = 7, //!< indicates that left mouse button is double clicked.
           EVENT_RBUTTONDBLCLK  = 8, //!< indicates that right mouse button is double clicked.
           EVENT_MBUTTONDBLCLK  = 9, //!< indicates that middle mouse button is double clicked.
           EVENT_MOUSEWHEEL     = 10,//!< positive and negative values mean forward and backward scrolling, respectively.
           EVENT_MOUSEHWHEEL    = 11 //!< positive and negative values mean right and left scrolling, respectively.
         };
    

    从枚举的名称不难看出其所代表的意义。

    int x, int y 参数代表鼠标指针在图像坐标系中的坐标。
    int flags 参数代表物理按键类型。对应枚举值如下:

    //! Mouse Event Flags see cv::MouseCallback
    enum MouseEventFlags {
           EVENT_FLAG_LBUTTON   = 1, //!< indicates that the left mouse button is down.
           EVENT_FLAG_RBUTTON   = 2, //!< indicates that the right mouse button is down.
           EVENT_FLAG_MBUTTON   = 4, //!< indicates that the middle mouse button is down.
           EVENT_FLAG_CTRLKEY   = 8, //!< indicates that CTRL Key is pressed.
           EVENT_FLAG_SHIFTKEY  = 16,//!< indicates that SHIFT Key is pressed.
           EVENT_FLAG_ALTKEY    = 32 //!< indicates that ALT Key is pressed.
         };
    

    *void userdata 参数代表自定义参数。

    • 第三个参数:*void userdata 参数代表自定义参数。

    相关文章

      网友评论

        本文标题:与OpenCV的第三天

        本文链接:https://www.haomeiwen.com/subject/zwivbttx.html