引言

在实际应用中,常常会有将检测到的轮廓用多边形表示出来的需求。这里为大家讲解如何用多边形表示出轮廓,或者说如何根据轮廓提取出多边形。

API:

approxPolyDP ()主要功能是把一个连续光滑曲线折线化,对图像轮廓点进行多边形拟合。

python opencv在屏幕上画方框 opencv画矩形框_拟合

python opencv在屏幕上画方框 opencv画矩形框_轮廓周围绘制矩形框和圆形框_02

原理图:对比之前黑点连线,之后蓝色连线:

python opencv在屏幕上画方框 opencv画矩形框_拟合_03

boundingRect()函数计算并返回指定点集最外面的矩形边界。

python opencv在屏幕上画方框 opencv画矩形框_OpenCV_04


minEnclosingCircle()函数利用一种迭代算法,对给定的2D点集,去寻找面积最小的可包围它们的圆形。

python opencv在屏幕上画方框 opencv画矩形框_轮廓周围绘制矩形框和圆形框_05

python opencv在屏幕上画方框 opencv画矩形框_点集_06


minAreaRect()函数对于给定的2D点集,寻找可旋转的最小面积的包围矩形。

python opencv在屏幕上画方框 opencv画矩形框_approxPolyDP ()_07


fitEllipse()函数用椭圆拟合二维点集。

python opencv在屏幕上画方框 opencv画矩形框_拟合_08

代码示例:

1.通过移动滑动块控制生成随机点的数量,对于生成的随机点的点集,寻找最外面的矩阵边界、面积最小的可包围它们的圆形、

可旋转的最小面积的包围矩形,用椭圆拟合二维点集。

#include "pch.h"
#include <iostream>
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
int pointNum = 50;
int pointMax = 100;
void PolyBound_demo(int pos, void* userdata);
RNG rng(getTickCount());
int mode = 0;
int main()
	namedWindow("PolyBound", WINDOW_AUTOSIZE);
	createTrackbar("pointNum", "PolyBound", &pointNum, pointMax, PolyBound_demo);
	createTrackbar("mode", "PolyBound", &mode,1, PolyBound_demo);
	setTrackbarMin("pointNum", "PolyBound", 5);
	PolyBound_demo(pointNum, 0);
	waitKey(0);
void PolyBound_demo(int pos, void* userdata)
	Mat img = Mat::zeros(Size(500, 500), CV_8UC3);
	//产生随机点并绘制
	vector<Point> points;
	for (int i = 0; i < pointNum; i++)
		Point point;
		point.x = rng.uniform(img.cols / 4, img.cols * 3 / 4);
		point.y = rng.uniform(img.rows / 4, img.rows * 3 / 4);
		points.push_back(point);
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		circle(img, point, 2, color , FILLED, LINE_AA);
	if (mode == 0)  
		//对于以上生成的点集,寻找最外面的矩形边界
		Rect poly_rect = boundingRect(points);
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		rectangle(img, poly_rect, color, 2, LINE_AA);
		//对给定的2D点集,去寻找面积最小的可包围它们的圆形
		Point2f center;
		float radius;
		minEnclosingCircle(points, center, radius);
		color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		circle(img, center, radius, color, 2, LINE_AA);
		//对于给定的2D点集,寻找可旋转的最小面积的包围矩形
		RotatedRect poly_rotateRect  =minAreaRect(points);
		Point2f pts[4];
		poly_rotateRect.points(pts);
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		for (int i = 0; i < 4; i++)
			line(img, pts[i], pts[(i + 1) % 4], color, 2, LINE_AA);
		//用椭圆拟合二维点集
		RotatedRect poly_ellipse = fitEllipse(points);
		color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		ellipse(img, poly_ellipse, color, 2, LINE_AA);
	imshow("PolyBound", img);
}

代码中出现void cv::RotatedRect::points(Point2f pts[]) const介绍如下:

python opencv在屏幕上画方框 opencv画矩形框_拟合_09

效果如下:

python opencv在屏幕上画方框 opencv画矩形框_拟合_10

python opencv在屏幕上画方框 opencv画矩形框_轮廓周围绘制矩形框和圆形框_11

2.创建包含轮廓的边界:

代码示例:

#include "pch.h"
#include <iostream>
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
int thresholdVal = 86;
int thresholdMax = 255;
void PolyBound_demo(int pos, void* userdata);
RNG rng(getTickCount());
int contourmode = 0;
int ploymode = 0;
Mat src;
Mat blursrc;
int main()
	src = imread("F:\\visual studio\\Image\\hand4.jpg");
	if (src.empty())
		cout << "Can't load the image " << endl;
	resize(src, src, Size(), 0.5, 0.5);
	//扩大图像的边界易于边框显示
	copyMakeBorder(src, src, 0, 50, 0, 0, BORDER_WRAP);
	imshow("src", src);
	Mat graysrc;
	cvtColor(src, graysrc, COLOR_BGR2GRAY);
	GaussianBlur(graysrc, blursrc, Size(5, 5),3,3);
	namedWindow("PolyBound", WINDOW_AUTOSIZE);
	createTrackbar("threshold", "PolyBound", &thresholdVal , thresholdMax, PolyBound_demo);
	createTrackbar("ploymode", "PolyBound", &ploymode, 1, PolyBound_demo);
	createTrackbar("contourmode", "PolyBound", &contourmode, 3, PolyBound_demo);
	PolyBound_demo(thresholdVal, 0);
	waitKey(0);
void PolyBound_demo(int pos, void* userdata)
	//阈值化
	Mat bin;
	threshold(~blursrc, bin, thresholdVal, thresholdMax, CV_THRESH_BINARY);
	imshow("bin", bin);
	//轮廓检测
	vector<vector<Point>> contours;
	vector<Vec4i> hiearchy;
	findContours(bin, contours, hiearchy, contourmode, CV_CHAIN_APPROX_SIMPLE, Point());
	//对图像轮廓点进行多边形拟合
	vector<vector<Point>> contours_ploy(contours.size());
	for (int i = 0; i < contours.size(); i++)
		approxPolyDP(contours[i], contours_ploy[i], 3, true);
	Mat dst;
	src.copyTo(dst);
	if (ploymode == 0)
		for (int i = 0; i < contours_ploy.size(); i++)
			//对于以上生成的点集,寻找最外面的矩形边界
			Rect poly_rect = boundingRect(contours_ploy[i]);
			Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
			rectangle(dst, poly_rect, color, 2, LINE_AA);
			//对给定的2D点集,去寻找面积最小的可包围它们的圆形
			Point2f center;
			float radius;
			minEnclosingCircle(contours_ploy[i], center, radius);
			color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
			circle(dst, center, radius, color, 2, LINE_AA);
		for (int i = 0; i < contours_ploy.size(); i++)
			//对于给定的2D点集,寻找可旋转的最小面积的包围矩形
			RotatedRect poly_rotateRect = minAreaRect(contours_ploy[i]);
			Point2f pts[4];
			poly_rotateRect.points(pts);
			Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
			for (int i = 0; i < 4; i++)
				line(dst, pts[i], pts[(i + 1) % 4], color, 2, LINE_AA);
			//用椭圆拟合二维点集 至少需要有5个点
			if (contours_ploy[i].size() >= 5)
				RotatedRect poly_ellipse = fitEllipse(contours_ploy[i]);
				color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
				ellipse(dst, poly_ellipse, color, 2, LINE_AA);
	imshow("PolyBound", dst);
}

效果如下:

python opencv在屏幕上画方框 opencv画矩形框_拟合_12

python opencv在屏幕上画方框 opencv画矩形框_OpenCV_13

ploymode=0时,显示轮廓最外面的矩阵边界、面积最小的可包围轮廓的圆形:

contourmode=0时,只查找最外层的轮廓:

python opencv在屏幕上画方框 opencv画矩形框_拟合_14

python opencv在屏幕上画方框 opencv画矩形框_approxPolyDP ()_15

ploymode=1时,显示可旋转的最小面积的包围矩形,用椭圆拟合轮廓,注意:用椭圆拟合至少需要5个点。

python opencv在屏幕上画方框 opencv画矩形框_点集_16

python opencv在屏幕上画方框 opencv画矩形框_approxPolyDP ()_17

python处理dataFrame数据加速

Python数据分析首先需要进行数据清洗处理,涉及到很多DataFrame和Series相关知识,这里对涉及到的常用方法进行整理,主要设计数据增减、变更索引、数值替换等。其中一些函数的参数并没有介绍齐全,可以通过参考pandas文档或者在编辑器输入方法+?查询(例如df.reindex?),实践是检验知识水平的最好途径。import pandas as pd import numpy