OpenCV函數:提取輪廓相關函數使用方法


opencv中提供findContours()函數來尋找圖像中物體的輪廓,並結合drawContours()函數將找到的輪廓繪制出。首先看一下findContours(),opencv中提供了兩種定義形式

官網:https://docs.opencv.org/3.3.1/d3/dc0/group__imgproc__shape.html#ga17ed9f5d79ae97bd4c7cf18403e1689a 

void cv::findContours   (   InputOutputArray    image,
                            OutputArrayOfArrays     contours,
                            OutputArray     hierarchy,
                            int     mode,
                            int     method,
                            Point   offset = Point() 
                        )   

  

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>

using namespace cv;
using namespace std;

Mat src; Mat src_gray;
int thresh = 100;
int max_thresh = 255;
RNG rng(12345);

/// Function header
void thresh_callback(int, void*);

/** @function main */
int main(int argc, char** argv)
{
	/// 加載源圖像
	src = imread("E:\\VS2015Opencv\\vs2015\\project\\picture\\07.jpg", 1);

	/// 轉成灰度並模糊化降噪
	cvtColor(src, src_gray, CV_BGR2GRAY);
	blur(src_gray, src_gray, Size(3, 3));

	/// 創建窗體
	char* source_window = "Source";
	namedWindow(source_window, CV_WINDOW_AUTOSIZE);
	imshow(source_window, src);

	createTrackbar(" Canny thresh:", "Source", &thresh, max_thresh, thresh_callback);
	thresh_callback(0, 0);

	waitKey(0);
	return(0);
}

