张学志の博客

记录学习的技能和遇到的问题

OpenCV学习笔记1

博客新址: http://blog.xuezhisd.top
邮箱:xuezhisd@126.com


地平线机器人——嵌入式人工智能领导者 长期招聘计算机视觉/深度学习等方向的工程师或实习生。感兴趣的话,请发送邮件,可以内推


参考

读入,显示,保存图像

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace cv;

int main()
{
    // 读入图像
    Mat img = imread("lena.jpg");
    // 显示图像
    namedWindow("原图");
    imshow("原图", img);
    // 保存图像
    imwrite("lena_result.jpg",img);  
    //等待用户操作
    waitKey();

    return 0;
}

ROI操作,掩膜操作,复制

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace cv;

int main()
{
    //【1】读入图像  
    Mat srcImage1= imread("dota_pa.jpg");  
    Mat logoImage= imread("dota_logo.jpg");  

    //【2】定义一个Mat类型并给其设定ROI区域  
    Mat imageROI= srcImage1(Rect(200,250,logoImage.cols,logoImage.rows));  

    //【3】加载掩模(必须是灰度图)  
    Mat mask= imread("dota_logo.jpg",0);  

    //【4】将掩膜拷贝到ROI  
    logoImage.copyTo(imageROI,mask);  

    //【5】显示结果  
    namedWindow("<1>利用ROI实现图像叠加示例窗口");  
    imshow("<1>利用ROI实现图像叠加示例窗口",srcImage1);  

    waitKey();

    return 0;
}

线性混合

  • 公式:dst = src1[I]*alpha+ src2[I]*beta + gamma;
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace cv;

int main()
{
    //【0】定义一些局部变量  
    double alphaValue = 0.5;  
    double betaValue;  
    Mat srcImage2, srcImage3, dstImage;  

    //【1】读取图像 ( 两幅图片需为同样的类型和尺寸 )  
    srcImage2= imread("mogu.jpg");  
    srcImage3= imread("rain.jpg");  
    if(!srcImage2.data ) { printf("你妹,读取srcImage2错误~! \n"); return false; }  
    if(!srcImage3.data ) { printf("你妹,读取srcImage3错误~! \n"); return false; }  

    //【2】做图像混合加权操作  
    betaValue= ( 1.0 - alphaValue );  
    addWeighted(srcImage2, alphaValue, srcImage3, betaValue, 0.0, dstImage);  

    //【3】创建并显示原图窗口  
    namedWindow("<1>线性混合示例窗口【原图】 by浅墨", 1);  
    imshow("<1>线性混合示例窗口【原图】 by浅墨", srcImage2 );  
    namedWindow("<2>线性混合示例窗口【原图】 by浅墨", 1);  
    imshow("<2>线性混合示例窗口【原图】 by浅墨", srcImage3 );  
    namedWindow("<3>线性混合示例窗口【效果图】 by浅墨", 1);  
    imshow("<3>线性混合示例窗口【效果图】 by浅墨", dstImage );  

    waitKey();

    return 0;
}

设置ROI,图像加权和(线性混合)

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace cv;

int main()
{
    //载入图片  
    Mat image= imread("dota.jpg",199);  
    Mat logo= imread("dota_logo.jpg");  
    //载入后先显示  
    namedWindow("原图");  
    imshow("原图",image);  
    namedWindow("logo图");  
    imshow("logo图",logo);  

    // 创建并设置ROI
    Mat imageROI;  
    //方法一  
    imageROI=image(Rect(800,350,logo.cols,logo.rows));  
    //方法二  
    //imageROI=image(Range(350,350+logo.rows),Range(800,800+logo.cols));  

    // ROI区域的加权和(图像融合)
    addWeighted(imageROI,0.5,logo,0.3,0.,imageROI);  

    namedWindow("原图+logo图");
    imshow("原图+logo图", image);

    //等待用户操作
    waitKey();

    return 0;
}

分离颜色通道,多颜色通道混合

  • 混合公式:
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace cv;
using namespace std;

