【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、参考

相关推荐
高山我梦口香糖1 小时前
[react]searchParams转普通对象
开发语言·前端·javascript
信号处理学渣1 小时前
matlab画图,选择性显示legend标签
开发语言·matlab
红龙创客1 小时前
某狐畅游24校招-C++开发岗笔试(单选题)
开发语言·c++
蓝天星空1 小时前
Python调用open ai接口
人工智能·python
jasmine s1 小时前
Pandas
开发语言·python
郭wes代码1 小时前
Cmd命令大全(万字详细版)
python·算法·小程序
leaf_leaves_leaf2 小时前
win11用一条命令给anaconda环境安装GPU版本pytorch,并检查是否为GPU版本
人工智能·pytorch·python
biomooc2 小时前
R 语言 | 绘图的文字格式(绘制上标、下标、斜体、文字标注等)
开发语言·r语言
夜雨飘零12 小时前
基于Pytorch实现的说话人日志(说话人分离)
人工智能·pytorch·python·声纹识别·说话人分离·说话人日志
骇客野人2 小时前
【JAVA】JAVA接口公共返回体ResponseData封装
java·开发语言