opencv入门

第一章 数字图像基础

1. opencv简介

OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉库,可以运行在Linux、Windows、Android和Mac OS操作系统上。它轻量级而且高效,由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。

Opencv其应用非常广泛,如无人机、无人驾驶等都能看到Opencv的踪迹,很多机器学习也都是基于opencv视觉库。要学好opencv,必看opencv官网,官网包含Opencv各个版本下载链接、Opencv各平台安装说明以及各API接口函数说明文档,是学习Opencv最好的网站。

学习Opencv不要上来就要弄明白各个细节,入门时,应该多实践,看着教程跑示例,先对Opencv有个基本的认知,再深入去了解背后的算法和c++语言。

2. Mat类

在正式介绍之前,先简单一下数字图像的基本概念。在计算机看来一副图像只是一堆亮度各异的点,一副尺寸为M × N的图像可以用一个M × N的矩阵来表示,阵元素的值表示这个位置上像素的亮度,一般来说越大该点亮。一般来说,灰度图用2维矩阵表示,彩色(多通道)图像用3维矩阵(M x N x 3)表示。对于图像显示来说,目前大部分设备都是用无符号8位整数(类型为CV_8U)表示像素亮度。

早期的 OpenCV 中,使用IplImage和CvMat数据结构来表示图像。IplImage和CvMat都是C语言的结构。使用这两个结构的问题是内存需要手动管理,开发者必须清楚的知道何时需要申请内存,释放内存。这个给开发者带来了一定的负担,开发者应该将更多精力用于算法设计,因此在新版本的 OpenCV中引入了Mat类。

Mat本质上是由两个数据部分组成的类:Header和Pointer。Header中主要包含矩阵的大小,存储方式,存储地址等信息,Pointer中存储指向像素值的指针。

示例一:创建3行两列5通道矩阵
#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main()
{
    Mat M(3,2,CV_8UC(5));
    cout<<M <<endl;
}
示例二:创建3行两列3通道矩阵,并赋值
#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main()
{
    Mat M(3,2,CV_8UC3,Scalar(0,0,255));
    cout <<"M="<<endl <<" "<<M <<endl;
}
示例三:特殊矩阵
#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main()
{
    //0矩阵
    Mat Z=Mat::zeros(2,3,CV_8UC1);
    cout<<Z<<endl;

    //1矩阵
    Mat O=Mat::ones(2,3,CV_32F);
    cout<<O<<endl;

    //单位矩阵
    Mat E=Mat::eye(2,3,CV_64F);
    cout<<E<<endl;
}

3. 图像显示

示例一:显示图片
#include <opencv2/opencv.hpp>
using namespace cv; 

int main()
{
    //读取图片,当前目录下,名为1.jpg的图片
    Mat img0=imread("1.jpg");
    //图像拷贝
    Mat img1=img0.clone();
    //图像拷贝
    Mat img2;
    img2=img0;
    //创建同大小,同类型图像,但并不拷贝像素点
    Mat img3;
    img3.create(img0.size(),img0.type());

    imshow("img0",img0);
    imshow("img1",img1);
    imshow("img2",img2);
    imshow("img3",img3);

    //这里一定要延时,因为imshow加载图片需要时间,这里0表示无限延时,停在此处
    waitKey(0);
}
示例二:at()函数遍历像素点,渐变赋值
#include <opencv2/opencv.hpp>
using namespace cv;

int main()
{
    //创建图像,大小为600*800
    Mat grayim(600,800,CV_8UC1);
    Mat colorim(600,800,CV_8UC3);

    for(int i=0;i<grayim.rows;++i)
        for(int j=0;j<grayim.cols;++j)
            grayim.at <uchar>(i,j)=(i+j)%255;

    for(int i=0;i<colorim.rows;++i)
        for(int j=0;j<colorim.cols;++j)
        {
            //Vec3b表示8U类型的RGB彩色图像向量
            //pixel变量描述RGB颜色
            Vec3b pixel;
            //0通道的B分量
            pixel[0]=i%255;
            //1通道的G分量
            pixel[1]=j%255;
            //2通道的R分量
            pixel[2]=0;
            colorim.at<Vec3b>(i,j)=pixel;
        }
    imshow("grayim",grayim);
    imshow("colorim",colorim);
    waitKey(0);
    return 0;
}
示例三:MatIterator_容器遍历像素点,随机赋值
#include <opencv2/opencv.hpp>
using namespace cv;