int main()
{
    system("color5E"); 

    //【0】定义相关变量  
    Mat srcImage;  
    Mat logoImage;  
    vector<Mat>channels;  
    Mat  imageBlueChannel;  

    //=================【蓝色通道部分】=================  
    //     描述:多通道混合-蓝色分量部分  
    //============================================  

    //【1】读入图片  
    logoImage=imread("dota_logo.jpg",0);  
    srcImage=imread("dota_jugg.jpg");  
    if(!logoImage.data ) { printf("Oh,no,读取logoImage错误~!\n"); return false; }  
    if(!srcImage.data ) { printf("Oh,no,读取srcImage错误~!\n"); return false; }  

    //【2】把一个3通道图像转换成3个单通道图像  
    split(srcImage,channels);//分离色彩通道  

    //【3】将原图的蓝色通道引用返回给imageBlueChannel,注意是引用,相当于两者等价,修改其中一个另一个跟着变  
    imageBlueChannel=channels.at(0);  
    //【4】将原图的蓝色通道的(500,250)坐标处右下方的一块区域和logo图进行加权操作,将得到的混合结果存到imageBlueChannel中  
    addWeighted(imageBlueChannel(Rect(500,250,logoImage.cols,logoImage.rows)),1.0,  
        logoImage,0.5,0,imageBlueChannel(Rect(500,250,logoImage.cols,logoImage.rows)));  

    //【5】将三个单通道重新合并成一个三通道  
    merge(channels,srcImage);  

    //【6】显示效果图  
    namedWindow("<1>游戏原画+logo蓝色通道 by浅墨");  
    imshow("<1>游戏原画+logo蓝色通道 by浅墨",srcImage);  

    waitKey();

    return 0;
}

滚动条,查找轮廓

//-----------------------------------【头文件包含部分】---------------------------------------  
    //  描述:包含程序所依赖的头文件  
    //----------------------------------------------------------------------------------------------   
#include "opencv2/imgproc/imgproc.hpp"  
#include "opencv2/highgui/highgui.hpp"  
#include <iostream>  

    //-----------------------------------【命名空间声明部分】---------------------------------------  
    //  描述:包含程序所使用的命名空间  
    //-----------------------------------------------------------------------------------------------     
    using namespace cv;  
    using namespace std;  

//-----------------------------------【全局函数声明部分】--------------------------------------  
//  描述:全局函数声明  
//-----------------------------------------------------------------------------------------------  
Mat img;  
int threshval = 160;            //轨迹条滑块对应的值,给初值160  

//-----------------------------【on_trackbar( )函数】------------------------------------  
//  描述:轨迹条的回调函数  
//-----------------------------------------------------------------------------------------------  
static void on_trackbar(int, void*)  
{  
    Mat bw = threshval < 128 ? (img < threshval) : (img > threshval);  

    //定义点和向量  
    vector<vector<Point> > contours;  
    vector<Vec4i> hierarchy;  

    //查找轮廓  
    findContours( bw, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );  
    //初始化dst  
    Mat dst = Mat::zeros(img.size(), CV_8UC3);  
    //开始处理  
    if( !contours.empty() && !hierarchy.empty() )  
    {  
        //遍历所有顶层轮廓,随机生成颜色值绘制给各连接组成部分  
        int idx = 0;  
        for( ; idx >= 0; idx = hierarchy[idx][0] )  
        {  
            Scalar color( (rand()&255), (rand()&255), (rand()&255) );  
            //绘制填充轮廓  
            drawContours( dst, contours, idx, color, CV_FILLED, 8, hierarchy );  
        }  
    }  
    //显示窗口  
    imshow( "Connected Components", dst );  

    int posInt = getTrackbarPos("Threshold", "Connected Components");
    std::cout << "当前轨迹条位置:" << posInt << std::endl;
}  


