openCV 轮廓查找-测量物体尺寸

一,利用openCV的findContours轮廓查找功能,用已知物体的尺寸(比如硬币)作为参考,根据实际尺寸与像素尺寸的比列,求出图片中物体的实际大小。存在的问题有两个:

  • 图片的阴影导致轮廓不准确,除了多给点光之外没有想到怎么消除阴影。
  • 拍摄的角度要求垂直物体,这个也很难做到,可以靠工装固定,目前不知道怎么用算法来规避。

二,流程

三,代码

#include "stdafx.h"
#include <iostream>

#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/video/background_segm.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <opencv\cxcore.hpp>
#include <stdio.h>
using namespace std;
using namespace cv;

Mat g_srcImage;
Mat g_grayImage;

const int g_dReferWidth=19;//mm 
double g_dPixelsPerMetric;
vector<vector<cv::Point>> g_vContours;
vector<Vec4i> g_vHierarchy;
bool g_bFirst=true;

static cv::Point2f midpoint(cv::Point2f& ptA, cv::Point2f& ptB);//求中点 
static float getDistance(Point2f pointA, Point2f pointB);//求距离
static bool ContoursSortFun(vector<cv::Point> contour1, vector<cv::Point> contour2);//按照 x坐标 排序
//-----------------------------------【main( )函数】--------------------------------------------
//      描述:控制台应用程序的入口函数,我们的程序从这里开始
//-------------------------------------------------------------------------------------------------
int main(int argc, const char** argv)
{
	system("color 1F");

	g_srcImage = imread("1.jpg", 1);
	//灰度 降低计算量
	cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);
	
	//高斯滤波 降噪
	GaussianBlur(g_grayImage, g_grayImage, Size(7, 7), 0);
	imshow("高斯滤波", g_grayImage);
	
	//边缘检测
	Canny(g_grayImage, g_grayImage, 50,100);

	Mat element = getStructuringElement(MORPH_RECT, Size(15, 15)); //隔开物体
	dilate(g_grayImage, g_grayImage, element);//膨胀
	erode(g_grayImage, g_grayImage, element);//腐蚀
	imshow("形态学", g_grayImage);

	//寻找轮廓
	findContours(g_grayImage, g_vContours, g_vHierarchy, CV_RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
	
	std::sort(g_vContours.begin(),g_vContours.end(), ContoursSortFun);//按照从左到右 排序
	for (unsigned i = 0; i < g_vContours.size(); i++) {
		
		if (contourArea(g_vContours[i]) < 100)//面积太小 则忽略
			continue;

		RotatedRect box = minAreaRect(g_vContours[i]);
		Point2f boxPoints[4];
		box.points(boxPoints);

		Point2f pointA = midpoint(boxPoints[0], boxPoints[1]);
		Point2f pointB = midpoint(boxPoints[1], boxPoints[2]);
		Point2f pointC = midpoint(boxPoints[2], boxPoints[3]);
		Point2f pointD = midpoint(boxPoints[3], boxPoints[0]);

		circle(g_srcImage, pointA, 2, Scalar(0, 0, 255));
		circle(g_srcImage, pointB, 2, Scalar(0, 0, 255));
		circle(g_srcImage, pointC, 2, Scalar(0, 0, 255));
		circle(g_srcImage, pointD, 2, Scalar(0, 0, 255));

		line(g_srcImage, pointA, pointC, Scalar(255, 0, 0));
		line(g_srcImage, pointD, pointB, Scalar(255, 0, 0));

		double dWidth = getDistance(pointA, pointC);
		double dHeight = getDistance(pointD, pointB);
		if (g_bFirst) {
			g_dPixelsPerMetric = dWidth/g_dReferWidth; //计算像素与 实际大小的比列
			cout << "pixelPerMetric:" << dWidth <<" "<< g_dReferWidth <<"  "<< g_dPixelsPerMetric;
			g_bFirst = false;
		}

		cout << "dWidth" << dWidth <<"   "<< dHeight<< "      "<<dWidth / g_dPixelsPerMetric<<"    "<< dHeight / g_dPixelsPerMetric;
		putText(g_srcImage, cv::format("(%.0f,%.0f)", dWidth/g_dPixelsPerMetric,dHeight/g_dPixelsPerMetric), boxPoints[2],FONT_HERSHEY_COMPLEX,0.5,Scalar(0,0,255));

		for (int i = 0; i <=3; i++)
		{
			line(g_srcImage, boxPoints[i], boxPoints[(i + 1) % 4], Scalar(0, 255, 0));
		}
	}


	cv::namedWindow("效果", CV_WINDOW_AUTOSIZE);
	cv::imshow("效果", g_srcImage);

	waitKey(0);
	return 0;
}

