RM装甲识别程序分析(一)

RM装甲识别程序分析

目录

1. 代码预览

1.1 基于opencv2.4.9编写

//来自网络并非原创
#include "stdafx.h"
#include "cv.h"
#include "highgui.h"
#include "cxcore.h"
#include "omp.h"
#include "iostream"

using namespace cv;
using namespace std;

#define T_ANGLE_THRE 10
#define T_SIZE_THRE 5

void BrightAdjust(IplImage* src, IplImage* dst,   //亮度调节函数
    double dContrast, double dBright)
{
    int nVal;

    unsigned char* SrcData = (unsigned char*)src->imageData; //原图像数据区指针
    unsigned char* DstData = (unsigned char*)dst->imageData; //目的图像数据区指针
    int step = src->widthStep / sizeof(unsigned char) / 3; //一行有多少个像素

    omp_set_num_threads(8);
#pragma omp parallel for

    for (int nI = 0; nI<src->height; nI++)
    {
        for (int nJ = 0; nJ <src->width; nJ++)
        {
            for (int nK = 0; nK < 3; nK++)
            {
                nVal = (int)(dContrast * SrcData[(nI*step + nJ) * 3 + nK] + dBright);  //每个像素的每个通道的值都进行线性变换
                if (nVal < 0)
                    nVal = 0;
                if (nVal > 255)
                    nVal = 255;
                DstData[(nI*step + nJ) * 3 + nK] = nVal;
            }
        }
    }
}

void GetDiffImage(IplImage* src1, IplImage* src2, IplImage* dst, int nThre)
{
    unsigned char* SrcData1 = (unsigned char*)src1->imageData;
    unsigned char* SrcData2 = (unsigned char*)src2->imageData;
    unsigned char* DstData = (unsigned char*)dst->imageData;
    int step = src1->widthStep / sizeof(unsigned char);

    omp_set_num_threads(8);
#pragma omp parallel for

    for (int nI = 0; nI<src1->height; nI++)
    {
        for (int nJ = 0; nJ <src1->width; nJ++)
        {
            if (SrcData1[nI*step + nJ] - SrcData2[nI*step + nJ]> nThre) //
            {
                DstData[nI*step + nJ] = 255;
            }
            else
            {
                DstData[nI*step + nJ] = 0;
            }
        }
    }
}

vector<CvBox2D> ArmorDetect(vector<CvBox2D> vEllipse)
{
    vector<CvBox2D> vRlt;
    CvBox2D Armor; //定义装甲区域的旋转矩形
    int nL, nW;
    double dAngle;
    vRlt.clear();
    if (vEllipse.size() < 2) //如果检测到的旋转矩形个数小于2,则直接返回
        return vRlt;
    for (unsigned int nI = 0; nI < vEllipse.size() - 1; nI++) //求任意两个旋转矩形的夹角
    {
        for (unsigned int nJ = nI + 1; nJ < vEllipse.size(); nJ++)
        {
            dAngle = abs(vEllipse[nI].angle - vEllipse[nJ].angle);
            while (dAngle > 180)
                dAngle -= 180;
            if ((dAngle < T_ANGLE_THRE || 180 - dAngle < T_ANGLE_THRE) && abs(vEllipse[nI].size.height - vEllipse[nJ].size.height) < (vEllipse[nI].size.height + vEllipse[nJ].size.height) / T_SIZE_THRE && abs(vEllipse[nI].size.width - vEllipse[nJ].size.width) < (vEllipse[nI].size.width + vEllipse[nJ].size.width) / T_SIZE_THRE) //判断这两个旋转矩形是否是一个装甲的两个LED等条
            {
                Armor.center.x = (vEllipse[nI].center.x + vEllipse[nJ].center.x) / 2; //装甲中心的x坐标 
                Armor.center.y = (vEllipse[nI].center.y + vEllipse[nJ].center.y) / 2; //装甲中心的y坐标
                Armor.angle = (vEllipse[nI].angle + vEllipse[nJ].angle) / 2;   //装甲所在旋转矩形的旋转角度
                if (180 - dAngle < T_ANGLE_THRE)
                    Armor.angle += 90;
                nL = (vEllipse[nI].size.height + vEllipse[nJ].size.height) / 2; //装甲的高度
                nW = sqrt((vEllipse[nI].center.x - vEllipse[nJ].center.x) * (vEllipse[nI].center.x - vEllipse[nJ].center.x) + (vEllipse[nI].center.y - vEllipse[nJ].center.y) * (vEllipse[nI].center.y - vEllipse[nJ].center.y)); //装甲的宽度等于两侧LED所在旋转矩形中心坐标的距离
                if (nL < nW)
                {
                    Armor.size.height = nL;
                    Armor.size.width = nW;
                }
                else
                {
                    Armor.size.height = nW;
                    Armor.size.width = nL;
                }
                vRlt.push_back(Armor); //将找出的装甲的旋转矩形保存到vector
            }
        }
    }
    return vRlt;
}