//-----------------------------------【main( )函数】--------------------------------------------  
//  描述:控制台应用程序的入口函数,我们的程序从这里开始  
//-----------------------------------------------------------------------------------------------  
int main(  )  
{  
    //system("color 5F");    
    //载入图片  
    img = imread("girl.jpg", 0);  
    if( !img.data ) { printf("Oh,no,读取img图片文件错误~! \n"); return -1; }  

    //显示原图  
    namedWindow( "Image", 1 );  
    imshow( "Image", img );  

    //创建处理窗口  
    namedWindow( "Connected Components", 1 );  
    //创建轨迹条  
    createTrackbar( "Threshold", "Connected Components", &threshval, 255, on_trackbar );  
    on_trackbar(threshval, 0);//轨迹条回调函数  

    waitKey(0);  
    return 0;  
}  

亮度和对比度调整

  • 点操作(亮度调整,对比度调整,颜色校正,颜色变换)
  • 公式:g(x) = a*f(x) + bg(i,j) = a*f(i,j) + b
    • a为增益,控制图像的对比度。
    • b为偏置,控制图像的亮度。
//-----------------------------------【程序说明】----------------------------------------------
//  程序名称::【OpenCV入门教程之四】 创建Trackbar&图像对比度、亮度值调整 配套博文源码
// VS2010版  OpenCV版本:2.4.8
//  2014年3月18 日 Create by 浅墨
//------------------------------------------------------------------------------------------------


//-----------------------------------【头文件包含部分】---------------------------------------
//     描述:包含程序所依赖的头文件
//----------------------------------------------------------------------------------------------
#include <opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include"opencv2/imgproc/imgproc.hpp"
#include <iostream>

//-----------------------------------【命名空间声明部分】---------------------------------------
//     描述:包含程序所使用的命名空间
//-----------------------------------------------------------------------------------------------  
using namespace std;
using namespace cv;


//-----------------------------------【全局函数声明部分】--------------------------------------
//     描述:全局函数声明
//-----------------------------------------------------------------------------------------------
static void ContrastAndBright(int, void *);

//-----------------------------------【全局变量声明部分】--------------------------------------
//     描述:全局变量声明
//-----------------------------------------------------------------------------------------------
int g_nContrastValue; //对比度值
int g_nBrightValue;  //亮度值
Mat g_srcImage,g_dstImage;
//-----------------------------------【main( )函数】--------------------------------------------
//     描述:控制台应用程序的入口函数,我们的程序从这里开始
//-----------------------------------------------------------------------------------------------
int main(  )
{
    //改变控制台前景色和背景色
    system("color5F"); 

    //读入用户提供的图像
    g_srcImage= imread( "pic1.jpg");
    if(!g_srcImage.data ) { printf("Oh,no,读取g_srcImage图片错误~!\n"); return false; }
    g_dstImage= Mat::zeros( g_srcImage.size(), g_srcImage.type() );

    //设定对比度和亮度的初值
    g_nContrastValue=80;
    g_nBrightValue=80;

    //创建窗口
    namedWindow("【效果图窗口】", 1);

    //创建轨迹条
    createTrackbar("对比度:", "【效果图窗口】",&g_nContrastValue,300,ContrastAndBright );
    createTrackbar("亮   度:","【效果图窗口】",&g_nBrightValue,200,ContrastAndBright );

    //调用回调函数
    ContrastAndBright(g_nContrastValue,0);
    ContrastAndBright(g_nBrightValue,0);

    //按下“q”键时,程序退出
    while(char(waitKey(1)) != 'q') {}
    return 0;
}


//-----------------------------【ContrastAndBright( )函数】------------------------------------
//     描述:改变图像对比度和亮度值的回调函数
//-----------------------------------------------------------------------------------------------
static void ContrastAndBright(int, void *)
{

    //创建窗口
    namedWindow("【原始图窗口】", 1);

    //三个for循环,执行运算 g_dstImage(i,j) =a*g_srcImage(i,j) + b
    for(int y = 0; y < g_srcImage.rows; y++ )
    {
        for(int x = 0; x < g_srcImage.cols; x++ )
        {
            for(int c = 0; c < 3; c++ )
            {
                g_dstImage.at<Vec3b>(y,x)[c]= saturate_cast<uchar>( (g_nContrastValue*0.01)*(g_srcImage.at<Vec3b>(y,x)[c] ) + g_nBrightValue );
            }
        }
    }

    //显示图像
    imshow("【原始图窗口】", g_srcImage);
    imshow("【效果图窗口】", g_dstImage);
}