Point2f midpoint(Point2f& ptA, Point2f& ptB) {
	return Point2f((ptA.x+ ptB.x)*0.5,(ptA.y + ptB.y)*0.5);
}

float getDistance(Point2f pointA, Point2f pointB)
{
	float distance;
	distance = powf((pointA.x - pointB.x), 2) + powf((pointA.y - pointB.y), 2);
	distance = sqrtf(distance);
	return distance;
}

bool ContoursSortFun(vector<cv::Point> contour1, vector<cv::Point> contour2) {
	return  (contour1[0].x<contour2[0].x); // a.x < b.x;
}

四,效果

参考:使用OpenCV测量图像中物体的大小_-出发-的博客-CSDN博客_opencv测量物体尺寸

  • 30
    点赞
  • 381
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 24
    评论
使用OpenCV调用摄像头实时测量物体尺寸,你可以按照以下步骤进行: 1. 导入必要的库 ```python import cv2 import numpy as np ``` 2. 创建VideoCapture对象来读取摄像头 ```python cap = cv2.VideoCapture(0) ``` 3. 定义一些常量 ```python # 摄像头分辨率 frameWidth = 640 frameHeight = 480 # 比例因子 scale = 2 # 颜色范围 lower = np.array([20, 100, 100]) upper = np.array([30, 255, 255]) ``` 4. 设置摄像头的分辨率 ```python cap.set(cv2.CAP_PROP_FRAME_WIDTH, frameWidth) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, frameHeight) ``` 5. 定义一个函数来测量物体尺寸 ```python def get_object_size(contours): for cnt in contours: area = cv2.contourArea(cnt) if area > 500: cv2.drawContours(frame, cnt, -1, (255, 0, 0), 3) perimeter = cv2.arcLength(cnt, True) approx = cv2.approxPolyDP(cnt, 0.02 * perimeter, True) x, y, w, h = cv2.boundingRect(approx) size = (w, h) cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2) cv2.putText(frame, str(size), (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2) ``` 6. 创建一个死循环,不断从摄像头读取图像并进行处理 ```python while True: # 读取摄像头图像 ret, frame = cap.read() # 缩小图像以提高处理速度 frameSmall = cv2.resize(frame, (int(frameWidth / scale), int(frameHeight / scale))) # 转换颜色空间 hsv = cv2.cvtColor(frameSmall, cv2.COLOR_BGR2HSV) # 使用颜色范围过滤图像并进行膨胀和腐蚀处理 mask = cv2.inRange(hsv, lower, upper) mask = cv2.erode(mask, None, iterations=2) mask = cv2.dilate(mask, None, iterations=2) # 查找轮廓测量物体尺寸 contours, _ = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) get_object_size(contours) # 显示图像 cv2.imshow("Frame", frame) cv2.imshow("Mask", mask) # 按下q键退出循环 if cv2.waitKey(1) & 0xFF == ord('q'): break ``` 7. 释放摄像头并关闭所有窗口 ```python cap.release() cv2.destroyAllWindows() ``` 这个程序可以帮助你实时测量物体尺寸,只需要将物体放在摄像头前面即可。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 24
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

土拨鼠不是老鼠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值