void DrawBox(CvBox2D box, IplImage* img)
{
    CvPoint2D32f point[4];
    int i;
    for (i = 0; i<4; i++)
    {
        point[i].x = 0;
        point[i].y = 0;
    }
    cvBoxPoints(box, point); //计算二维盒子顶点 
    CvPoint pt[4];
    for (i = 0; i<4; i++)
    {
        pt[i].x = (int)point[i].x;
        pt[i].y = (int)point[i].y;
    }
    cvLine(img, pt[0], pt[1], CV_RGB(0, 0, 255), 2, 8, 0);
    cvLine(img, pt[1], pt[2], CV_RGB(0, 0, 255), 2, 8, 0);
    cvLine(img, pt[2], pt[3], CV_RGB(0, 0, 255), 2, 8, 0);
    cvLine(img, pt[3], pt[0], CV_RGB(0, 0, 255), 2, 8, 0);
}

int main()
{
    CvCapture* pCapture0 = cvCreateFileCapture("RawImage\\RedCar.avi");
    //CvCapture* pCapture0 = cvCreateCameraCapture(0);
    IplImage* pFrame0 = NULL;

    CvSize pImgSize;
    CvBox2D s;   //定义旋转矩形
    vector<CvBox2D> vEllipse; //定以旋转矩形的向量,用于存储发现的目标区域
    vector<CvBox2D> vRlt;
    vector<CvBox2D> vArmor;
    CvScalar sl;
    bool bFlag = false;
    CvSeq *pContour = NULL;
    CvMemStorage *pStorage = cvCreateMemStorage(0);


    pFrame0 = cvQueryFrame(pCapture0);

    pImgSize = cvGetSize(pFrame0);

    IplImage *pRawImg = cvCreateImage(pImgSize, IPL_DEPTH_8U, 3);

    IplImage* pGrayImage = cvCreateImage(pImgSize, IPL_DEPTH_8U, 1);
    IplImage* pRImage = cvCreateImage(pImgSize, IPL_DEPTH_8U, 1);
    IplImage* pGImage = cvCreateImage(pImgSize, IPL_DEPTH_8U, 1);
    IplImage *pBImage = cvCreateImage(pImgSize, IPL_DEPTH_8U, 1);
    IplImage *pBinary = cvCreateImage(pImgSize, IPL_DEPTH_8U, 1);
    IplImage *pRlt = cvCreateImage(pImgSize, IPL_DEPTH_8U, 1);

    CvSeq* lines = NULL;
    CvMemStorage* storage = cvCreateMemStorage(0);
    while (1)
    {
        if (pFrame0)
        {
            BrightAdjust(pFrame0, pRawImg, 1, -120);  //每个像素每个通道的值都减去120
            cvSplit(pRawImg, pBImage, pGImage, pRImage, 0); //将三个通道的像素值分离
            //如果像素R值-G值大于25,则返回的二值图像的值为255,否则为0
            GetDiffImage(pRImage, pGImage, pBinary, 25); 
            cvDilate(pBinary, pGrayImage, NULL, 3);   //图像膨胀
            cvErode(pGrayImage, pRlt, NULL, 1);  //图像腐蚀,先膨胀在腐蚀属于闭运算
            cvFindContours(pRlt, pStorage, &pContour, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);   //在二值图像中寻找轮廓
            for (; pContour != NULL; pContour = pContour->h_next)
            {
                if (pContour->total > 10)  //判断当前轮廓是否大于10个像素点
                {
                    bFlag = true;   //如果大于10个,则检测到目标区域
                   //拟合目标区域成为椭圆,返回一个旋转矩形(中心、角度、尺寸)
                    s = cvFitEllipse2(pContour); 
                    for (int nI = 0; nI < 5; nI++)
                    {
                        for (int nJ = 0; nJ < 5; nJ++)   //遍历以旋转矩形中心点为中心的5*5的像素块
                        {
                            if (s.center.y - 2 + nJ > 0 && s.center.y - 2 + nJ < 480 && s.center.x - 2 + nI > 0 && s.center.x - 2 + nI <  640)  //判断该像素是否在有效的位置
                            {
                                sl = cvGet2D(pFrame0, (int)(s.center.y - 2 + nJ), (int)(s.center.x - 2 + nI)); //获取遍历点点像素值
                              //判断中心点是否接近白色
                                if (sl.val[0] < 200 || sl.val[1] < 200 || sl.val[2] < 200) 
                                    bFlag = false;      //如果中心不是白色,则不是目标区域
                            }
                        }
                    }
                    if (bFlag)
                    {
                        vEllipse.push_back(s); //将发现的目标保存
                        //cvEllipseBox(pFrame0, s, CV_RGB(255, 0, 0), 2, 8, 0);
                    }
                }

            }
       //调用子程序,在输入的LED所在旋转矩形的vector中找出装甲的位置,并包装成旋转矩形,存入vector并返回
            vRlt = ArmorDetect(vEllipse); 

            for (unsigned int nI = 0; nI < vRlt.size(); nI++) //在当前图像中标出装甲的位置
                DrawBox(vRlt[nI], pFrame0);
            cvShowImage("Raw", pFrame0);
            if (cvWaitKey(50) == 27)
            {
                break;
            }
            vEllipse.clear();
            vRlt.clear();
            vArmor.clear();
            pFrame0 = cvQueryFrame(pCapture0);
        }
        else
        {
            break;
        }

    }
    cvReleaseCapture(&pCapture0);
    return 0;
}