线性邻域滤波

  • 平滑滤波是低频增强的空间域滤波技术。它的目的有两类:一类是模糊;另一类是消除噪音。
  • 方框滤波——boxblur函数
  • 均值滤波(邻域平均滤波)——blur函数
  • 高斯滤波——GaussianBlur函数
  • 中值滤波——medianBlur函数
  • 双边滤波——bilateralFilter函数
  • 几种常见的线性滤波器:
    • 允许低频率通过的低通滤波器。
    • 允许高频率通过的高通滤波器。
    • 允许一定范围频率通过的带通滤波器。
    • 阻止一定范围频率通过并且允许其它频率通过的带阻滤波器。
    • 允许所有频率通过、仅仅改变相位关系的全通滤波器。
    • 阻止一个狭窄频率范围通过的特殊带阻滤波器,陷波滤波器(Band-stop filter)。
  • 低通就是模糊,高通就是锐化。
  • 均值滤波是方框滤波归一化(normalized)后的特殊情况。
  • 非归一化(Unnormalized)的方框滤波用于计算每个像素邻域内的积分特性,比如密集光流算法(dense optical flow algorithms)中用到的图像倒数的协方差矩阵

  • 方框滤波,均值滤波和高斯滤波

#include <opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include"opencv2/imgproc/imgproc.hpp"
#include <iostream>

using namespace std;
using namespace cv;

int main(  )
{
    Mat img = imread("lena.jpg");
    namedWindow("原图",1);
    imshow("原图",img);

    // 方框滤波
    Mat res;
    boxFilter(img, res, -1, Size(5,5));
    namedWindow("boxFilter()滤波【均值】",1);
    imshow("boxFilter()滤波【均值】",res);

    // blur滤波
    Mat out;  
    blur(img, out, Size(7, 7));  
    namedWindow("blur()滤波【均值】",1);
    imshow("blur()滤波【均值】",out);

    //高斯滤波
    Mat outG;  
    GaussianBlur( img, outG, Size( 5, 5 ), 0, 0 ); 
    namedWindow("GaussianBlur()滤波",1);
    imshow("GaussianBlur()滤波",outG);

    waitKey(0);

    return 0;
}

非线性滤波

  • 中值滤波,双边滤波
  • 双边滤波器的好处是可以做边缘保存。
#include <opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include"opencv2/imgproc/imgproc.hpp"
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
    Mat img = imread("lena.jpg");
    namedWindow("原图",1);
    imshow("原图",img);

    // 中值滤波
    Mat res;
    medianBlur(img, res, 7);
    namedWindow("中值滤波",1);
    imshow("中值滤波",res);

    // 双边滤波
    Mat out;  
    bilateralFilter(img, out, 25, 25*2, 25/2);  
    namedWindow("双边滤波",1);
    imshow("双边滤波",out);

    waitKey(0);

    return 0;

}

形态学操作-膨胀和腐蚀

  • 二值膨胀和腐蚀、开和闭运算,骨架抽取,极限腐蚀,击中击不中变换,形态学梯度,Top-hat变换,颗粒分析,流域变换,灰值腐蚀和膨胀,灰值开闭运算和灰值形态学梯度。
  • 腐蚀和膨胀是对白色部分(高亮部分)而言的,不是黑色部分。膨胀就是图像中的高亮部分进行膨胀,“领域扩张”。腐蚀就是原图中的高亮部分被腐蚀。
  • 膨胀就是求局部最大值的操作。
  • 腐蚀就是求局部最小值的操作。
#include <opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include"opencv2/imgproc/imgproc.hpp"
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
    Mat img = imread("lena.jpg");
    namedWindow("原图");
    imshow("原图", img);

    // 膨胀操作
    Mat element = getStructuringElement(MORPH_RECT, Size(15,15));
    Mat out;
    dilate(img, out, element);
    namedWindow("膨胀");
    imshow("膨胀", out);

    // 腐蚀操作
    Mat out2;
    erode(img, out2, element);
    namedWindow("腐蚀");
    imshow("腐蚀",out2);

    waitKey(0);

    return 0;

}