int main()
{
    Mat grayim(600,800,CV_8UC1);
    Mat colorim(600,800,CV_8UC3);

    MatIterator_<uchar> grayit,grayend;
    for(grayit=grayim.begin<uchar>(),grayend=grayim.end<uchar>();grayit!=grayend;++grayit)
        *grayit=rand()%255;

    MatIterator_<Vec3b> colorit,colorend;
    for(colorit=colorim.begin<Vec3b>(),colorend=colorim.end<Vec3b>();colorit!=colorend;
    ++colorit)
    {
        (*colorit)[0]=rand()%255;
        (*colorit)[1]=rand()%255;
        (*colorit)[2]=rand()%255;
    }

    imshow("grayim",grayim);
    imshow("colorim",colorim);

    waitKey(0);
    return 0;
}
示例四:打开摄像头
#include <opencv2/opencv.hpp>  
using namespace cv;  

int main()  
{  
    //从摄像头读入视频
    VideoCapture capture(0);
    //循环显示每一帧
    while(1)  
    {  
        //定义一个Mat变量,用于存储每一帧的图像
        Mat frame;
        //读取当前帧  
        capture>>frame;
        //显示当前帧  
        imshow("read video",frame);
        //延时30ms  
        waitKey(30);  
    }  
    return 0;     
}  
示例五:打开网络摄像头
//使用mjpg-streamer工具将图像发布到网络上
#include <iostream>
#include <opencv2/opencv.hpp>  

using namespace cv;
using namespace std;

int main(int, char**) 
{  
    VideoCapture vcap;  
    Mat image;  
    const std::string videoStreamAddress = "http://192.168.23.128:8080/?action=stream?dummy=param.mjpg";   
    /* it may be an address of an mjpeg stream,  
    e.g. "http://user:pass@cam_address:8081/cgi/mjpg/mjpg.cgi?.mjpg" */  

    //open the video stream and make sure it's opened  
    if(!vcap.open(videoStreamAddress)) 
    {  
        cout << "Error opening video stream or file" << endl;  
        return -1;  
    }  

    while(1)
    {  
        if(!vcap.read(image)) 
        {  
            cout << "No frame" << endl;  
            waitKey();  
        }  
        imshow("Output Window", image);  
        if(waitKey(1) >= 0) 
            break;  
    }     
}

第二章 数字图像处理

1. 图像滤波

图像滤波,即在尽量保留图像细节特征的条件下对目标图像的噪声进行抑制。消除图像中的噪声成分叫作图像的平滑化或滤波操作。信号或图像的能量大部分集中在幅度谱的低频和中频段是很常见的,而在较高频段,感兴趣的信息经常被噪声淹没。

图像滤波的目的有两个:一是抽出对象的特征作为图像识别的特征模式;另一个是为适应图像处理的要求,消除图像数字化时所混入的噪声。

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

//调整各滤波函数参数大小,观察滤波后的效果
int main()
{
    Mat src=imread("lena.jpg");
    Mat dst;
    //高斯滤波,低通就是模糊,高通就是锐化
    GaussianBlur(src,dst,Size(5,5),0,0);
    imwrite("gauss.jpg",dst);
    //中值滤波
    medianBlur(src,dst,3);
    imwrite("med.jpg",dst);
    //均值滤波
    blur(src,dst,Size(3,3),Point(-1,-1));
    imwrite("mean.jpg",dst);
    //双边滤波
    bilateralFilter(src,dst,5,10.0,2.0);
    //将生成的图片写入当前目录
    imwrite("bil.jpg",dst);

    waitKey();
    return 0;
}

2. 图像膨胀与腐蚀

膨胀与腐蚀能实现多种多样的功能,主要如下:

  1. 消除噪声
  2. 分割(isolate)出独立的图像元素,在图像中连接(join)相邻的元素
  3. 寻找图像中的明显的极大值区域或极小值区域
  4. 求出图像的梯度

腐蚀和膨胀是对白色部分(高亮部分)而言的,不是黑色部分。膨胀就是图像中的高亮部分进行膨胀,“领域扩张”,效果图拥有比原图更大的高亮区域。腐蚀就是原图中的高亮部分被腐蚀,“领域被蚕食”,效果图拥有比原图更小的高亮区域。

