C++ OpenCV实现物体尺寸测量示例详解

目录
  • 前言
  • 一、图像透视矫正
  • 二、物体定位
  • 三、尺寸测量
  • 四、效果显示
  • 五、源码
  • 总结

前言

本文将使用OpenCV C++ 进行物体尺寸测量。具体来说就是先定位到待测物体的位置,然后测量物体的宽高。

一、图像透视矫正

原图如图所示。本案例的需求是测量图片中两张卡片的尺寸。首先,我们得定位到两张卡片的位置。第一步,我们首先得将白色A4纸切割出来,这样方便定位到两张卡片所在位置。这里用到的算法是图像透视矫正,具体可以参考OpenCV C++案例实战四《图像透视矫正》

//图像矫正
void getWarp(Mat src, Mat &Warp)
{
	Mat gray;
	cvtColor(src, gray, COLOR_BGR2GRAY);

	Mat thresh;
	threshold(gray, thresh, 0, 255, THRESH_BINARY | THRESH_OTSU);

	Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5));
	Mat open;
	morphologyEx(thresh, open, MORPH_OPEN, kernel);

	vector<vector<Point>>contours;
	findContours(open, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
	vector<vector<Point>>conPoly(contours.size());
	vector<Point>srcPts;

	//找到最大轮廓
	int MaxIndex = 0;
	double Area = 0;
	for (int i = 0; i < contours.size(); i++)
	{
		double area = contourArea(contours[i]);
		if (area > Area)
		{
			Area = area;
			MaxIndex = i;
		}
	}

	//获取矩形四个角点
	double peri = arcLength(contours[MaxIndex], true);
	approxPolyDP(contours[MaxIndex], conPoly[MaxIndex], 0.02*peri, true);

	srcPts = { conPoly[MaxIndex][0],conPoly[MaxIndex][1],conPoly[MaxIndex][2],conPoly[MaxIndex][3] };

	int T_L, B_L, B_R, T_R;
	int width = src.cols / 2;
	int height = src.rows / 2;
	for (int i = 0; i < srcPts.size(); i++)
	{
		if (srcPts[i].x < width && srcPts[i].y < height)
		{
			T_L = i;
		}
		if (srcPts[i].x < width && srcPts[i].y > height)
		{
			B_L = i;
		}
		if (srcPts[i].x > width && srcPts[i].y > height)
		{
			B_R = i;
		}
		if (srcPts[i].x > width && srcPts[i].y < height)
		{
			T_R = i;
		}
	}

	double UpWidth = EuDis(srcPts[T_L], srcPts[T_R]);
	double DownWidth = EuDis(srcPts[B_L], srcPts[B_R]);
	double MaxWidth = max(UpWidth, DownWidth);

	double UpHeight = EuDis(srcPts[T_L], srcPts[B_L]);
	double DownHeight = EuDis(srcPts[T_R], srcPts[B_R]);
	double MaxHeight = max(UpHeight, DownHeight);

	//透视变换进行图像矫正
	Point2f SrcAffinePts[4] = { Point2f(srcPts[T_L]),Point2f(srcPts[T_R]) ,Point2f(srcPts[B_R]) ,Point2f(srcPts[B_L]) };
	Point2f DstAffinePts[4] = { Point2f(0,0),Point2f(MaxWidth,0),Point2f(MaxWidth,MaxHeight),Point2f(0,MaxHeight) };

	Mat M = getPerspectiveTransform(SrcAffinePts, DstAffinePts);
	warpPerspective(src, Warp, M, Point(MaxWidth, MaxHeight));

}

效果如图所示。接下来,我们需要定位两张卡片所在位置,寻找特征。

二、物体定位

