C++OpenCV系统学习(19)——轮廓周围绘制矩形和圆形框

1.轮廓周围绘制矩形和园

1.1绘制矩形和圆概述

        在图像外侧绘制最小矩形。基于RDP算法实现,目的是减少多边形轮廓的点数,加快运算效率,对图像轮廓点拟合多边形;该函数用另一条曲线或具有较少顶点的多边形逼近曲线或多边形,使它们之间的距离小于或等于指定的精度;

1.2绘制矩形API

void approxPolyDP(InputArray curve,
    OutputArray approxCurve,
    double epsilon,
    bool closed) 
第一个参数,InputArray curve,一般是由图像的轮廓点组成的点集;
第二个参数,OutputArray approxCurve,表示输出的多边形点集;
第一个参数,double epsilon,主要表示输出的精度;这是原始曲线与其近似之间的最大距离;
第二个参数,bool closed,表示输出的多边形是否封闭;true表示封闭,false表示不封闭;

1.3绘制不同的矩形API

  • cv::boundingRect(inputArray points)得到轮廓周围最小矩形左上交点坐标和右下交点坐标,绘制一个矩形
  • cv::minAreaRect(inputArray points)得到一个旋转的矩形,返回旋转矩形

1.4轮廓周围绘制圆和椭圆API

cv::minEnclosingCircle(inputArray points,//得到最小区域圆形

Pointsf& center,//圆心位置
float& radius//圆半径
)

cv::fitEllipse(inputArray points)//得到最小椭圆

1.5算法流程

  1. 首先将图像变为二值图像
  2. 发现轮廓找到图像轮廓
  3. 通过相关API在轮廓点上找到最小包含矩形和圆,旋转矩形与椭圆
  4. 绘制他们

2.案例分析

第一步:createTrabar调节二值化阈值得到二值化图像:

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

Mat src, gray_src, drawImg;
int threshold_v = 170;
int threshold_max = 255;
const char* output_win = "rectangle-demo";
const char* source_win = "input_image";
RNG rng(12345);
void Contours_Callback(int, void*);

int main(int argc, const char* argv[])
{
	src = imread("F:/testImage/qiqiu.png");
	if (src.empty()) {
		printf("could not load image...\n");
		return -1;
	}
	//namedWindow("input", WINDOW_AUTOSIZE);
	//imshow("input", src);
	cvtColor(src, gray_src, COLOR_BGR2GRAY);
	blur(gray_src, gray_src, Size(3, 3), Point(-1, -1));
	namedWindow(source_win, WINDOW_AUTOSIZE);
	namedWindow(output_win, WINDOW_AUTOSIZE);
	imshow(source_win, src);

	createTrackbar("Threshold Value:", output_win, &threshold_v, threshold_max, Contours_Callback);
	Contours_Callback(0, 0);
	

	waitKey(0);
	return 0;
}

void Contours_Callback(int, void*)
{
	Mat binary_output;
	vector<vector<Point>>contours;
	vector<Vec4i>hierachy;
	threshold(gray_src, binary_output, threshold_v, threshold_max, THRESH_BINARY);
	imshow(output_win, binary_output);
	findContours(binary_output, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(-1, -1));
	
}

3.完整程序

#include<opencv2/opencv.hpp>
#include<iostream>
#include"myApi.h"
#include<math.h>

using namespace cv;
using namespace std;


Mat src, gray_src, drawImg;
int threshold_v = 170;
int threshold_max = 255;
const char* output_win = "rectangle_demo";
const char* source_win = "input_image";
RNG rng(12345);
void Contours_Callback(int, void*);

int main(int argc, char** argv)
{
	Mat src = imread("F:/testImage/qiqiu.png");
	if (!src.data)
	{
		cout << "图片没有找到" << endl;
		return -1;
	}
	imshow("src", src);

	/*Mat gray;
	cvtColor(src, gray, COLOR_BGR2GRAY);
	imshow("gray", gray);
	
	Mat precess_img = preprocessImg(gray);
	imshow("precess_img", precess_img);*/


	cvtColor(src, gray_src, COLOR_BGR2GRAY);
	blur(gray_src, gray_src, Size(3, 3), Point(-1, -1));
	namedWindow(source_win, WINDOW_AUTOSIZE);
	namedWindow(output_win, WINDOW_AUTOSIZE);
	imshow(source_win, src);

	createTrackbar("Threshold Value:", output_win, &threshold_v, threshold_max, Contours_Callback);
	Contours_Callback(0, 0);
	
	
	waitKey(0);
	return 0;
}