示例一:图像膨胀
#include <opencv2/opencv.hpp> 
using namespace cv;

int main()  
{    
    Mat image = imread("1.jpg");  
    imshow("src", image);
    //获取自定义核  
    Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));  
    Mat out;    
    //进行膨胀操作
    dilate(image,out, element);   
    imshow(" ", out);  
    waitKey(0);  
    return 0;  
} 
示例二:图像腐蚀
#include <opencv2/opencv.hpp> 
using namespace cv;

int main()
{
    Mat srcImage = imread("1.jpg");
    imshow("src", srcImage);
    //获取自定义核 
    Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));
    Mat dstImage;
    //进行腐蚀操作 
    erode(srcImage, dstImage, element);
    imshow(" ", dstImage);
    waitKey(0); 
    return 0;
}

3. 边缘检测

缘检测一般步骤:

  1. 滤波:边缘检测的算法主要是基于图像强度的一阶和二阶导数,但导数通常对噪声很敏感,因此必须采用滤波器来改善与噪声有关的边缘检测器的性能。
  2. 增强:增强边缘的基础是确定图像各点邻域强度的变化值。增强算法可以将图像灰度点邻域强度值有显著变化的点凸显出来。
  3. 检测:经过增强的图像,往往邻域中有很多点的梯度值比较大,而在特定的应用中,这些点并不是我们要找的边缘点,所以应该采用某种方法来对这些点进行取舍。实际工程中,常用的方法是通过阈值化方法来检测。

边缘检测有canny算子、laplace算子、sobel算子以及scharr算子算法

示例一:canny算子
#include <opencv2/opencv.hpp> 
using namespace cv;

int main()
{  
    Mat src=imread("1.jpg");  
    Mat src1=src.clone();  
    imshow("src",src);   

    Canny(src,src,150,100,3);  
    imshow("result1", src);   

    Mat dst,edge,gray;  

    //创建与src同类型和大小的矩阵(dst)  
    dst.create(src1.size(),src1.type());  
    //将原图像转换为灰度图像  
    cvtColor(src1,gray,CV_BGR2GRAY );  
    //先用使用3x3内核来降噪  
    blur(gray,edge,Size(3,3));  
    //运行Canny算子
    Canny(edge,edge,3,9,3);  
    //将dst内的所有元素设置为0   
    dst=Scalar::all(0);  
    //使用Canny算子输出的边缘图edge作为掩码,将原图src拷到目标图dst中
    //copyTo将src1中edge矩阵对应的非零部分复制到dst中  
    src1.copyTo(dst,edge);  
    imshow("result2",dst);

    waitKey(0);   
    return 0;
}
示例二:sobel算子

Sobel()算子是一个主要用作边缘检测的离散微分算子,它结合了高斯平滑和微分求导,用来计算图像灰度函数的近似梯度。在图像的任何一点使用此算子,将会产生对应的梯度矢量或是其法矢量。

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

int main()  
{  
    //创建 grad_x 和 grad_y 矩阵  
    Mat grad_x, grad_y;  
    Mat abs_grad_x, abs_grad_y,dst;  

    Mat src = imread("1.jpg");
    imshow("src",src);   

    //求 X方向梯度  
    Sobel(src,rad_x,CV_16S,1,0,3,1,1,BORDER_DEFAULT);  
    convertScaleAbs(grad_x, abs_grad_x);  
    imshow("X方向Sobel",abs_grad_x);   

    //求Y方向梯度  
    Sobel(src,grad_y,CV_16S,0,1,3,1,1,BORDER_DEFAULT );  
    convertScaleAbs(grad_y,abs_grad_y);  
    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;   
} 
示例三:laplace算子

laplacian()函数可以计算出图像经过拉普拉斯变换后的结果

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

int main()  
{  
    Mat src,src_gray,dst, abs_dst;    
    src = imread("1.jpg");  
    imshow("src", src);   

    //使用高斯滤波消除噪声  
    GaussianBlur(src,src,Size(3,3),0,0,BORDER_DEFAULT);  
    //转换为灰度图  
    cvtColor(src,src_gray,CV_RGB2GRAY);  
    //使用Laplace函数  
    Laplacian(src_gray,dst,CV_16S,3,1,0,BORDER_DEFAULT);  
    //计算绝对值,并将结果转换成8位  
    convertScaleAbs(dst,abs_dst );  

    imshow("图像Laplace变换",abs_dst);  
    waitKey(0);   

    return 0;   
}  
示例四:scharr滤波器