//获取物体坐标
void FindPts(Mat &Warp, vector<vector<Point>>&TargetPts)
{

	Mat gray;
	cvtColor(Warp, gray, COLOR_BGR2GRAY);

	Mat thresh;
	threshold(gray, thresh, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);

	Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
	Mat open;
	morphologyEx(thresh, open, MORPH_OPEN, kernel);

	vector<vector<Point>>contours;
	findContours(open, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
	vector<vector<Point>>conPoly(contours.size());
	//定位卡片四个角点
	for (int i = 0; i < contours.size(); i++)
	{
		double area = contourArea(contours[i]);

		if (area > 1000)
		{
			double peri = arcLength(contours[i], true);

			approxPolyDP(contours[i], conPoly[i], 0.02*peri, true);

			vector<Point>temp;
			temp = { conPoly[i][0],conPoly[i][1], conPoly[i][2], conPoly[i][3] };

			TargetPts.push_back(temp);
		}
	}
}

如图所示。通过上面代码段,我们已经定位出卡片的四个角点。接下来,只需根据角点位置就可以计算卡片的宽高了。

三、尺寸测量

//计算距离
void DrawAndCompute(Mat &Warp, vector<vector<Point>>&TargetPts)
{
	for (int i = 0; i < TargetPts.size(); i++)
	{
		for (int j = 0; j < TargetPts[i].size(); j++)
		{
			//尺寸测量
			Point PtA = Point(TargetPts[i][j]);
			Point PtB = Point(TargetPts[i][(j + 1) % TargetPts[i].size()]);
			double dis = round(EuDis(PtA, PtB) * 100) / 100;

			//效果显示
			circle(Warp, TargetPts[i][j], 5, Scalar(0, 255, 0), -1);
			line(Warp, PtA, PtB, Scalar(0, 0, 255), 2);
			char text[20];
			sprintf_s(text, "%.2f", dis);
			Point point = Point((PtA.x + PtB.x) / 2, (PtA.y + PtB.y) / 2);
			putText(Warp, text, point, FONT_HERSHEY_SIMPLEX, 1, Scalar(255, 0, 255), 2);
		}
	}
}

四、效果显示

五、源码

#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;

//欧式距离
double EuDis(Point pt1, Point pt2)
{
	return sqrt((pt2.x - pt1.x)*(pt2.x - pt1.x) + (pt2.y - pt1.y)*(pt2.y - pt1.y));
}

//图像矫正
void getWarp(Mat src, Mat &Warp)
{
	Mat gray;
	cvtColor(src, gray, COLOR_BGR2GRAY);

	Mat thresh;
	threshold(gray, thresh, 0, 255, THRESH_BINARY | THRESH_OTSU);

	Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5));
	Mat open;
	morphologyEx(thresh, open, MORPH_OPEN, kernel);

	vector<vector<Point>>contours;
	findContours(open, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
	vector<vector<Point>>conPoly(contours.size());
	vector<Point>srcPts;

	//找到最大轮廓
	int MaxIndex = 0;
	double Area = 0;
	for (int i = 0; i < contours.size(); i++)
	{
		double area = contourArea(contours[i]);
		if (area > Area)
		{
			Area = area;
			MaxIndex = i;
		}
	}

	//获取矩形四个角点
	double peri = arcLength(contours[MaxIndex], true);
	approxPolyDP(contours[MaxIndex], conPoly[MaxIndex], 0.02*peri, true);

	srcPts = { conPoly[MaxIndex][0],conPoly[MaxIndex][1],conPoly[MaxIndex][2],conPoly[MaxIndex][3] };

	int T_L, B_L, B_R, T_R;
	int width = src.cols / 2;
	int height = src.rows / 2;
	for (int i = 0; i < srcPts.size(); i++)
	{
		if (srcPts[i].x < width && srcPts[i].y < height)
		{
			T_L = i;
		}
		if (srcPts[i].x < width && srcPts[i].y > height)
		{
			B_L = i;
		}
		if (srcPts[i].x > width && srcPts[i].y > height)
		{
			B_R = i;
		}
		if (srcPts[i].x > width && srcPts[i].y < height)
		{
			T_R = i;
		}
	}

	double UpWidth = EuDis(srcPts[T_L], srcPts[T_R]);
	double DownWidth = EuDis(srcPts[B_L], srcPts[B_R]);
	double MaxWidth = max(UpWidth, DownWidth);

	double UpHeight = EuDis(srcPts[T_L], srcPts[B_L]);
	double DownHeight = EuDis(srcPts[T_R], srcPts[B_R]);
	double MaxHeight = max(UpHeight, DownHeight);

	//透视变换进行图像矫正
	Point2f SrcAffinePts[4] = { Point2f(srcPts[T_L]),Point2f(srcPts[T_R]) ,Point2f(srcPts[B_R]) ,Point2f(srcPts[B_L]) };
	Point2f DstAffinePts[4] = { Point2f(0,0),Point2f(MaxWidth,0),Point2f(MaxWidth,MaxHeight),Point2f(0,MaxHeight) };

	Mat M = getPerspectiveTransform(SrcAffinePts, DstAffinePts);
	warpPerspective(src, Warp, M, Point(MaxWidth, MaxHeight));

}

