【opencv450-samples】轮廓点拟合椭圆fitellipse.cpp

2023-11-10 22:59

本文主要是介绍【opencv450-samples】轮廓点拟合椭圆fitellipse.cpp,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

测试示例

/***********************************************************************************  This program is demonstration for ellipse fitting. Program finds*  contours and approximate it by ellipses using three methods.*  1: OpenCV's original method fitEllipse which implements Fitzgibbon 1995 method.*  2: The Approximate Mean Square (AMS) method fitEllipseAMS  proposed by Taubin 1991*  3: The Direct least square (Direct) method fitEllipseDirect proposed by Fitzgibbon1999.**  Trackbar specify threshold parameter.**  White lines is contours/input points and the true ellipse used to generate the data.*  1: Blue lines is fitting ellipses using openCV's original method.*  2: Green lines is fitting ellipses using the AMS method.*  3: Red lines is fitting ellipses using the Direct method.***  Original Author:  Denis Burenkov*  AMS and Direct Methods Author:  Jasper Shemilt*  这个程序是椭圆拟合的演示。 程序使用三种方法找到轮廓并通过椭圆对其进行近似。
* 1:OpenCV 的原始方法 fitEllipse 实现了 Fitzgibbon 1995 方法。
* 2:Taubin 1991 提出的近似均方 (AMS) 方法 fitEllipseAMS
* 3:Fitzgibbon1999提出的直接最小二乘(Direct)方法 fitEllipseDirect。
*
* Trackbar  指定阈值参数.//
*
* 白线是轮廓/输入点和用于生成数据的真实椭圆。
* 1:蓝线是使用openCV的原始方法拟合椭圆。
* 2:绿线是使用 AMS 方法拟合椭圆。
* 3:红线是使用 Direct 方法拟合椭圆。
*
*
* 原作者:丹尼斯布伦科夫
* AMS 和直接方法作者:Jasper Shemilt
*
*
********************************************************************************/
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>using namespace cv;
using namespace std;
//画布
class canvas {
public:bool setupQ;cv::Point origin;//左上原点cv::Point corner;//右下角点int minDims, maxDims;//最小和最大维度double scale;//比例int rows, cols;cv::Mat img;//画布初始化void init(int minD, int maxD) {// Initialise the canvas with minimum and maximum rows and column sizes.//使用最小和最大行和列大小初始化画布。minDims = minD; maxDims = maxD;origin = cv::Point(0, 0);corner = cv::Point(0, 0);scale = 1.0;rows = 0;cols = 0;setupQ = false;}//画布拉伸void stretch(cv::Point2f min, cv::Point2f max) {// Stretch the canvas to include the points min and max.//拉伸画布以包括点 min 和 max。if (setupQ) {if (corner.x < max.x) { corner.x = (int)(max.x + 1.0); };向右下移动角点   扩大宽度if (corner.y < max.y) { corner.y = (int)(max.y + 1.0); };//扩大高度if (origin.x > min.x) { origin.x = (int)min.x; };//向左上移动原点if (origin.y > min.y) { origin.y = (int)min.y; };// }else {origin = cv::Point((int)min.x, (int)min.y);//更新原点corner = cv::Point((int)(max.x + 1.0), (int)(max.y + 1.0));//更新右下角点}int c = (int)(scale * ((corner.x + 1.0) - origin.x));//宽度*比例if (c < minDims) {scale = scale * (double)minDims / (double)c;//修正宽度比例  不低于最小维度}else {if (c > maxDims) {scale = scale * (double)maxDims / (double)c;//修正宽度比例  不超过最大维度}}int r = (int)(scale * ((corner.y + 1.0) - origin.y));if (r < minDims) {scale = scale * (double)minDims / (double)r;//修正高度比例  不低于最小维度}else {if (r > maxDims) {scale = scale * (double)maxDims / (double)r;//修正高度比例  不高于最大维度}}cols = (int)(scale * ((corner.x + 1.0) - origin.x));//新的列数rows = (int)(scale * ((corner.y + 1.0) - origin.y));//新的行数setupQ = true;}void stretch(vector<Point2f> pts){   // Stretch the canvas so all the points pts are on the canvas.//拉伸画布,使所有点 pts 都在画布上。cv::Point2f min = pts[0];cv::Point2f max = pts[0];for (size_t i = 1; i < pts.size(); i++) {Point2f pnt = pts[i];//搜索最小,最大点if (max.x < pnt.x) { max.x = pnt.x; };if (max.y < pnt.y) { max.y = pnt.y; };if (min.x > pnt.x) { min.x = pnt.x; };if (min.y > pnt.y) { min.y = pnt.y; };};stretch(min, max);//拉伸,计算新的列数  行数}void stretch(cv::RotatedRect box)//{   // Stretch the canvas so that the rectangle box is on the canvas.//拉伸画布,使旋转矩形框位于画布上。cv::Point2f min = box.center;//矩形中心cv::Point2f max = box.center;cv::Point2f vtx[4];//四个角点box.points(vtx);//获取边框的四个角点for (int i = 0; i < 4; i++) {//遍历四个角点,找出最大(x,y)点,最小(x,y)点cv::Point2f pnt = vtx[i];if (max.x < pnt.x) { max.x = pnt.x; };if (max.y < pnt.y) { max.y = pnt.y; };if (min.x > pnt.x) { min.x = pnt.x; };if (min.y > pnt.y) { min.y = pnt.y; };}stretch(min, max);//拉伸画布}//绘制带框的椭圆void drawEllipseWithBox(cv::RotatedRect box, cv::Scalar color, int lineThickness){if (img.empty()) {stretch(box);img = cv::Mat::zeros(rows, cols, CV_8UC3);//初始化背景}box.center = scale * cv::Point2f(box.center.x - origin.x, box.center.y - origin.y);//box.size.width = (float)(scale * box.size.width);box.size.height = (float)(scale * box.size.height);ellipse(img, box, color, lineThickness, LINE_AA);Point2f vtx[4];box.points(vtx);for (int j = 0; j < 4; j++) {line(img, vtx[j], vtx[(j + 1) % 4], color, lineThickness, LINE_AA);}}//绘制点void drawPoints(vector<Point2f> pts, cv::Scalar color){if (img.empty()) {stretch(pts);img = cv::Mat::zeros(rows, cols, CV_8UC3);}for (size_t i = 0; i < pts.size(); i++) {Point2f pnt = scale * cv::Point2f(pts[i].x - origin.x, pts[i].y - origin.y);img.at<cv::Vec3b>(int(pnt.y), int(pnt.x))[0] = (uchar)color[0];img.at<cv::Vec3b>(int(pnt.y), int(pnt.x))[1] = (uchar)color[1];img.at<cv::Vec3b>(int(pnt.y), int(pnt.x))[2] = (uchar)color[2];};}//绘制标签void drawLabels(std::vector<std::string> text, std::vector<cv::Scalar> colors){if (img.empty()) {img = cv::Mat::zeros(rows, cols, CV_8UC3);}int vPos = 0;for (size_t i = 0; i < text.size(); i++) {cv::Scalar color = colors[i];std::string txt = text[i];Size textsize = getTextSize(txt, FONT_HERSHEY_COMPLEX, 1, 1, 0);vPos += (int)(1.3 * textsize.height);Point org((img.cols - textsize.width), vPos);cv::putText(img, txt, org, FONT_HERSHEY_COMPLEX, 1, color, 1, LINE_8);}}};static void help(char** argv)
{cout << "\nThis program is demonstration for ellipse fitting. The program finds\n""contours and approximate it by ellipses. Three methods are used to find the \n""elliptical fits: fitEllipse, fitEllipseAMS and fitEllipseDirect.\n""Call:\n"<< argv[0] << " [image_name -- Default ellipses.jpg]\n" << endl;
}int sliderPos = 70;//滑块位置Mat image;bool fitEllipseQ, fitEllipseAMSQ, fitEllipseDirectQ;//三种拟合方法
cv::Scalar fitEllipseColor = Scalar(255, 0, 0);//蓝色
cv::Scalar fitEllipseAMSColor = Scalar(0, 255, 0);//绿色
cv::Scalar fitEllipseDirectColor = Scalar(0, 0, 255);//红色
cv::Scalar fitEllipseTrueColor = Scalar(255, 255, 255);//白色void processImage(int, void*);//先声明,main之后实现int main(int argc, char** argv)
{//三种计算方式fitEllipseQ = true;fitEllipseAMSQ = true;fitEllipseDirectQ = true;//读取图片cv::CommandLineParser parser(argc, argv, "{help h||}{@image|ok0015.bmp|}");//ellipses.jpg    fruits.jpg  detect_blob.png ok0008.bmpif (parser.has("help")){help(argv);return 0;}string filename = parser.get<string>("@image");image = imread(samples::findFile(filename), 0);if (image.empty()){cout << "Couldn't open image " << filename << "\n";return 0;}if (image.cols > 1920){resize(image, image, Size(750, 615));}if (image.channels() == 3){cvtColor(image, image, COLOR_BGR2GRAY);}imshow("source", image);namedWindow("result", WINDOW_NORMAL);// 创建滑动条  :设置二值图像的白色阈值createTrackbar("threshold", "result", &sliderPos, 255, processImage);processImage(0, 0);// Wait for a key stroke; the same function arranges events processingwaitKey();return 0;
}// Define trackbar callback function. This function finds contours,
// draws them, and approximates by ellipses.
//定义轨迹栏回调函数。 此函数查找轮廓、绘制轮廓并通过椭圆进行近似。
void processImage(int /*h*/, void*)
{RotatedRect box, boxAMS, boxDirect;//三种方式的矩形框vector<vector<Point> > contours;//轮廓点 集合Mat bimage = image >= sliderPos;//白色阈值 以上的像素 findContours(bimage, contours, RETR_LIST, CHAIN_APPROX_NONE);//找到轮廓点 集合canvas paper;paper.init(int(0.8 * MIN(bimage.rows, bimage.cols)), int(1.2 * MAX(bimage.rows, bimage.cols)));//图像窄边的0.8倍  图像宽边的1.2倍paper.stretch(cv::Point2f(0.0f, 0.0f), cv::Point2f((float)(bimage.cols + 2.0), (float)(bimage.rows + 2.0)));//延伸画布//文本显示std::vector<std::string> text;std::vector<cv::Scalar> color;if (fitEllipseQ) {text.push_back("OpenCV");color.push_back(fitEllipseColor);}if (fitEllipseAMSQ) {text.push_back("AMS");color.push_back(fitEllipseAMSColor);}if (fitEllipseDirectQ) {text.push_back("Direct");color.push_back(fitEllipseDirectColor);}paper.drawLabels(text, color);//绘制文本int margin = 2;vector< vector<Point2f> > points;for (size_t i = 0; i < contours.size(); i++)//遍历所有轮廓{size_t count = contours[i].size();//轮廓i的 轮廓点数if (count < 6)continue;//轮廓点少于6不考虑Mat pointsf;Mat(contours[i]).convertTo(pointsf, CV_32F);//轮廓点坐标转换为Matvector<Point2f>pts;//采样点for (int j = 0; j < pointsf.rows; j++) {//遍历单个轮廓的所有行Point2f pnt = Point2f(pointsf.at<float>(j, 0), pointsf.at<float>(j, 1));//点的x,y坐标if ((pnt.x > margin && pnt.y > margin && pnt.x < bimage.cols - margin && pnt.y < bimage.rows - margin)) {//点在画布上if (j % 20 == 0) {//取20分之一的点pts.push_back(pnt);}}}points.push_back(pts);//采样的轮廓点 集合}//拟合椭圆和绘制椭圆for (size_t i = 0; i < points.size(); i++)//遍历采样的轮廓点集{vector<Point2f> pts = points[i];if (pts.size() <= 5) {//单个轮廓点数少于5 不考虑continue;}if (fitEllipseQ) {box = fitEllipse(pts);//拟合椭圆,得到旋转矩形if (MAX(box.size.width, box.size.height) > MIN(box.size.width, box.size.height) * 30 ||  //长边比短边的三倍还要长,不考虑跳过MAX(box.size.width, box.size.height) <= 0 ||MIN(box.size.width, box.size.height) <= 0) {continue;//旋转矩形不合法,跳过};}if (fitEllipseAMSQ) {boxAMS = fitEllipseAMS(pts);//AMS法拟合椭圆if (MAX(boxAMS.size.width, boxAMS.size.height) > MIN(boxAMS.size.width, boxAMS.size.height) * 30 ||MAX(box.size.width, box.size.height) <= 0 ||MIN(box.size.width, box.size.height) <= 0) {continue;};}if (fitEllipseDirectQ) {boxDirect = fitEllipseDirect(pts);//直接拟合if (MAX(boxDirect.size.width, boxDirect.size.height) > MIN(boxDirect.size.width, boxDirect.size.height) * 30 ||MAX(box.size.width, box.size.height) <= 0 ||MIN(box.size.width, box.size.height) <= 0) {continue;};}//绘制椭圆if (fitEllipseQ) {paper.drawEllipseWithBox(box, fitEllipseColor, 3);//在画布上绘制椭圆  线宽3}if (fitEllipseAMSQ) {paper.drawEllipseWithBox(boxAMS, fitEllipseAMSColor, 2);//}if (fitEllipseDirectQ) {paper.drawEllipseWithBox(boxDirect, fitEllipseDirectColor, 1);}paper.drawPoints(pts, cv::Scalar(255, 255, 255));//绘制采样的点为 白点}imshow("result", paper.img);//显示最终结果
}

这篇关于【opencv450-samples】轮廓点拟合椭圆fitellipse.cpp的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/385842

相关文章

OpenCV结构分析与形状描述符(11)椭圆拟合函数fitEllipse()的使用

操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C++11 算法描述 围绕一组2D点拟合一个椭圆。 该函数计算出一个椭圆,该椭圆在最小二乘意义上最好地拟合一组2D点。它返回一个内切椭圆的旋转矩形。使用了由[90]描述的第一个算法。开发者应该注意,由于数据点靠近包含的 Mat 元素的边界,返回的椭圆/旋转矩形数据

类模板中.h和.cpp的实现方法

一般类的声明和实现放在两个文件中,然后在使用该类的主程序代码中,包含相应的头文件".h"就可以了,但是,模板类必须包含该其实现的.cpp文件才行。也就是说,在你的主程序中,将 #include"DouCirLList.h" 替换成 #include"DouCirLList.cpp" 应该就可以了。 在使用类模板技术时,可在.h中实现,也可在.h和.cpp中分开实现,若用.h实

CPP中的hash [more cpp-7]

写在前面 hash 在英文中是弄乱的含义。在编程中,hash是一种数据技术,它把任意类型的数据通过算法,生成一串数字(hash code),实现hash的函数称为哈希函数,又称散列函数,杂凑函数。在CPP中hashcode是一个size_t类型的数字。 你可能会问?把数据弄乱有什么用?为什么我们要把数据映射到一串数字上?这又什么意义吗?我们先看看hash的性质 一般hash性质 唯一性(唯

【最新华为OD机试E卷-支持在线评测】机器人活动区域(100分)多语言题解-(Python/C/JavaScript/Java/Cpp)

🍭 大家好这里是春秋招笔试突围 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-E/D卷的三语言AC题解 💻 ACM金牌🏅️团队| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 🍿 最新华为OD机试D卷目录,全、新、准,题目覆盖率达 95% 以上,支持题目在线评测,专栏文章质量平均 94 分 最新华为OD机试目录: https://blog.

llama.cpp demo

git clone https://github.com/ggerganov/llama.cppcd llama.cpp 修改Makefile使能mfma参数     MK_CFLAGS   += -mfma -mf16c -mavx     MK_CXXFLAGS += -mfma -mf16c -mavx 安装python3依赖 cat ./requirements/requirem

6. 深度学习中的正则化技术:防止过拟合

引言 过拟合是深度学习模型在训练过程中常遇到的挑战。过拟合会导致模型在训练数据上表现良好,但在新数据上表现不佳。为了防止过拟合,研究者们提出了多种正则化技术,如L1/L2正则化、Dropout、数据增强等。这些技术通过约束模型的复杂度或增加数据的多样性,有效提高了模型的泛化能力。本篇博文将深入探讨这些正则化技术的原理、应用及其在实际深度学习任务中的效果。 1. 过拟合的原因与影响 过拟合通常

OpenCV结构分析与形状描述符(10)检测并提取轮廓函数findContours()的使用

操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C++11 算法描述 在二值图像中查找轮廓。 该函数使用算法 253从二值图像中检索轮廓。轮廓是有用的工具,可用于形状分析和对象检测与识别。参见 OpenCV 示例目录中的 squares.cpp。 findContours 是 OpenCV 库中的一个重要函数

(4)SVG-path中的椭圆弧A(绝对)或a(相对)

1、概念 表示经过起始点(即上一条命令的结束点),到结束点之间画一段椭圆弧 2、7个参数 rx,ry,x-axis-rotation,large-arc-flag,sweep-flag,x,y (1)和(2)rx,ry rx:椭圆的x轴半径(即水平半径) ry:椭圆的y轴半径(即垂直半径) 这两个参数好理解,就是椭圆的两条对称轴半径,相等即为圆 也可以写比例,写比例时默认用符合条件

OpenCV结构分析与形状描述符(9)检测轮廓相对于其凸包的凹陷缺陷函数convexityDefects()的使用

操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C++11 算法描述 查找一个轮廓的凸性缺陷。 下图显示了一个手部轮廓的凸性缺陷: convexityDefects 是 OpenCV 库中的一个函数,用于检测轮廓相对于其凸包的凹陷缺陷。这个函数可以帮助识别轮廓中的凹进去的部分,通常被用来分析手部或其他物体的形状

【最新华为OD机试E卷-支持在线评测】分糖果(100分)-多语言题解-(Python/C/JavaScript/Java/Cpp)

🍭 大家好这里是春秋招笔试突围 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-E/D卷的三语言AC题解 💻 ACM金牌🏅️团队| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 🍿 最新华为OD机试D卷目录,全、新、准,题目覆盖率达 95% 以上,支持题目在线评测,专栏文章质量平均 94 分 最新华为OD机试目录: https://blog.