使用Scharr()滤波器运算符计算x或y方向的图像差分,它的参数变量和Sobel基本上是一样的,除了没有ksize核的大小。

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

int main( )  
{  
    //创建grad_x和grad_y矩阵  
    Mat grad_x, grad_y;  
    Mat abs_grad_x,abs_grad_y,dst;  

    Mat src = imread("1.jpg"); 
    imshow("src", src);   

    //求X方向梯度  
    Scharr(src,grad_x, CV_16S,1,0,1,0,BORDER_DEFAULT);  
    convertScaleAbs(grad_x, abs_grad_x );  
    imshow("X方向Scharr", abs_grad_x);   
    //求Y方向梯度  
    Scharr(src,grad_y,CV_16S,0,1,1,0,BORDER_DEFAULT);  
    convertScaleAbs(grad_y,abs_grad_y);  
    imshow("Y方向Scharr",abs_grad_y);   
    //合并梯度(近似)  
    addWeighted(abs_grad_x,0.5,abs_grad_y,0.5,0,dst);  

    imshow("合并梯度后Scharr",dst);   

    waitKey(0);   
    return 0;   
}  

4. 图像融合

addWeighted()这个函数的作用是,计算两个数组(图像阵列)的加权和。

void addWeighted(InputArray src1,double alpha, InputArray src2, double beta, double gamma, OutputArray dst, int dtype=-1);

  • src1:表示需要加权的第一个数组。
  • alpha:表示第一个数组的权重
  • src2:表示第二个数组,它需要和第一个数组拥有相同的尺寸和通道数。
  • beta:表示第二个数组的权重值。
  • dst:输出的数组,它和输入的两个数组拥有相同的尺寸和通道数。
  • gamma:一个加到权重总和上的标量值。
  • dtype:输出阵列的可选深度,有默认值-1。
#include <opencv2/opencv.hpp>
using namespace cv;

int main()
{
    Mat image1=imread("1.jpg",1);
    Mat image2=imread("2.jpg",1);
    Mat image;
    addWeighted(image1,0.8,image2,0.2,0.0,image);

    imshow("1",image1);
    imshow("2",image2);
    imshow("new",image);

    waitKey(0);
    return 0;
} 

5. 分离颜色通道

  • split()函数将一个多通道数组分离成几个单通道数组。
  • merge()函数的功能是split函数的逆向操作,将多个数组组合合并成一个多通道的数组。
#include <opencv2/opencv.hpp>
using namespace cv;

int main()
{
    Mat srcImage;
    Mat grayImage;
    Mat imageBlueChannel;
    vector<Mat>channels;

    srcImage=imread("1.jpg");
    imshow("src",srcImage);
    //读取灰度图像
    grayImage=imread("1.jpg",0);
    //分离颜色通道
    split(srcImage,channels);
    //选取蓝色通道
    imageBlueChannel=channels.at(0);
    //融合蓝色通道与灰度图像
    addWeighted(imageBlueChannel,1.0,grayImage,0.5,0.0,imageBlueChannel);
    //合并颜色通道,相当于对原图像蓝色通道加强
    merge(channels,imageBlueChannel);
    imshow("blue",imageBlueChannel);

    waitKey(0);
    return 0;
}
}

6. RGB与HSV空间转换

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

int main()
{
    Mat srcImage=imread("1.jpg");
    cvtColor(srcImage,srcImage,COLOR_BGR2HSV);
    imshow(" ",srcImage);
    waitKey();
}

第三章 图像缩放

1. 图像旋转

getRotationMatrix2D()函数主要用于获得图像绕着某一点的旋转矩阵。

getRotationMatrix2D(Point2f center,double angle,double scale)

  • Point2f center:表示旋转的中心点。
  • double angle:表示旋转的角度。
  • double scale:图像缩放因子。
#include <opencv2/opencv.hpp>
using namespace cv;

void img_rotate(Mat src_img,Mat* rotate_img,int angle)
{
    Point2f center=Point2f(src_img.cols/2,src_img.rows/2);
    Mat rotateMat=getRotationMatrix2D(center,angle,1);
    warpAffine(src_img,*rotate_img,rotateMat,src_img.size()); 
}