形态学操作-开闭运算、梯度、顶帽,黑帽

  • 开运算,就是先腐蚀后膨胀的过程。
  • 闭运算, 就是先膨胀后腐蚀的过程。
  • 形态学梯度,就是膨胀图与腐蚀图之差。
  • 顶帽运算,就是原图像与“开运算“的结果图之差。
  • 黑帽运算,就是”闭运算“的结果图与原图像之差。
#include <opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include"opencv2/imgproc/imgproc.hpp"
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
    Mat img = imread("lena.jpg");
    namedWindow("原图");
    imshow("原图", img);
    // 开运算
    Mat element = getStructuringElement(MORPH_RECT, Size(15,15));
    Mat out1;
    morphologyEx(img, out1, MORPH_OPEN, element);
    namedWindow("开运算");
    imshow("开运算", out1);
    // 闭运算
    Mat out2;
    morphologyEx(img, out2, MORPH_CLOSE, element);
    namedWindow("闭运算");
    imshow("闭运算", out2);
    // 形态学梯度
    Mat out3;
    morphologyEx(img, out3, MORPH_GRADIENT, element);
    namedWindow("形态学梯度");
    imshow("形态学梯度", out3);
    // 顶帽运算
    Mat out4;
    morphologyEx(img, out4, MORPH_TOPHAT, element);
    namedWindow("顶帽运算");
    imshow("顶帽运算", out4);
    // 黑帽运算
    Mat out5;
    morphologyEx(img, out5, MORPH_BLACKHAT, element);
    namedWindow("黑帽运算");
    imshow("黑帽运算", out5);
    // 腐蚀运算
    Mat out6;
    morphologyEx(img, out6, MORPH_ERODE, element);
    namedWindow("腐蚀运算");
    imshow("腐蚀运算", out6);
    // 膨胀运算
    Mat out7;
    morphologyEx(img, out7, MORPH_DILATE, element);
    namedWindow("膨胀运算");
    imshow("膨胀运算", out7);

    waitKey(0);

    return 0;
}

边缘检测——Canny算子,Sobel算子,Laplace算子和Scharr滤波器

  • 边缘检测的一般步骤:
    • 滤波。降低噪声的干扰。
    • 增强。
    • 检测。
  • Canny算子。多级边缘检测算法。推荐的高低阈值比在2:1到3:1之间。
  • Sobel算子结合了高斯平滑和微分求导,用来计算图像灰度函数的近似梯度。
  • Laplacian 算子是n维欧几里德空间中的一个二阶微分算子,定义为梯度grad()的散度div()。

  • Canny边缘检测

#include <opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include"opencv2/imgproc/imgproc.hpp"
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
    Mat img = imread("lena.jpg");
    namedWindow("原图");
    imshow("原图", img);
    // Canny边缘检测
    Mat out1;
    Canny(img, out1, 3, 9, 3);
    namedWindow("Canny边缘检测");
    imshow("Canny边缘检测", out1);


    waitKey(0);

    return 0;
}
  • Sobel边沿检测
#include <opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include"opencv2/imgproc/imgproc.hpp"
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
    Mat img = imread("lena.jpg");
    namedWindow("原图");
    imshow("原图", img);
    // Sobel边缘检测
    Mat grad_x, grad_y;  
    Mat abs_grad_x, abs_grad_y,dst;  
    // x方向梯度
    Sobel( img, grad_x, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT );  
    convertScaleAbs(grad_x, abs_grad_x);
    namedWindow("x方向 Sobel边缘检测");
    imshow("x方向 Sobel边缘检测", abs_grad_x);
    // y方向梯度
    Sobel( img, grad_y, CV_16S, 0, 1, 3, 1, 1, BORDER_DEFAULT );  
    convertScaleAbs(grad_x, abs_grad_y);
    namedWindow("y方向 Sobel边缘检测");
    imshow("y方向 Sobel边缘检测", abs_grad_y);
    // 合并梯度
    addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, dst );  
    imshow("整体方向Sobel", dst);  

    waitKey(0);

    return 0;
}
  • Laplacian算子
#include <opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include"opencv2/imgproc/imgproc.hpp"
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
    Mat src = imread("lena.jpg");
    namedWindow("原图");
    imshow("原图", src);
    // Laplacian边缘检测
    Mat src_gray, dst, abs_dst;
    GaussianBlur(src, src, Size(3,3), 0, 0, BORDER_DEFAULT); //高斯平滑,降低噪声
    cvtColor(src, src_gray, CV_RGB2GRAY); // RGB→Gray
    Laplacian(src_gray, dst, CV_16S, 3, 1, 0, BORDER_DEFAULT);
    convertScaleAbs(dst, abs_dst);

    namedWindow("拉普拉斯边缘检测");
    imshow("拉普拉斯边缘检测", abs_dst);

    waitKey(0);
    return 0;
}
  • Scharr滤波器
  • 它在OpenCV中主要是配合Sobel算子的运算而存在的,一个万年备胎。
#include <opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include"opencv2/imgproc/imgproc.hpp"
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
    Mat src = imread("lena.jpg");
    namedWindow("原图");
    imshow("原图", src);
    // Scharr滤波
    Mat gray_x, gray_y;
    Mat abs_gray_x, abs_gray_y, dst;
    // x方向梯度
    Scharr(src, gray_x, CV_16S, 1, 0, 1,0, BORDER_DEFAULT);
    convertScaleAbs(gray_x, abs_gray_x);
    imshow("X方向Scharr滤波器", abs_gray_x);
    // y方向梯度
    Scharr(src, gray_y, CV_16S, 0, 1, 1, 0, BORDER_DEFAULT);
    convertScaleAbs(gray_y, abs_gray_y);
    imshow("y方向Scharr滤波器", abs_gray_y);
    //合并梯度
    addWeighted(abs_gray_x, 0.5, abs_gray_y, 0.5, 0, dst);
    imshow("合并梯度Scharr", dst);
    waitKey(0);
    return 0;
}

金字塔——高斯/拉普拉斯金字塔,图片尺寸缩放

  • 使用OpenCV函数 pyrUp 和 pyrDown 对图像进行向上和向下采样,缩放图像尺寸的resize函数。
  • 高斯金字塔(Gaussianpyramid): 用来向下采样,主要的图像金字塔
  • 拉普拉斯金字塔(Laplacianpyramid): 用来从金字塔低层图像重建上层未采样图像,在数字图像处理中也即是预测残差,可以对图像进行最大程度的还原,配合高斯金字塔一起使用。
  • 区别:高斯金字塔用来向下降采样图像,而拉普拉斯金字塔则用来从金字塔底层图像中向上采样重建一个图像。
  • 对图像向上采样:pyrUp函数
  • 对图像向下采样:pyrDown函数
  • 可以将拉普拉斯金字塔理解为高斯金字塔的逆形式。

  • resize()

#include <opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include"opencv2/imgproc/imgproc.hpp"
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
    Mat src = imread("lena.jpg");
    imshow("原图", src);

    Mat dstImage1, dstImage2;
    // 缩小二分之一
    resize(src, dstImage1, Size(src.cols/2, src.rows/2), (0,0), (0,0), 3);
    // 放大二倍
    resize(src, dstImage2, Size(src.cols*2, src.rows*2), (0,0), (0,0), 3);
    imshow("缩小图", dstImage1);
    imshow("放大图", dstImage2);
    waitKey(0);
    return 0;
}
  • pyrUp()和pyrDown()
#include <opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include"opencv2/imgproc/imgproc.hpp"
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
    Mat src = imread("lena.jpg");
    imshow("原图", src);
    Mat dstImage1, dstImage2;
    // 向上采样操作
    pyrUp( src, dstImage1, Size(src.cols*2, src.rows*2) );
    // 向下采样操作
    pyrDown( src, dstImage2, Size(src.cols/2, src.rows/2) );
    imshow("上采样", dstImage1);
    imshow("下采样", dstImage2);
    waitKey(0);
    return 0;
}