void Contours_Callback(int, void*)
{
	Mat binary_output;
	vector<vector<Point>>contours;
	vector<Vec4i>hierachy;
	threshold(gray_src, binary_output, threshold_v, threshold_max, THRESH_BINARY);
	//imshow(output_win, binary_output);
	findContours(binary_output, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(-1, -1));

	// 找到下面参数
	vector<vector<Point>> contour_ploy(contours.size());  //找外接多边形,(contours.size())表示对参数进行初始化
	vector<Rect> ploy_rects(contours.size());   //找外接矩形
	vector<Point2f> ccs(contours.size()); //圆心
	vector<float> radius(contours.size());  //半径

	vector<RotatedRect>minRects(contours.size());
	vector<RotatedRect>myeclipse(contours.size());
	for (size_t i = 0; i < contours.size(); i++)
	{
		approxPolyDP(Mat(contours[i]), contour_ploy[i], 3, true); //多边形拟合曲线
		ploy_rects[i] = boundingRect(contour_ploy[i]);
		minEnclosingCircle(contour_ploy[i], ccs[i], radius[i]);
		if (contour_ploy[i].size() > 5)
		{
			myeclipse[i] = fitEllipse(contour_ploy[i]);
			minAreaRect(contour_ploy[i]);
		}
	}

	//draw it
	Mat drawImg = Mat::zeros(src.size(), src.type());
	Point2f pts[4]; //矩形四个点
	for (size_t t = 0; t < contours.size(); t++)
	{
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		/*rectangle(drawImg, ploy_rects[t], color, 2, 8);
		circle(drawImg, ccs[t], radius[t], color, 2, 8);*/

		if (contour_ploy[t].size() > 5)
		{
			ellipse(drawImg, myeclipse[t], color, 1, 8);
			minRects[t].points(pts);
			for (int r = 0; r < 4; r++)
			{
				line(drawImg, pts[r], pts[(r + 1) % 4], color, 1, 8);
			}
		}
	}
	imshow(output_win, drawImg);
	return;
}



4.案例2

#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>

using namespace cv;
using namespace std;

int main()
{
    system("color F0");  //更改输出界面颜色
    Mat img=imread("coins.jpeg");
    if(img.empty()){
        cout<<"请确认输入烦人图片路径是否正确"<<endl;
        return -1;
    }
    imshow("原图",img);
    Mat gray,binary;
    cvtColor(img,gray,COLOR_BGR2GRAY);
    GaussianBlur(gray,gray,Size(9,9),2,2);//平滑滤波
    threshold(gray,binary,170,255,THRESH_BINARY|THRESH_OTSU);//自适应二值化

    //轮廓发现与绘制
    vector<vector<Point>>contours;//轮廓
    vector<Vec4i>hierachy;//存放轮廓结构变量
    findContours(binary,contours,hierachy,RETR_TREE,CHAIN_APPROX_SIMPLE);
    //绘制轮廓
    for(int i=0;i<contours.size();++i){
        drawContours(img,contours,i,Scalar(0,0,255),2,8);
    }
    //输出轮廓结构描述子
    for(int i=0;i<hierachy.size();++i){
        cout<<hierachy[i]<<endl;
    }
    //显示结果
    imshow("轮廓检测结果",img);
    waitKey(0);
    return 0;
}

 API解释:

void cv::findContours(InputArray  image,
	                  OutputArrayOfArrays  contours,
	                  int  mode,
	                  int  method,
	                  Point  offset = Point() 
	                  )
  • image:输入图像,数据类型为CV_8U的单通道灰度图像或者二值化图像。
  • contours:检测到的轮廓,每个轮廓中存放着像素的坐标。
  • mode:轮廓检测模式标志,可以选择的参数在表7-2给出。
  • method:轮廓逼近方法标志,可以选择的参数在表7-3给出。
  • offset:每个轮廓点移动的可选偏移量。这个函数主要用在从ROI图像中找出轮廓并基于整个图像分析轮廓的场景中。

void cv::drawContours(InputOutputArray  image,
                      InputArrayOfArrays  contours,
                      int   contourIdx,
                      const Scalar &  color,
                      int  thickness = 1,
                      int  lineType = LINE_8,
                      InputArray  hierarchy = noArray(),
                      int  maxLevel = INT_MAX,
                      Point  offset = Point() 
                      )
  • image:绘制轮廓的目标图像。
  • contours:所有将要绘制的轮廓
  • contourIdx:要绘制的轮廓的数目,如果是负数,则绘制所有的轮廓。
  • color:绘制轮廓的颜色。
  • thickness:绘制轮廓的线条粗细,如果参数为负数,则绘制轮廓的内部,默认参数值为1.
  • lineType:边界线连接的类型,可以选择参数在表7-4给出,默认参数值为LINE_8。
  • hierarchy:可选的结构关系信息,默认值为noArray()。
  • maxLevel:表示用于绘制轮廓的最大等级,默认值为INT_MAX。
  • offset:可选的轮廓偏移参数,按指定的移动距离绘制所有的轮廓。

该函数用于绘制findContours()函数检测到的图像轮廓。
函数的第一个参数为绘制轮廓的图像,根据需求该参数可以是单通道的灰度图像或者三通道的彩色图像。
第二个参数是所有将要绘制的轮廓,数据类型为vector。
第三个参数是要绘制的轮廓数目,该参数的数值与第二个参数相对应,应小于所有轮廓的数目,如果该参数值为负数,则绘制所有的轮廓。
第四个参数是绘制轮廓的颜色,对于单通道的灰度图像用Scalar(x)赋值,对于三通道的彩色图像用Scalar(x,y,z)赋值。
第五个参数是边界线的连接类型,可以选择的参数在表7-4给出,默认参数值为LINE_8。
第六个参数是可选的结构关系信息,默认值为noArray()。
第七个参数表示绘制轮廓的最大等级,参数值如果为0,则仅绘制指定的轮廓;如果为1,则该函数绘制轮廓和所有嵌套轮廓;如果为2,则该函数绘制轮廓以及所有嵌套轮廓和所有嵌套到嵌套轮廓的轮廓,以此类推,默认值为INT_MAX。函数最后一个参数是可选的轮廓偏移参数,按指定的移动距离绘制所有的轮廓。

猜你喜欢

转载自blog.csdn.net/bigData1994pb/article/details/120391732