int main()
{
    Mat srcImage,dstImage;
    srcImage=imread("1.jpg");
    img_rotate(srcImage,&dstImage,180);
    imshow(" ",dstImage);
    waitKey();
}

2. 图像缩放

示例一:resize函数

resize()函数将源图像精确地转换为指定尺寸的目标图像。

void resize(InputArray src,OutputArray dst, Size dsize, double fx=0, double fy=0, int interpolation=INTER_LINEAR )

  • src:输入图像。
  • dst:输出图像。
  • dsize:输出图像的大小。
  • fx:沿水平轴的缩放系数。
  • fy:沿垂直轴的缩放系数。
  • interpolation:用于指定插值方式,默认为INTER_LINEAR(线性插值)。
#include <opencv2/opencv.hpp>
using namespace cv;

int main()
{
    Mat srcImage = imread("1.jpg");
    Mat tmpImage,dstImage1,dstImage2;
    tmpImage=srcImage;

    //进行尺寸调整操作
    resize(tmpImage,dstImage1,Size( tmpImage.cols/2, tmpImage.rows/2 ),(0,0),(0,0),3);
    resize(tmpImage,dstImage2,Size( tmpImage.cols*2, tmpImage.rows*2 ),(0,0),(0,0),3);

    imshow("resize1", dstImage1);  
    imshow("resize2", dstImage2);  

    waitKey(0);  
    return 0;  
}
示例二:pyrUp函数

pyrUp()函数的作用是向上采样并模糊一张图像,说白了就是放大一张图片。

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

int main()  
{     
    Mat srcImage = imread("1.jpg");
    Mat tmpImage,dstImage;
    tmpImage=srcImage;
    imshow("srcImage", srcImage);  
    pyrUp( tmpImage, dstImage, Size( tmpImage.cols*2, tmpImage.rows*2 ) );  

    imshow("dstImage", dstImage);    
    waitKey(0);    
    return 0;    
}
示例三:pyrDown函数

pyrDown()函数的作用是向下采样并模糊一张图片,说白了就是缩小一张图片。

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

int main()  
{    
    Mat srcImage = imread("1.jpg");
    Mat tmpImage,dstImage;  
    tmpImage=srcImage;
    imshow("srcImage", srcImage);      
    pyrDown( tmpImage, dstImage, Size( tmpImage.cols/2, tmpImage.rows/2 ) );    
    imshow("dstImage", dstImage);    

    waitKey(0);    
    return 0;    
}  

第四章 图像分割

1. 图像分割

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

//剪切图片为m * n 块  
void Cut_img(Mat src_img,int m,int n,Vector<Mat> ceil_img)
{  
    int t = m * n;  
    int height = src_img.rows;  
    int width  = src_img.cols;  

    int ceil_height = height/m;  
    int ceil_width  = width/n;   

    Mat roi_img,tmp_img;  

    Point p1,p2;  
    for(int i = 0;i<m;i++)  
        for(int j = 0;j<n;j++)
        {   
            Rect rect(i+j*ceil_width,j+i*ceil_height,ceil_width,ceil_height);  
            src_img(rect).copyTo(roi_img);  
            ceil_img.push_back(roi_img);  
            imshow("roi_img",roi_img); 
            //关闭当前显示中的图像,才可以显示其他图像   
            waitKey(0);   
        }     
}  
int main()  
{  
    Mat img = imread("lena.jpg",1);  
    imshow("src img",img);  
    int m = 3;  
    int n = 3;

    Vector<Mat> ceil_img = m*n;
    Cut_img(img,m,n,ceil_img);  
    waitKey();  
    return 0;  
} 

2. 获取感兴趣区

#include <opencv2/opencv.hpp> 

using namespace cv;
using namespace std;

void getROI(Mat src_image,Mat* dst_roi,Rect rect);//获取兴趣区
void setRect(Rect* rect,int x,int y,int width,int height);//设置矩形区

int main()
{
    Mat image=imread("1.jpg");
    Mat roi;
    Rect rect;

    imshow("Origin",image);
    cout<<"width:"<<image.cols<<" "<<"height:"<<image.rows<<endl;

    setRect(&rect,320,240,150,150);
    getROI(image,&roi,rect);

    imshow("ROI",roi);
    waitKey(0);
    return 0;
}