1.2 基于opencv3.0.0编写

//根据以上代码将其在opencv3.0.0中编写
#include "stdafx.h"
#include "opencv2/core.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/videoio.hpp"
#include "opencv2/imgproc.hpp"
#include "iostream"
#include "omp.h"
using namespace cv;
using namespace std;

#define T_ANGLE_THRE 10
#define T_SIZE_THRE 5

void brightAdjust(Mat src, Mat dst, double dContrast, double dBright); //亮度调节函数
void getDiffImage(Mat src1, Mat src2, Mat dst, int nThre); //二值化
vector<RotatedRect> armorDetect(vector<RotatedRect> vEllipse); //检测装甲
void drawBox(RotatedRect box, Mat img); //标记装甲

int main()
{

    VideoCapture cap0("RawImage\\RedCar.avi");
    Mat frame0;

    Size imgSize;
    RotatedRect s;   //定义旋转矩形
    vector<RotatedRect> vEllipse; //定以旋转矩形的向量,用于存储发现的目标区域
    vector<RotatedRect> vRlt;
    vector<RotatedRect> vArmor;
    bool bFlag = false;

    vector<vector<Point> > contour;

    cap0 >> frame0;
    imgSize = frame0.size();

    Mat rawImg = Mat(imgSize, CV_8UC3);

    Mat grayImage = Mat(imgSize, CV_8UC1);
    Mat rImage = Mat(imgSize, CV_8UC1);
    Mat gImage = Mat(imgSize, CV_8UC1);
    Mat bImage = Mat(imgSize, CV_8UC1);
    Mat binary = Mat(imgSize, CV_8UC1);
    Mat rlt = Mat(imgSize, CV_8UC1);
    namedWindow("Raw");
    while (1)
    {
        if (cap0.read(frame0))
        {
            brightAdjust(frame0, rawImg, 1, -120);  //每个像素每个通道的值都减去120
            Mat bgr[3];
            split(rawImg, bgr); //将三个通道的像素值分离
            bImage = bgr[0];
            gImage = bgr[1];
            rImage = bgr[2];
          //如果像素R值-G值大于25,则返回的二值图像的值为255,否则为0
            getDiffImage(rImage, gImage, binary, 25); 
            dilate(binary, grayImage, Mat(), Point(-1,-1), 3);   //图像膨胀
            erode(grayImage, rlt, Mat(), Point(-1,-1), 1);  //图像腐蚀,先膨胀在腐蚀属于闭运算
            findContours(rlt, contour, RETR_CCOMP , CHAIN_APPROX_SIMPLE); //在二值图像中寻找轮廓
            for (int i=0; i<contour.size(); i++)
            {
                if (contour[i].size()> 10)  //判断当前轮廓是否大于10个像素点
                {
                    bFlag = true;   //如果大于10个,则检测到目标区域
                  //拟合目标区域成为椭圆,返回一个旋转矩形(中心、角度、尺寸)
                    s = fitEllipse(contour[i]);  
                    for (int nI = 0; nI < 5; nI++)
                    {
                        for (int nJ = 0; nJ < 5; nJ++)  //遍历以旋转矩形中心点为中心的5*5的像素块
                        {
                            if (s.center.y - 2 + nJ > 0 && s.center.y - 2 + nJ < 480 && s.center.x - 2 + nI > 0 && s.center.x - 2 + nI <  640)  //判断该像素是否在有效的位置
                            {   
                                Vec3b v3b = frame0.at<Vec3b>((int)(s.center.y - 2 + nJ), (int)(s.center.x - 2 + nI)); //获取遍历点点像素值
                               //判断中心点是否接近白色
                                if (v3b[0] < 200 || v3b[1] < 200 || v3b[2] < 200)
                                    bFlag = false;        //如果中心不是白色,则不是目标区域
                            }
                        }
                    }
                    if (bFlag)
                    {
                        vEllipse.push_back(s); //将发现的目标保存
                    }
                }

            }
        //调用子程序,在输入的LED所在旋转矩形的vector中找出装甲的位置,并包装成旋转矩形,存入vector并返回
            vRlt = armorDetect(vEllipse); 
            for (unsigned int nI = 0; nI < vRlt.size(); nI++) //在当前图像中标出装甲的位置
                drawBox(vRlt[nI], frame0);
            imshow("Raw", frame0);
            if (waitKey(50) == 27)
            {
                break;
            }
            vEllipse.clear();
            vRlt.clear();
            vArmor.clear();
        }
        else
        {
            break;
        }
    }
    cap0.release();
    return 0;

}

