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算法流程
- 首先将图像变为二值图像
- 发现轮廓找到图像轮廓
- 通过相关API在轮廓点上找到最小包含矩形和圆,旋转矩形与椭圆
- 绘制他们
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。函数最后一个参数是可选的轮廓偏移参数,按指定的移动距离绘制所有的轮廓。