void setRect(Rect* rect,int x,int y,int width,int height)
{
    (*rect).x=x;
    (*rect).y=y;
    (*rect).width=width;
    (*rect).height=height;
}

void getROI(Mat src_image,Mat* dst_roi,Rect rect)
{
    Mat img=src_image.clone();

    int cols=img.cols,rows=img.rows;
    if(cols - 1 - rect.x<rect.width||rows - 1 - rect.y<rect.height)
        cout<<"over area!"<<endl;
    *dst_roi=img(Rect(rect.x,rect.y,rect.width,rect.height));
}

3. 图像拼接

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

int main()
{  
    Mat combine1,combine2,combine;
    Mat img1 = imread("1.jpg",1);
    Mat img2 = imread("2.jpg",1); 
    Mat img3 = imread("3.jpg",1); 
    Mat img4 = imread("4.jpg",1); 

    hconcat(img1,img2,combine1);  
    hconcat(img3,img4,combine2);  
    vconcat(combine1,combine2,combine);

    imshow("roi_img",roi_img);    
    waitKey(0);
}   

第五章 图像识别

1. 直线识别

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

int main()  
{  
    Mat srcImage = imread("1.jpg");
    Mat midImage,dstImage;  

    Canny(srcImage, midImage, 50, 200, 3);
    cvtColor(midImage,dstImage, CV_GRAY2BGR);

    vector<Vec4i> lines; 
    HoughLinesP(midImage, lines, 1, CV_PI/180, 80, 50, 10 );  

    //依次在图中绘制出每条线段  
    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(186,88,255),1,CV_AA);  
    }   
    imshow(" ", dstImage);    
    waitKey(0);    

    return 0;    
}

2. 矩形识别

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

int main()
{
    Mat src_image=imread("1.jpg");
    Mat gray_image;
    cvtColor(src_image,gray_image,CV_BGR2GRAY);
    imshow("src",src_image);
    Mat binary_image;

    //局部自适应二值化函数
    adaptiveThreshold(gray_image,binary_image,255,CV_ADAPTIVE_THRESH_MEAN_C,CV_THRESH_BINARY_INV,25,10);  

    imshow("binary",binary_image);

    Mat de_noise=binary_image.clone();
    medianBlur(binary_image,de_noise,5); //中值滤波 

    Mat dilate_image;//膨胀
    Mat element=getStructuringElement(MORPH_RECT,Size(20,20));
    dilate(de_noise,dilate_image,element);
    imshow("dilate",dilate_image);

    //外部加框,检测连通域,每一个连通域以一系列的点表示,FindContours方法只能得到第一个域
    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;

    //CV_RETR_EXTERNAL只检测外部轮廓,可根据自身需求进行调整  
    findContours(dilate_image,contours,hierarchy,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_NONE);

    Mat contours_image(dilate_image.rows,dilate_image.cols,CV_8U,Scalar(255));
    int index=0;
    for(;index>=0;index=hierarchy[index][0])
    {
        Scalar color(rand()&255,rand()&255,rand()&255);
        drawContours(contours_image,contours,index,Scalar(0),1,8,hierarchy);//描绘字符的外轮廓
        Rect rect=boundingRect(contours[index]);//检测外轮廓  
        rectangle(contours_image,rect,Scalar(0,0,255),3);//对外轮廓加矩形框 
    }
    imshow("zt",contours_image);

    waitKey(0);
}

3. 圆形识别

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

int main()  
{      
    Mat srcImage = imread("1.jpg");  
    Mat midImage,dstImage;

    cvtColor(srcImage,midImage, CV_BGR2GRAY);//转化边缘检测后的图为灰度图  
    GaussianBlur( midImage, midImage, Size(9, 9), 2, 2 );  

    vector<Vec3f> circles;  
    HoughCircles( midImage, circles, CV_HOUGH_GRADIENT,1.5, 10, 200, 100, 0, 0 );  

    //依次在图中绘制出圆  
    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( srcImage, center, 3, Scalar(0,255,0), -1, 8, 0 );  
        //绘制圆轮廓  
        circle( srcImage, center, radius, Scalar(155,50,255), 3, 8, 0 ); 
    }  

    imshow(" ", srcImage);    
    waitKey(0);    
    return 0;    
}
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值