void brightAdjust(Mat src, Mat dst, double dContrast, double dBright)
{
    int nVal;
    omp_set_num_threads(8);
#pragma omp parallel for

    for (int nI = 0; nI<src.rows; nI++)
    {
        Vec3b* p1 = src.ptr<Vec3b>(nI);
        Vec3b* p2 = dst.ptr<Vec3b>(nI);
        for (int nJ = 0; nJ <src.cols; nJ++)
        {
            for (int nK = 0; nK < 3; nK++)
            {
               //每个像素的每个通道的值都进行线性变换
                nVal = (int)(dContrast * p1[nJ][nK] + dBright);
                if (nVal < 0)
                    nVal = 0;
                if (nVal > 255)
                    nVal = 255;
                p2[nJ][nK] = nVal;
            }
        }
    }
}

void getDiffImage(Mat src1, Mat src2, Mat dst, int nThre)
{
    omp_set_num_threads(8);
#pragma omp parallel for

    for (int nI = 0; nI<src1.rows; nI++)
    {
        uchar* pchar1 = src1.ptr<uchar>(nI);
        uchar* pchar2 = src2.ptr<uchar>(nI);
        uchar* pchar3 = dst.ptr<uchar>(nI);
        for (int nJ = 0; nJ <src1.cols; nJ++)
        {
            if (pchar1[nJ] - pchar2[nJ]> nThre) //
            {
                pchar3[nJ] = 255;
            }
            else
            {
                pchar3[nJ] = 0;
            }
        }
    }
}

