【python】OpenCV—findContours(4.5)

文章目录

1、功能描述

输入图片,计算出图片中的目标到相机间的距离

2、原理分析

用最简单的三角形相似性

已知参数,物体的宽度 W W W,物体到相机的距离 D D D,物体的宽在画面中的像素数 P P P,可以求出相机的焦距 F F F

F = P × D W F = \frac{P \times D}{W} F=WP×D

后续移动物体到不同的距离, W W W 已知, F F F 已知,通过 P P P 即可计算物体到相机间的距离 D D D

D = F × W P D = \frac{F \times W}{ P} D=PF×W

该方法缺点,物体需正对镜头,不然角度产生的物体形变会影响测量精度

可以利用标定求出相机参数,这样应用的鲁棒性会更高

3、代码实现

python 复制代码
# import the necessary packages
from imutils import paths
import numpy as np
import imutils
import cv2

# initialize the known distance from the camera to the object, which
# in this case is 24 inches
KNOWN_DISTANCE = 24.0

# initialize the known object width, which in this case, the piece of
# paper is 12 inches wide
KNOWN_WIDTH = 11.0

# load the furst image that contains an object that is KNOWN TO BE 2 feet
# from our camera, then find the paper marker in the image, and initialize
# the focal length
image = cv2.imread("images/2ft.png")
marker = find_marker(image)
focalLength = (marker[1][0] * KNOWN_DISTANCE) / KNOWN_WIDTH

导入必要的库函数,配置好 KNOWN_DISTANCE D,KNOWN_WIDTH W,读入图片,通过找到画面中的物体,求出来 P,计算 focalLength F

计算 P 是通过 find_marker 函数实现的

python 复制代码
def find_marker(image):
	# convert the image to grayscale, blur it, and detect edges
	gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
	# cv2.imwrite("gray.jpg", gray)

	gray = cv2.GaussianBlur(gray, (5, 5), 0)
	# cv2.imwrite("gray-blur.jpg", gray)

	edged = cv2.Canny(gray, 35, 125)
	# cv2.imwrite("edged.jpg", edged)

	# find the contours in the edged image and keep the largest one;
	# we'll assume that this is our piece of paper in the image
	cnts, _ = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
	# cnts = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
	# cnts = imutils.grab_contours(cnts)

	# img_copy = image.copy()
	# cv2.drawContours(img_copy, cnts, -1, (0,255,0))
	# cv2.imwrite("draw_edged.jpg", img_copy)

	c = max(cnts, key=cv2.contourArea)

	# compute the bounding box of the of the paper region and return it
	return cv2.minAreaRect(c)

输入图片,灰度化,高斯模糊,Canny 算子进行边缘检测,findContours 找出潜在轮廓,求面积最大的轮廓max(cnts, key=cv2.contourArea),求最大面积轮廓的最小外接矩阵

为什么要通过求最大面积轮廓的最小外接矩阵来定位到画面中的物品呢?这里比较灵活,可以尝试其他任何方法,核心目的是找出画面中物体的宽,只是正好样例图片可以

现在开始测试其他距离的效果

python 复制代码
# loop over the images
for imagePath in sorted(paths.list_images("images")):
	# load the image, find the marker in the image, then compute the
	# distance to the marker from the camera
	image = cv2.imread(imagePath)
	marker = find_marker(image)
	inches = distance_to_camera(KNOWN_WIDTH, focalLength, marker[1][0])

	# draw a bounding box around the image and display it
	box = cv2.BoxPoints(marker) if imutils.is_cv2() else cv2.boxPoints(marker)
	box = np.intp(box)
	cv2.drawContours(image, [box], -1, (0, 255, 0), 2)
	cv2.putText(image, "%.2fft" % (inches / 12),
		(image.shape[1] - 200, image.shape[0] - 20), cv2.FONT_HERSHEY_SIMPLEX,
		2.0, (0, 255, 0), 3)
	cv2.imshow("image", image)
	cv2.waitKey(0)

遍历图片,求最大面积轮廓的最小外接矩阵,调用 distance_to_camera,求实际距离

绘制最大轮廓的最小外接矩阵,注释上距离

这里 12 表示下面的转换关系,foot 和 inches

python 复制代码
def distance_to_camera(knownWidth, focalLength, perWidth):
	# compute and return the distance from the maker to the camera
	return (knownWidth * focalLength) / perWidth