//获取物体坐标
void FindPts(Mat &Warp, vector<vector<Point>>&TargetPts)
{

	Mat gray;
	cvtColor(Warp, gray, COLOR_BGR2GRAY);

	Mat thresh;
	threshold(gray, thresh, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);

	Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
	Mat open;
	morphologyEx(thresh, open, MORPH_OPEN, kernel);

	vector<vector<Point>>contours;
	findContours(open, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
	vector<vector<Point>>conPoly(contours.size());
	//定位卡片四个角点
	for (int i = 0; i < contours.size(); i++)
	{
		double area = contourArea(contours[i]);

		if (area > 1000)
		{
			double peri = arcLength(contours[i], true);

			approxPolyDP(contours[i], conPoly[i], 0.02*peri, true);

			vector<Point>temp;
			temp = { conPoly[i][0],conPoly[i][1], conPoly[i][2], conPoly[i][3] };

			TargetPts.push_back(temp);
		}
	}
}

//计算距离
void DrawAndCompute(Mat &Warp, vector<vector<Point>>&TargetPts)
{
	for (int i = 0; i < TargetPts.size(); i++)
	{
		for (int j = 0; j < TargetPts[i].size(); j++)
		{
			//尺寸测量
			Point PtA = Point(TargetPts[i][j]);
			Point PtB = Point(TargetPts[i][(j + 1) % TargetPts[i].size()]);
			double dis = round(EuDis(PtA, PtB) * 100) / 100;

			//效果显示
			circle(Warp, TargetPts[i][j], 5, Scalar(0, 255, 0), -1);
			line(Warp, PtA, PtB, Scalar(0, 0, 255), 2);
			char text[20];
			sprintf_s(text, "%.2f", dis);
			Point point = Point((PtA.x + PtB.x) / 2, (PtA.y + PtB.y) / 2);
			putText(Warp, text, point, FONT_HERSHEY_SIMPLEX, 1, Scalar(255, 0, 255), 2);
		}
	}
}

int main()
{
	Mat src = imread("src.jpg");
	if (src.empty())
	{
		cout << "No Image!" << endl;
		system("pause");
		return -1;
	}

	Mat Warp;
	getWarp(src, Warp);

	vector<vector<Point>>TargetPts;
	FindPts(Warp, TargetPts);

	DrawAndCompute(Warp, TargetPts);

	imshow("Warp", Warp);
	waitKey(0);
	destroyAllWindows();
	system("pause");
	return 0;
}

总结

本文使用OpenCV C++ 进行物体尺寸测量,关键步骤有以下几点。

1、图像透视矫正。方便定位物体所在位置。

2、物体定位。定位所需物体位置,获取特征。

3、根据已知特征进行计算。

以上就是C++ OpenCV实现物体尺寸测量示例详解的详细内容,更多关于C++ OpenCV物体尺寸测量的资料请关注我们其它相关文章!

(0)

相关推荐

  • Opencv实现对象提取与测量

    本文实例为大家分享了Opencv3实现对象提取与测量的具体代码,供大家参考,具体内容如下 案例背景:下图为一张卫星拍摄的图片,要获取其中岛屿的周长和面积 方案思路:高斯模糊去噪,灰度二值化提取轮廓,闭操作填充缝隙 或小的孔洞,寻找轮廓,通过轮廓特征选择轮廓 #include<opencv2\opencv.hpp> using namespace cv; using namespace std; int main(int arc, char** argv) { Mat src = imread(

  • C++ OpenCV实战之图像透视矫正

    目录 前言 一.图像预处理 二.轮廓提取 1.提取最外轮廓 2.提取矩形四个角点 3.将矩形角点排序 三.透视矫正 四.源码 前言 本文将使用OpenCV C++ 进行图像透视矫正. 一.图像预处理 原图如图所示.首先进行图像预处理.将图像进行灰度.滤波.二值化.形态学等操作,目的是为了下面的轮廓提取.在这里我还使用了形态学开.闭操作,目的是使整个二值图像连在一起.大家在做图像预处理时,可以根据图像特征自行处理. Mat gray; cvtColor(src, gray, COLOR_BGR2G

  • OpenCV半小时掌握基本操作之对象测量

    目录 概述 对象测量 多边形拟合 计算对象中心 [OpenCV]⚠️高手勿入! 半小时学会基本操作 ⚠️ 对象测量 概述 OpenCV 是一个跨平台的计算机视觉库, 支持多语言, 功能强大. 今天小白就带大家一起携手走进 OpenCV 的世界. 对象测量 对象测量可以帮助我们进行矩阵计算: 获取弧长与面积 多边形拟合 计算图片对象中心 原点距: 中心距: 图像重心坐标: 多边形拟合 步骤: 读取图片 转换成灰度图 二值化 轮廓检测 计算轮廓周长 多边形拟合 格式: cv2.approxPolyD

  • Python OpenCV实现测量图片物体宽度

    一. 题目描述 测量所给图片的高度,即上下边缘间的距离. 思路: 将图片进行阈值操作得到二值化图片. 截取只包含上下边框的部分,以便于后续的轮廓提取 轮廓检测 得到结果 二. 实现过程 1.用于给图片添加中文字符 #用于给图片添加中文字符 def ImgText_CN(img, text, left, top, textColor=(0, 255, 0), textSize=20): if (isinstance(img, np.ndarray)): #判断是否为OpenCV图片类型 img =

  • C++ OpenCV实现物体尺寸测量示例详解

    目录 前言 一.图像透视矫正 二.物体定位 三.尺寸测量 四.效果显示 五.源码 总结 前言 本文将使用OpenCV C++ 进行物体尺寸测量.具体来说就是先定位到待测物体的位置,然后测量物体的宽高. 一.图像透视矫正 原图如图所示.本案例的需求是测量图片中两张卡片的尺寸.首先,我们得定位到两张卡片的位置.第一步,我们首先得将白色A4纸切割出来,这样方便定位到两张卡片所在位置.这里用到的算法是图像透视矫正,具体可以参考OpenCV C++案例实战四<图像透视矫正> //图像矫正 void ge

  • Python+Opencv实现物体尺寸测量的方法详解

    目录 1.效果展示 2.项目介绍 3.项目搭建 4.utils.py文件代码展示与讲解 5.项目代码展示与讲解 6.项目资源 7.项目总结 1.效果展示 我们将以两种方式来展示我们这个项目的效果. 下面这是视频的实时检测,我分别用了盒子和盖子来检测,按理来说效果不应该怎么差的,但我实在没有找到合适的背景与物体.且我的摄像头使用的是外设,我不得不手持,所以存在一点点的抖动,但我可以保证,它是缺少了适合检测物体与背景. 我使用手机拍了一张照片并经过了ps修改了背景,效果不错. 2.项目介绍 本项目中

  • C++ OpenCV生成蒙太奇图像的示例详解

    目录 前言 一.输入模板图像 二.读取素材图像 三.生成蒙太奇模板 四.生成蒙太奇图像 五.源码 总结 前言 本文将使用OpenCV C++ 生成蒙太奇图像. 一.输入模板图像 原图如图所示.我们将对此图生成蒙太奇图像. Mat src = imread("Taylor.jpg"); if (src.empty()) { cout << "No image!" << endl; system("pause"); retur

  • Python+OpenCV人脸检测原理及示例详解

    关于opencv OpenCV 是 Intel 开源计算机视觉库 (Computer Version) .它由一系列 C 函数和少量 C++ 类构成,实现了图像处理和计算机视觉方面的很多通用算法. OpenCV 拥有包括 300 多个 C 函数的跨平台的中.高层 API .它不依赖于其它的外部库 -- 尽管也可以使用某些外部库. OpenCV 对非商业应用和商业应用都是免费 的.同时 OpenCV 提供了对硬件的访问,可以直接访问摄像头,并且 opencv 还提供了一个简单的 GUI(graph

  • python opencv图像处理基本操作示例详解

    目录 1.图像基本操作 ①读取图像 ②显示图像 ③视频读取 ④图像截取 ⑤颜色通道提取及还原 ⑥边界填充 ⑦数值计算 ⑧图像融合 2.阈值与平滑处理 ①设定阈值并对图像处理 ②图像平滑-均值滤波 ③图像平滑-方框滤波 ④图像平滑-高斯滤波 ⑤图像平滑-中值滤波 3.图像的形态学处理 ①腐蚀操作 ②膨胀操作 ③开运算和闭运算 4.图像梯度处理 ①梯度运算 ②礼帽与黑帽 ③图像的梯度处理 5.边缘检测 ①Canny边缘检测 1.图像基本操作 ①读取图像 ②显示图像 该函数中,name是显示窗口的名字

  • python计算机视觉opencv卡号识别示例详解

    目录 一.模板预处理 1.将模板设置为二值图 2.检测模板的轮廓 3.对模板轮廓排序,并将数字和轮廓一一对应,以字典存储 4.备注 二.图片预处理 1.初始化卷积核 2.图片预处理第一部分 3.图像预处理第二部分 三.轮廓处理 1.大轮廓过滤 2.小轮廓分割 模板图片如下: 需识别的图片如下: 一.模板预处理 1.将模板设置为二值图 2.检测模板的轮廓 3.对模板轮廓排序,并将数字和轮廓一一对应,以字典存储 排序的函数如下: 排序并存储: 4.备注 ①每一个数字对应的是二值图截出来的那个数字图的

  • OpenCV实现相机标定示例详解

    目录 环境准备 相机标定 棋盘格图片 实时显示相机的画面 在线标定 实时显示相机画面,按键保存能检测到角点的 棋盘格图片 离线标定 畸变矫正 环境准备 vs2015+opencv4.10安装与配置 相机标定 棋盘格图片 可以自己生成,然后打印到A4纸上.(也可以去TB买一块,平价买亚克力板的,不反光买氧化铝材质,高精度买陶瓷的) /** * 生成棋盘格图片 **/ int generateCalibrationPicture() { //Mat frame = imread("3A4.bmp&q

  • Python OpenCV形态学运算示例详解

    目录 1. 腐蚀 & 膨胀 1.1什么是腐蚀&膨胀 1.2 腐蚀方法 cv2.erode() 1.3 膨胀方法 cv2.dilate() 2. 开运算 & 闭运算 2.1 简述 2.2 开运算 2.3 闭运算 3. morphologyEx()方法 3.1 morphologyEx()方法 介绍 3.2 梯度运算 3.3 顶帽运算 3.4 黑帽运算 1. 腐蚀 & 膨胀 1.1什么是腐蚀&膨胀 腐蚀&膨胀是图像形态学中的两种核心操作 腐蚀可以描述为是让图像沿

  • Python OpenCV实现图形检测示例详解

    目录 1. 轮廓识别与描绘 1.1 cv2.findComtours()方法 1.2 cv2.drawContours() 方法 1.3 代码示例 2. 轮廓拟合 2.1 矩形包围框拟合 - cv2.boundingRect() 2.2圆形包围框拟合 - cv2.minEnclosingCircle() 3. 凸包 绘制 4. Canny边缘检测 - cv2.Canny() 4.1 cv2.Canny() 用法简介 4.2 代码示例 5. 霍夫变换 5.1 概述 5.2 cv2.HoughLin

  • 基于Opencv图像识别实现答题卡识别示例详解

    目录 1. 项目分析 2.项目实验 3.项目结果 总结 在观看唐宇迪老师图像处理的课程中,其中有一个答题卡识别的小项目,在此结合自己理解做一个简单的总结. 1. 项目分析 首先在拿到项目时候,分析项目目的是什么,要达到什么样的目标,有哪些需要注意的事项,同时构思实验的大体流程. 图1. 答题卡测试图像 比如在答题卡识别的项目中,针对测试图片如图1 ,首先应当实现的功能是: 能够捕获答题卡中的每个填涂选项. 将获取的填涂选项与正确选项做对比计算其答题正确率. 2.项目实验 在对测试图像进行形态学操

随机推荐