vector<RotatedRect> armorDetect(vector<RotatedRect> vEllipse)
{
    vector<RotatedRect> vRlt;
    RotatedRect armor; //定义装甲区域的旋转矩形
    int nL, nW;
    double dAngle;
    vRlt.clear();
    if (vEllipse.size() < 2) //如果检测到的旋转矩形个数小于2,则直接返回
        return vRlt;
    for (unsigned int nI = 0; nI < vEllipse.size() - 1; nI++) //求任意两个旋转矩形的夹角
    {
        for (unsigned int nJ = nI + 1; nJ < vEllipse.size(); nJ++)
        {
            dAngle = abs(vEllipse[nI].angle - vEllipse[nJ].angle);
            while (dAngle > 180)
                dAngle -= 180;
          //判断这两个旋转矩形是否是一个装甲的两个LED等条
            if ((dAngle < T_ANGLE_THRE || 180 - dAngle < T_ANGLE_THRE) && abs(vEllipse[nI].size.height - vEllipse[nJ].size.height) < (vEllipse[nI].size.height + vEllipse[nJ].size.height) / T_SIZE_THRE && abs(vEllipse[nI].size.width - vEllipse[nJ].size.width) < (vEllipse[nI].size.width + vEllipse[nJ].size.width) / T_SIZE_THRE) 
            {
                armor.center.x = (vEllipse[nI].center.x + vEllipse[nJ].center.x) / 2; //装甲中心的x坐标 
                armor.center.y = (vEllipse[nI].center.y + vEllipse[nJ].center.y) / 2; //装甲中心的y坐标
                armor.angle = (vEllipse[nI].angle + vEllipse[nJ].angle) / 2;   //装甲所在旋转矩形的旋转角度
                if (180 - dAngle < T_ANGLE_THRE)
                    armor.angle += 90;
                nL = (vEllipse[nI].size.height + vEllipse[nJ].size.height) / 2; //装甲的高度
                nW = sqrt((vEllipse[nI].center.x - vEllipse[nJ].center.x) * (vEllipse[nI].center.x - vEllipse[nJ].center.x) + (vEllipse[nI].center.y - vEllipse[nJ].center.y) * (vEllipse[nI].center.y - vEllipse[nJ].center.y)); //装甲的宽度等于两侧LED所在旋转矩形中心坐标的距离
                if (nL < nW)
                {
                    armor.size.height = nL;
                    armor.size.width = nW;
                }
                else
                {
                    armor.size.height = nW;
                    armor.size.width = nL;
                }
                vRlt.push_back(armor); //将找出的装甲的旋转矩形保存到vector
            }
        }
    }
    return vRlt;
}

void drawBox(RotatedRect box, Mat img)
{
    Point2f pt[4];
    int i;
    for (i = 0; i<4; i++)
    {
        pt[i].x = 0;
        pt[i].y = 0;
    }
    box.points(pt); //计算二维盒子顶点 
    line(img, pt[0], pt[1], CV_RGB(0, 0, 255), 2, 8, 0);
    line(img, pt[1], pt[2], CV_RGB(0, 0, 255), 2, 8, 0);
    line(img, pt[2], pt[3], CV_RGB(0, 0, 255), 2, 8, 0);
    line(img, pt[3], pt[0], CV_RGB(0, 0, 255), 2, 8, 0);
}