/** @function thresh_callback */
void thresh_callback(int, void*)
{
	Mat canny_output;
	vector<vector<Point> > contours;
	vector<Vec4i> hierarchy;

	/// 用Canny算子檢測邊緣
	Canny(src_gray, canny_output, thresh, thresh * 2, 3);
	/// 尋找輪廓
	findContours(canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

	/// 繪出輪廓
	Mat drawing = Mat::zeros(canny_output.size(), CV_8UC3);
	for (int i = 0; i< contours.size(); i++)
	{
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		drawContours(drawing, contours, i, color, 2, 8, hierarchy, 0, Point());
	}

	/// 在窗體中顯示結果
	namedWindow("Contours", CV_WINDOW_AUTOSIZE);
	imshow("Contours", drawing);
}

  

 

OpenCV提取輪廓之后,還可以進行許多操作:

ArcLength()                計算輪廓長度 
ContourArea()            計算輪廓區域的面積 
BoundingRect()          輪廓的外包矩形 
ConvexHull()              提取輪廓的凸包 
IsContourConvex()     測試輪廓的凸性 
MinAreaRect()            輪廓的最小外包矩形 
MinEnclosingCircle()  輪廓的最小外包圓
fitEllipse()                   用橢圓擬合二維點集
approxPolyDP()          逼近多邊形曲線

boundingRect函數簡介

boundingRect函數是用來計算輪廓的最小外接矩形,通常與findContours函數組合使用,findContours函數用來查找圖像的輪廓,boundingRect獲取輪廓的最小外接矩形!

Rect boundingRect( InputArray array );

(1) 第一個參數,InputArray array,一般為findContours函數查找的輪廓,包含輪廓的點集或者Mat;

(2) 返回值,Rect,返回值為最小外接矩形的Rect,即左上點與矩形的寬度和高度;

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>

using namespace cv;
using namespace std;

Mat src; Mat src_gray;
int thresh = 100;
int max_thresh = 255;
RNG rng(12345);

/// 函數聲明
void thresh_callback(int, void*);

/** @主函數 */
int main(int argc, char** argv)
{
	/// 載入原圖像, 返回3通道圖像
	src = imread("E:\\VS2015Opencv\\vs2015\\project\\picture\\1.1.jpg", 1);

	/// 轉化成灰度圖像並進行平滑
	cvtColor(src, src_gray, CV_BGR2GRAY);
	blur(src_gray, src_gray, Size(3, 3));

	/// 創建窗口
	char* source_window = "Source";
	namedWindow(source_window, CV_WINDOW_AUTOSIZE);
	imshow(source_window, src);

	createTrackbar(" Threshold:", "Source", &thresh, max_thresh, thresh_callback);
	thresh_callback(0, 0);

	waitKey(0);
	return(0);
}

/** @thresh_callback 函數 */
void thresh_callback(int, void*)
{
	Mat threshold_output;
	vector<vector<Point> > contours;
	vector<Vec4i> hierarchy;

	/// 使用Threshold檢測邊緣
	threshold(src_gray, threshold_output, thresh, 255, THRESH_BINARY);
	/// 找到輪廓
	findContours(threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

	/// 多邊形逼近輪廓 + 獲取矩形和圓形邊界框
	vector<vector<Point> > contours_poly(contours.size());
	vector<Rect> boundRect(contours.size());
	vector<Point2f>center(contours.size());
	vector<float>radius(contours.size());

	for (int i = 0; i < contours.size(); i++)
	{
		approxPolyDP(Mat(contours[i]), contours_poly[i], 3, true);
		boundRect[i] = boundingRect(Mat(contours_poly[i]));
		minEnclosingCircle(contours_poly[i], center[i], radius[i]);
	}


	/// 畫多邊形輪廓 + 包圍的矩形框 + 圓形框
	Mat drawing = Mat::zeros(threshold_output.size(), CV_8UC3);
	for (int i = 0; i< contours.size(); i++)
	{
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		drawContours(drawing, contours_poly, i, color, 1, 8, vector<Vec4i>(), 0, Point());
		rectangle(drawing, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0);
		circle(drawing, center[i], (int)radius[i], color, 2, 8, 0);
	}

	/// 顯示在一個窗口
	namedWindow("Contours", CV_WINDOW_AUTOSIZE);
	imshow("Contours", drawing);
}

 

minAreaRect()

作用:找到一個能包圍輸入二維點集的面積最小的任意方向矩形。

形式:minAreaRect(InputArray points);

參數:points:輸入二維點集,並用std::vector or Mat存儲;

 

fitEllipse()

作用:尋找一個適合的圍繞二維點集的橢圓。

形式:fitEllipse(InputArray points);

參數:points:輸入二維點集,並用std::vector or Mat存儲;

 

ellipse()

作用:畫一個簡單的或明顯的橢圓弧,或填充一個橢圓部分。

形式:void ellipse(Mat& img, const RotatedRect& box, const Scalar& color, int thickness=1, int lineType=8);

或void ellipse(Mat& img, Point center, Size axes, double angle, double startAngle, double endAngle, const Scalar& color, int thickness=1, int lineType=8, int shift=0);

參數:

img:輸入的圖像;

box:通過RotatedRect or CvBox2D選擇橢圓代表,也就是在任意方向矩陣中鑲嵌一個橢圓;

后邊三個參數分別是:顏色、邊線粗細、邊線的類型;

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>

using namespace cv;
using namespace std;

Mat src; Mat src_gray;
int thresh = 100;
int max_thresh = 255;
RNG rng(12345);

/// Function header
void thresh_callback(int, void*);

/** @function main */
int main(int argc, char** argv)
{
    /// 加載源圖像
    src = imread("E:\\VS2015Opencv\\vs2015\\project\\picture\\01.jpg");

    /// 轉為灰度圖並模糊化
    cvtColor(src, src_gray, CV_BGR2GRAY);
    blur(src_gray, src_gray, Size(3, 3));

    /// 創建窗體
    char* source_window = "Source";
    namedWindow(source_window, CV_WINDOW_AUTOSIZE);
    imshow(source_window, src);

    createTrackbar(" Threshold:", "Source", &thresh, max_thresh, thresh_callback);
    thresh_callback(0, 0);

    waitKey(0);
    return(0);
}

/** @function thresh_callback */
void thresh_callback(int, void*)
{
    Mat threshold_output;
    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;

    /// 閾值化檢測邊界
    threshold(src_gray, threshold_output, thresh, 255, THRESH_BINARY);
    /// 尋找輪廓
    findContours(threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

    /// 對每個找到的輪廓創建可傾斜的邊界框和橢圓
    vector<RotatedRect> minRect(contours.size());
    vector<RotatedRect> minEllipse(contours.size());

    for (int i = 0; i < contours.size(); i++)
    {
        minRect[i] = minAreaRect(Mat(contours[i]));
        if (contours[i].size() > 5)
        {
            minEllipse[i] = fitEllipse(Mat(contours[i]));
        }
    }

    /// 繪出輪廓及其可傾斜的邊界框和邊界橢圓
    Mat drawing = Mat::zeros(threshold_output.size(), CV_8UC3);
    for (int i = 0; i < contours.size(); i++)
    {
        Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
        // contour
        drawContours(drawing, contours, i, color, 1, 8, vector<Vec4i>(), 0, Point());
        // ellipse
        ellipse(drawing, minEllipse[i], color, 2, 8);
        // rotated rectangle
        Point2f rect_points[4]; minRect[i].points(rect_points);
        for (int j = 0; j < 4; j++)
            line(drawing, rect_points[j], rect_points[(j + 1) % 4], color, 1, 8);
    }

    /// 結果在窗體中顯示
    namedWindow("Contours", CV_WINDOW_AUTOSIZE);
    imshow("Contours", drawing);
}

 

 本文參考:OpenCV函數:提取輪廓相關函數使用方法

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM