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.0Start讀取一幀圖片調用BrightAdjust函數進行亮度調節調用cvSplit將圖像BGR三個通道的數值分離調用GetDiffImage將圖像二值化對二值化的圖像膨脹,腐蝕調用cvFindContours提取圖像所有輪廓存放到序列中遍歷所有輪廓調用cvFitEllipse2擬合輪廓爲旋轉矩形旋轉矩形中心5*5像素是否接近白色?是LED燈條所在區域,將該旋轉矩形添加到vector*****************遍歷結束?***************調用ArmorDetect,在輸入的LED所在旋轉矩形的vector中找出裝甲的位置,幷包裝成旋轉矩形,存入vector並返回調用DrawBox,在當前圖像中標記裝甲位置顯示當前圖像Endyesnoyesno

一幀圖像爲例,說明其檢測過程,

原圖片

這裏寫圖片描述bo_test\robo_test\原圖片.png)

亮度調整。每個通道的數值-120,小於零=0,大於255則=255,用於突出LED燈帶所在區域

這裏寫圖片描述

二值化。將上圖RGB,三個通道分離,R值減去G值,若大於25,則在二值圖像中爲255,否則爲0.

二值化後可以看到斷斷續續的LED燈區域的輪廓

這裏寫圖片描述

膨脹之後(下圖),將輪廓較爲平滑,連通區域變得粗重。

這裏寫圖片描述

腐蝕操作後見下圖,先膨脹在經腐蝕相當於閉運算,有去除空洞,使得輪廓變得平滑的功能

這裏寫圖片描述

提取輪廓後

這裏寫圖片描述

遍歷所有輪廓,找出滿足條件(輪廓要大於10個像素點)的輪廓,擬合成旋轉矩形,然後在判斷該旋轉矩形的中心5×5 的像素塊(要從二值化之前的圖像看)是否接近白色,如何是則說明可能是裝甲LED燈帶所在區域,將其添加至一個向量vEllipse中,爲下一步定位裝甲做準備。下圖展示了這些旋轉矩形

這裏寫圖片描述

下一步是檢測裝甲的位置,在以上旋轉矩形中,兩兩判斷,根據下載原則定位裝甲:

  • 兩個矩形近似平行,即旋轉矩形的角度之差接近0o180o
  • 兩個旋轉矩形的寬和高應該相差不大。

然後求出裝甲的寬度和高度,高度取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 
                    )
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章