2. 关于omp.h头文件

OpenMp提供了对并行算法的高层的抽象描述,程序员通过在源代码中加入专用的pragma来指明自己的意图,由此编译器可以自动将程序进行并行化,并在必要之处加入同步互斥以及通信。

要在Visual C++ 中使用OpenMP其实不难,只要将 Project 的Properties中C/C++里Language的OpenMP Support开启(参数为 /openmp),就可以让VC++2005 在编译时支持OpenMP 的语法了;而在编写使用OpenMP 的程序时,则需要先include OpenMP的头文件:omp.h

在for循环前面添加如下代码,可实现并行计算。

omp_set_num_threads(NUM_THREADS); //NUM_THREADS为并行计算的线程数
#pragma omp parallel for

3. 程序流程分析

首先检测出LED灯带的位置,检测的方法:图像二值化,提取轮廓,拟合成旋转矩形,判断旋转矩形的中心是否接近白色,若接近白色,则说明是LED等待所在位置,然后利用检测出的LED灯带的旋转矩形的是否是平行关系来检测装甲。

Created with Raphaël 2.1.0 Start 读取一帧图片 调用BrightAdjust函数进行亮度调节 调用cvSplit将图像BGR三个通道的数值分离 调用GetDiffImage将图像二值化 对二值化的图像膨胀,腐蚀 调用cvFindContours提取图像所有轮廓存放到序列中 遍历所有轮廓 调用cvFitEllipse2拟合轮廓为旋转矩形 旋转矩形中心5*5像素是否接近白色? 是LED灯条所在区域,将该旋转矩形添加到vector *****************遍历结束?*************** 调用ArmorDetect,在输入的LED所在旋转矩形的vector中找出装甲的位置,并包装成旋转矩形,存入vector并返回 调用DrawBox,在当前图像中标记装甲位置 显示当前图像 End yes no yes no

一帧图像为例,说明其检测过程,

原图片

这里写图片描述bo_test\robo_test\原图片.png)

亮度调整。每个通道的数值-120,小于零=0,大于255则=255,用于突出LED灯带所在区域

这里写图片描述

二值化。将上图RGB,三个通道分离,R值减去G值,若大于25,则在二值图像中为255,否则为0.

二值化后可以看到断断续续的LED灯区域的轮廓

这里写图片描述

膨胀之后(下图),将轮廓较为平滑,连通区域变得粗重。

这里写图片描述

腐蚀操作后见下图,先膨胀在经腐蚀相当于闭运算,有去除空洞,使得轮廓变得平滑的功能

这里写图片描述

提取轮廓后

这里写图片描述

遍历所有轮廓,找出满足条件(轮廓要大于10个像素点)的轮廓,拟合成旋转矩形,然后在判断该旋转矩形的中心 5×5 的像素块(要从二值化之前的图像看)是否接近白色,如何是则说明可能是装甲LED灯带所在区域,将其添加至一个向量vEllipse中,为下一步定位装甲做准备。下图展示了这些旋转矩形

这里写图片描述

下一步是检测装甲的位置,在以上旋转矩形中,两两判断,根据下载原则定位装甲:

  • 两个矩形近似平行,即旋转矩形的角度之差接近 0o 180o
  • 两个旋转矩形的宽和高应该相差不大。

然后求出装甲的宽度和高度,高度取LED旋转矩形height的平均值,宽度等于两个旋转矩形的中心距离。最后标出装甲位置

这里写图片描述

4. 相关数据结构

4.1 旋转矩形

//opencv2.4.x版本中的旋转矩形类
CvBox2D
Public Member Functions //成员函数
    CvBox2D (CvPoint2D32f c=CvPoint2D32f(), CvSize2D32f s=CvSize2D32f(), float a=0)
    CvBox2D (const cv::RotatedRect &rr)
    operator cv::RotatedRect () const

