目录
方法一:比例尺法
方法:二:三角法
方法三:相机标定
以下方法均在平面的前提下进行
方法一:比例尺法
在一张纸上绘制一个带刻度的直线,将纸张放在摄像头下,抓取任意两点的像素坐标,计算像素距离pd,再根据刻度读取实际距离ad,根据两者可以求出缩放比例,即地图上的比例尺
scale = ad / pd ,单位:mm/piexl
如图,一格表示1cm,AB=5cm,选择一段10cm的刻度,运行代码得到scale,后面只需要知道两点的坐标,即可通过公式求得得到实际尺寸
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2022/3/10 12:42
# @Author : @linlianqin
# @Site :
# @File : 计算像素尺寸和实际尺寸对应关系(勾股定理).py
# @Software: PyCharm
# @description:
import cv2
import cv2
import numpy as np
a = []
b = []
# 鼠标响应事件
def on_EVENT_LBUTTONDOWN(event, x, y, flags, param):
if event == cv2.EVENT_LBUTTONDOWN:
if len(a) < 4:
xy = "%d,%d" % (x, y)
a.append(x)
b.append(y)
cv2.circle(img, (x, y), 1, (0, 0, 255), thickness=-1)
cv2.putText(img, xy, (x, y), cv2.FONT_HERSHEY_PLAIN,
5.0, (0, 0, 255), thickness=5)
cv2.imshow("image", img)
else:
cv2.destroyAllWindows()
# 从图像中选择点
def getPoints(img):
cv2.namedWindow("image", cv2.WINDOW_NORMAL)
cv2.setMouseCallback("image", on_EVENT_LBUTTONDOWN)
cv2.imshow("image", img)
cv2.waitKey(0)
return [(a[0],b[0]),(a[1],b[1]),(a[2],b[2]),(a[3],b[3])]
# 计算像素尺寸到实际尺寸的缩放关系
def calculateDelta(p1,p2,trueDist):
'''
:param p1: 图像点1像素坐标
:param p2: 图像点2像素坐标
:param trueDist: p1和p2之间距离,单位mm
:return:
'''
x1,y1 = p1
x2,y2 = p2
print('p1,p2:',p1,p2)
piexlDist = np.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))
print("piexlDist:",piexlDist)
scale = trueDist/piexlDist
print("scale:",scale)
return scale
# 求两点的实际距离
def calculateTwoPDist(p1,p2,scale):
x1,y1 = p1
x2,y2 = p2
piexlDist = np.sqrt((x1-x2)**2+(y1-y2)**2)
trueDist = scale*piexlDist
return trueDist
if __name__ == '__main__':
# 图片路径
img = cv2.imread('Pic_2022_03_10_155053_1.bmp')
ps = getPoints(img)
p1,p2,p3,p4 = ps[:4]
print(p1,p2,p3,p4)
# 计算缩放比例
scale = calculateDelta(p1,p2,30)
# 验证
DD = calculateTwoPDist(p3,p4,scale)
print(DD)
'''
(1736, 971) (1327, 928) (405, 321) (1939, 1656)
p1,p2: (1736, 971) (1327, 928)
piexlDist: 411.254179310071
scale: 0.024315862313609115
49.447853010286586
'''
'''
(1736, 971) (1327, 928) (405, 321) (1939, 1656)
p1,p2: (1736, 971) (1327, 928)
piexlDist: 411.254179310071
scale: 0.024315862313609115
49.447853010286586
'''
可见误差在1mm以内
方法:二:三角法
这个方法和法一类似,只是这里考虑到两个方向的缩放比例不一致,所以通过两队点来解方程,得到横向和纵向两个方向的缩放比例dx,dy,这样既可将像素尺寸换算成横向和纵向实际尺寸,然后根据勾股定理得到实际尺寸
?
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2022/3/10 12:42
# @Author : @linlianqin
# @Site :
# @File : 计算像素尺寸和实际尺寸对应关系(勾股定理).py
# @Software: PyCharm
# @description:
import cv2
import cv2
import numpy as np
a = []
b = []
# 鼠标响应事件
def on_EVENT_LBUTTONDOWN(event, x, y, flags, param):
if event == cv2.EVENT_LBUTTONDOWN:
if len(a) < 6:
xy = "%d,%d" % (x, y)
a.append(x)
b.append(y)
cv2.circle(img, (x, y), 1, (0, 0, 255), thickness=-1)
cv2.putText(img, xy, (x, y), cv2.FONT_HERSHEY_PLAIN,
5.0, (0, 0, 255), thickness=5)
cv2.imshow("image", img)
else:
cv2.destroyAllWindows()
# 从图像中选择三个点
def getPoints(img):
cv2.namedWindow("image", cv2.WINDOW_NORMAL)
cv2.setMouseCallback("image", on_EVENT_LBUTTONDOWN)
cv2.imshow("image", img)
cv2.waitKey(0)
return [(a[0],b[0]),(a[1],b[1]),(a[2],b[2]),(a[3],b[3]),(a[4],b[4]),(a[5],b[5])]
# 计算像素尺寸到实际尺寸的缩放关系
def calculateDelta(p1,p2,p3,p4,trueDist1,trueDist2,):
'''
:param p1: 图像点1像素坐标
:param p2: 图像点2像素坐标
:param p3: 图像点3像素坐标
:param trueDist1: p1和p2之间距离,单位mm
:param trueDist2: p3和p4之间距离,单位mm
:return:
'''
x1,y1 = p1
x2,y2 = p2
x3,y3 = p3
a = x1 - x2
b = y1 - y2
c = x2 - x3
d = y2 - y3
print((trueDist1*trueDist1*d*d-trueDist2*trueDist2*b*b)/(d*d*a*a-b*b*c*c))
dx = np.sqrt(abs((trueDist1*trueDist1*d*d-trueDist2*trueDist2*b*b)/(d*d*a*a-b*b*c*c)))
print((trueDist2*trueDist2-(c*c*dx*dx))/(d*d))
dy = np.sqrt(abs((trueDist2*trueDist2*a*a-(c*c*trueDist1*trueDist1))/(a*a*d*d-c*c*b*b)))
return dx,dy
# 求两点的实际距离
def calculateTwoPDist(p1,p2,dx,dy):
x1,y1 = p1
x2,y2 = p2
x = (x1-x2)*dx
y = (y1-y2)*dy
D = np.sqrt(x*x + y*y)
return D
if __name__ == '__main__':
# 图片路径
img = cv2.imread('Pic_2022_03_10_155053_1.bmp')
ps = getPoints(img)
p1,p2,p3,p4 = ps[:4]
print(p1,p2,p3,p4)
# 计算缩放比例
dx,dy = calculateDelta(p1,p2,p3,p4,10,50)
print(dx,dy)
# 验证
p5,p6 = ps[4:]
print(p5,p6)
D = calculateTwoPDist(p1,p2,dx,dy)
print(D)
D = calculateTwoPDist(p2,p3,dx,dy)
print(D)
D = calculateTwoPDist(p5,p6,dx,dy)
print(D)
''' (2141, 1005) (1732, 962) (1936, 1670) (407, 327) 0.0005431680406709232 0.004942296911047749 0.023305965774258815 0.07030147161367072 (1327, 931) (151, 834) 10.0 50.0 28.243414026122252 '''
检测结果发现,实际尺寸为30,但是得到的是28mm,误差较大,可能是因为横向和纵向分开计算误差叠加了
方法三:相机标定
通过张正友标定获得相机内参:
张正友Python标定原理和方法见文章:https://blog.csdn.net/betrapped/article/details/89247561
?得到相机内参后,根据文章《原创?【机器视觉】——焦距计算&物体实际尺寸计算》来进行计算
|