霍夫变换——霍夫线/圆变换

  • 霍夫变换(Hough Transform)是图像处理中的一种特征提取技术,该过程在一个参数空间中通过计算累计结果的局部最大值得到一个符合该特定形状的集合作为霍夫变换结果。
  • 霍夫变换运用两个坐标空间之间的变换将在一个空间中具有相同形状的曲线或直线映射到另一个坐标空间的一个点上形成峰值,从而把检测任意形状的问题转化为统计峰值问题。
  • 霍夫变换在OpenCV中分为霍夫线变换和霍夫圆变换两种。
  • 霍夫线变换是一种用来寻找直线的方法。在使用霍夫线变换之前, 首先要对图像进行边缘检测的处理。
  • OpenCV支持三种不同的霍夫线变换,它们分别是:标准霍夫变换(Standard Hough Transform,SHT)和多尺度霍夫变换(Multi-Scale Hough Transform,MSHT)累计概率霍夫变换(Progressive Probabilistic Hough Transform ,PPHT)。

  • HoughLines()

#include <opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include"opencv2/imgproc/imgproc.hpp"
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
    Mat src = imread("building.jpg");
    imshow("原图", src);
    Mat midImage,dstImage;//临时变量和目标图的定义  
    //边缘检测
    Canny(src, midImage, 50, 200, 3);
    cvtColor(midImage, dstImage, CV_GRAY2BGR); //转换成彩色图像,用于显示结果
    imshow("边缘检测", midImage);  
    //霍夫线检测
    vector<Vec2f> lines;
    HoughLines(midImage, lines, 1, CV_PI/180, 150, 0, 0);
    //依次绘制每一条线
    for( size_t i = 0; i < lines.size(); i++ )  
    {  
        float rho = lines[i][0], theta = lines[i][1];  
        Point pt1, pt2;  
        double a = cos(theta), b = sin(theta);  
        double x0 = a*rho, y0 = b*rho;  
        pt1.x = cvRound(x0 + 1000*(-b));  
        pt1.y = cvRound(y0 + 1000*(a));  
        pt2.x = cvRound(x0 - 1000*(-b));  
        pt2.y = cvRound(y0 - 1000*(a));  
        line( dstImage, pt1, pt2, Scalar(55,100,195), 1, CV_AA);  
    }  
    imshow("霍夫线检测结果", dstImage);    

    waitKey(0);
    return 0;
}
  • HoughLinesP()
#include <opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include"opencv2/imgproc/imgproc.hpp"
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
    Mat src = imread("building.jpg");
    imshow("原图", src);
    Mat midImage,dstImage;//临时变量和目标图的定义  
    //边缘检测
    Canny(src, midImage, 50, 200, 3);
    cvtColor(midImage, dstImage, CV_GRAY2BGR); //转换成彩色图像,用于显示结果
    imshow("边缘检测", midImage);  
    //霍夫线检测
    vector<Vec4i> lines;
    HoughLinesP(midImage, lines, 1, CV_PI/180, 150, 0, 0);
    //依次绘制每一条线
    for( size_t i = 0; i < lines.size(); i++ )  
    {  
        Vec4i l = lines[i];  
        line( dstImage, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(23,180,55), 1, CV_AA);
    }  
    imshow("霍夫线检测结果", dstImage);    

    waitKey(0);
    return 0;
}
  • HoughCircles( )
#include <opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include"opencv2/imgproc/imgproc.hpp"
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
    Mat src = imread("circles.jpg");
    imshow("原图", src);
    Mat midImage,dstImage;//临时变量和目标图的定义  
    //边缘检测
    Canny(src, midImage, 50, 200, 3);
    cvtColor(midImage, dstImage, CV_GRAY2BGR); //转换成彩色图像,用于显示结果
    GaussianBlur( midImage, midImage, Size(9, 9), 2, 2 );  
    imshow("边缘检测", midImage);  

    //霍夫圆变换
    vector<Vec3f> circles;
    //HoughCircles( midImage, circles, CV_HOUGH_GRADIENT,1.5, 10, 200, 100, 0, 0 );  
    HoughCircles( midImage, circles, CV_HOUGH_GRADIENT,0.5, src.rows/8, 100, 100, 0, 0); 
    std::cout << circles.size() << std::endl;

    //依次绘制每一个圆
    for( size_t i = 0; i < circles.size(); i++ )  
    {  
        Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));  
        int radius = cvRound(circles[i][2]);  
        //绘制圆心  
        circle( src, center, 3, Scalar(0,255,0), -1, 8, 0 );  
        //绘制圆轮廓  
        circle( src, center, radius, Scalar(155,50,255), 3, 8, 0 );  
    }  
    imshow("霍夫圆变换结果", src);    

    waitKey(0);
    return 0;
}