Public Attributes //成员变量
float angle
CvPoint2D32f center
CvSize2D32f size

//opencv3.0以上版本中的旋转矩形类
RotatedRect
Public Member Functions  //成员函数
    RotatedRect () //无参数构造函数
    RotatedRect (const Point2f &center, const Size2f &size, float angle)//构造函数
    RotatedRect (const Point2f &point1, const Point2f &point2, const Point2f &point3)
    Rect    boundingRect () const//获取包围旋转矩形的最小的直立矩形
    void    points (Point2f pts[]) const//获取旋转矩形的四个定点坐标

Public Attributes //成员变量
float angle//旋转角度
Point2f center//中心坐标
Size2f  size//尺寸

5. 相关函数

5.1 通道分离

//
//opencv2.4.x版本中的通道分离函数
void cvSplit    (   const CvArr *   src,
                    CvArr *     dst0,
                    CvArr *     dst1,
                    CvArr *     dst2,
                    CvArr *     dst3 
                )   

  //opencv3.0以上版本中的通道分离函数
void cv::split  (   const Mat &     src,
                    Mat *   mvbegin //输出的Mat数组
                )       

5.2 膨胀、腐蚀

//opencv2.4.x版本中的膨胀函数
void cvDilate   (   const CvArr *   src,
                    CvArr *     dst,
                    IplConvKernel *     element = NULL,
                    int     iterations = 1 
                )           
//opencv3.0以上版本中的膨胀函数
void cv::dilate (   InputArray  src,
                    OutputArray     dst,
                    InputArray  kernel,//膨胀所用的结构元,默认为3*3的矩形
                    Point   anchor = Point(-1,-1),//结构元的中心
                    int     iterations = 1,//膨胀操作的次数
                    int     borderType = BORDER_CONSTANT,
                    const Scalar &  borderValue = morphologyDefaultBorderValue() 
                )   
//opencv2.4.x版本中的腐蚀函数
  void cvErode  (   const CvArr *   src,
                    CvArr *     dst,
                    IplConvKernel *     element = NULL,
                    int     iterations = 1 
                )   
  //opencv3.0以上版本中的腐蚀函数
  void cv::erode    (   InputArray  src,
                        OutputArray     dst,
                        InputArray  kernel,
                        Point   anchor = Point(-1,-1),
                        int     iterations = 1,
                        int     borderType = BORDER_CONSTANT,
                        const Scalar &  borderValue = morphologyDefaultBorderValue() 
                    )       

5.3 提取轮廓

//opencv2.4.x版本中的提取轮廓函数
int cvFindContours  (   CvArr *     image,
                        CvMemStorage *  storage,
                        CvSeq **    first_contour,
                        int     header_size = sizeof(CvContour),
                        int     mode = CV_RETR_LIST,
                        int     method = CV_CHAIN_APPROX_SIMPLE,
                        CvPoint     offset = cvPoint(0, 0) 
                    )   
  //opencv3.0以上版本中的提取轮廓函数
 void cv::findContours  (   InputOutputArray    image,
                            OutputArrayOfArrays     contours,
                            OutputArray     hierarchy,
                            int     mode,
                            int     method,
                            Point   offset = Point() 
                        )
  //注意该函数会修改输入的二值化图像,必要时要做备份

5.4 拟合旋转矩形

//opencv2.4.x版本中的拟合旋转矩形函数
CvBox2D cvFitEllipse2   (   const CvArr *   points  )
//opencv3.0以上版本中的拟合旋转矩形函数
RotatedRect cv::fitEllipse  (   InputArray  points  )

5.5 获取指定点的像素

//opencv2.4.x版本中的获取指定位置处像素的函数
CvScalar cvGet2D    (   const CvArr *   arr,
                        int     idx0,
                        int     idx1 
                    )

猜你喜欢

转载自blog.csdn.net/healingwounds/article/details/78583194
rm