根据 W、F 和 P 来求 D

4、效果展示

输入图片

灰度化后的结果

高斯模糊

Canny 算子计算边缘

找出画面中所有的轮廓

找出轮廓,获取到 P,结合已知的 W 和 D,求出 F

换一个距离,测试一下算法,计算得到 P,根据已知的 W 和 F,求出 D

再换一个距离,测试一下算法,计算得到 P,根据已知的 W 和 F,求出 D

5、完整代码

python 复制代码
# USAGE
# python distance_to_camera.py

# import the necessary packages
from imutils import paths
import numpy as np
import imutils
import cv2

def find_marker(image):
	# convert the image to grayscale, blur it, and detect edges
	gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
	# cv2.imwrite("gray.jpg", gray)

	gray = cv2.GaussianBlur(gray, (5, 5), 0)
	# cv2.imwrite("gray-blur.jpg", gray)

	edged = cv2.Canny(gray, 35, 125)
	# cv2.imwrite("edged.jpg", edged)

	# find the contours in the edged image and keep the largest one;
	# we'll assume that this is our piece of paper in the image
	cnts, _ = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
	# cnts = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
	# cnts = imutils.grab_contours(cnts)

	# img_copy = image.copy()
	# cv2.drawContours(img_copy, cnts, -1, (0,255,0))
	# cv2.imwrite("draw_edged.jpg", img_copy)

	c = max(cnts, key=cv2.contourArea)

	# compute the bounding box of the of the paper region and return it
	return cv2.minAreaRect(c)

def distance_to_camera(knownWidth, focalLength, perWidth):
	# compute and return the distance from the maker to the camera
	return (knownWidth * focalLength) / perWidth

# initialize the known distance from the camera to the object, which
# in this case is 24 inches
KNOWN_DISTANCE = 24.0

# initialize the known object width, which in this case, the piece of
# paper is 12 inches wide
KNOWN_WIDTH = 11.0

# load the furst image that contains an object that is KNOWN TO BE 2 feet
# from our camera, then find the paper marker in the image, and initialize
# the focal length
image = cv2.imread("images/2ft.png")
marker = find_marker(image)
focalLength = (marker[1][0] * KNOWN_DISTANCE) / KNOWN_WIDTH

# loop over the images
for imagePath in sorted(paths.list_images("images")):
	# load the image, find the marker in the image, then compute the
	# distance to the marker from the camera
	image = cv2.imread(imagePath)
	marker = find_marker(image)
	inches = distance_to_camera(KNOWN_WIDTH, focalLength, marker[1][0])

	# draw a bounding box around the image and display it
	box = cv2.BoxPoints(marker) if imutils.is_cv2() else cv2.boxPoints(marker)
	box = np.intp(box)
	cv2.drawContours(image, [box], -1, (0, 255, 0), 2)
	cv2.putText(image, "%.2fft" % (inches / 12),
		(image.shape[1] - 200, image.shape[0] - 20), cv2.FONT_HERSHEY_SIMPLEX,
		2.0, (0, 255, 0), 3)
	cv2.imshow("image", image)
	cv2.waitKey(0)

6、参考

相关推荐
Hylan_J2 小时前
【VSCode】MicroPython环境配置
ide·vscode·python·编辑器
软件黑马王子2 小时前
C#初级教程(4)——流程控制:从基础到实践
开发语言·c#
莫忘初心丶2 小时前
在 Ubuntu 22 上使用 Gunicorn 启动 Flask 应用程序
python·ubuntu·flask·gunicorn
闲猫2 小时前
go orm GORM
开发语言·后端·golang
李白同学4 小时前
【C语言】结构体内存对齐问题
c语言·开发语言
黑子哥呢?5 小时前
安装Bash completion解决tab不能补全问题
开发语言·bash
失败尽常态5235 小时前
用Python实现Excel数据同步到飞书文档
python·excel·飞书
2501_904447745 小时前
OPPO发布新型折叠屏手机 起售价8999
python·智能手机·django·virtualenv·pygame
青龙小码农5 小时前
yum报错:bash: /usr/bin/yum: /usr/bin/python: 坏的解释器:没有那个文件或目录
开发语言·python·bash·liunx
大数据追光猿5 小时前
Python应用算法之贪心算法理解和实践
大数据·开发语言·人工智能·python·深度学习·算法·贪心算法