漫水填充(floodFill)

  • 漫水填充法是一种用特定的颜色填充联通区域,通过设置可连通像素的上下限以及连通方式来达到不同的填充效果的方法。
  • 漫水填充,就是自动选择与种子点相连的区域,接着将该区域替换成指定的颜色,这是个非常有用的功能,经常用来标记或者分离图像的一部分进行处理或分析。漫水填充也可以用来从输入图像获取掩码区域,掩码会加速处理过程,或者只处理掩码指定的像素点。
#include <opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include"opencv2/imgproc/imgproc.hpp"
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
    Mat src = imread("lena.jpg");
    imshow("原图", src);
    //
    Rect ccomp;
    floodFill(src, Point(50, 300), Scalar(155, 255, 55), &ccomp, Scalar(20, 20, 20) );
    imshow("floodFill结果", src);

    waitKey(0);
    return 0;
}

Harris角点检测

#include <opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include"opencv2/imgproc/imgproc.hpp"
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
    Mat src = imread("lena.jpg");
    imshow("原图", src);
    // 转换成灰度图像
    Mat gray, normImage, scaledImage;
    cvtColor(src, gray, CV_RGB2GRAY);
    // 角点检测
    Mat cornerStrength;//临时变量和目标图的定义  
    cornerHarris(gray, cornerStrength, 2, 3, 0.01);  //输入需要是灰度图像
    // 归一化与转换  
    normalize( cornerStrength, normImage, 0, 255, NORM_MINMAX, CV_32FC1, Mat() );  
    convertScaleAbs( normImage, scaledImage );//将归一化后的图线性变换成8位无符号整型 
    imshow("角点检测结果", scaledImage);
    // 二值化,并显示
    Mat harrisCorner;
    threshold(cornerStrength, harrisCorner, 0.00001, 255, THRESH_BINARY);
    imshow("角点检测二值图", harrisCorner);

    waitKey(0);
    return 0;
}

重映射和Surf特征点检测

  • 重映射,就是把一幅图像中某位置的像素放置到另一个图片指定位置的过程。
  • SURF,我们简单介绍一下,英语全称为SpeededUp Robust Features。
  • URF最大的特征在于采用了harr特征以及积分图像的概念,这大大加快了程序的运行时间。
#include <opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include"opencv2/imgproc/imgproc.hpp"
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
    Mat src = imread("lena.jpg");
    imshow("原图", src);
    // 定义临时变量
    Mat map_x, map_y, dstImage;
    dstImage.create( src.size(), src.type() );  
    map_x.create( src.size(), CV_32FC1 );  
    map_y.create( src.size(), CV_32FC1 );  

    //双层循环,遍历每一个像素点,改变map_x & map_y的值——创建map
    for( int j = 0; j < src.rows;j++)  
    {   
        for( int i = 0; i < src.cols;i++)  
        {  
            //改变map_x & map_y的值.   
            map_x.at<float>(j,i) = static_cast<float>(i);  
            map_y.at<float>(j,i) = static_cast<float>(src.rows - j);  
        }   
    }  
    remap( src, dstImage, map_x, map_y, CV_INTER_LINEAR, BORDER_CONSTANT, Scalar(0,0, 0) );  

    imshow("重映射结果图", dstImage);

    waitKey(0);
    return 0;
}
阅读更多
版权声明:本文为博主原创文章,引用时请附上链接。 https://blog.csdn.net/xuezhisdc/article/details/63254312
文章标签: opencv
个人分类: OpenCV
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