使用 OpenCV python 进行测量时如何提高精度

问题描述

我一直在尝试使用 OpenCV python 中的参考对象(3x5 棋盘格)测量窗格,但我的测量值与实际值相差约 5-10%。有没有办法提高测量的精度?

我目前的方法

  1. 使用不同角度的参考物体图像校准相机
  2. 使用 cv2.undistort() 查找未失真的图像
  3. 使用 findChessboardCorners() 查找参考对象的角
  4. 创建一组顶视点
  5. 使用 findHomography()warpPerspective() 将原始图像转换为俯视图
  6. 选择最有可能是窗玻璃边缘的四个点
  7. 根据 4 个角找到边缘像素
  8. 使用参考对象的角来求出每个正方形的大致长度
  9. 使用边缘像素计算窗玻璃的相对长度
  10. 使用实际长度和参考方块的长度求出比例,并使用该比例求出窗玻璃的实际长度

我在此附上使用的参考对象和图像。任何建议将不胜感激。提前致谢!
window_pane

窗玻璃的原始尺寸为 6x10 英寸。

import numpy as np
import cv2
import imutils
import math
import os
import base64
import json
from sys import argv
import sys
from google.colab.patches import cv2_imshow

def get_refrence_corners(image):
    cornersList = []
    # resized = imutils.resize(image,width=600)
    gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
    ret,corners = cv2.findChessboardCorners(gray,(5,3),None)
    print(ret)
    # If found
    if ret == True:
        criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER,30,0.001)
        corners2 = cv2.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria)
        for x in range(len(corners2)):
            cornersList.append(corners2[x][0])
    return cornersList

def get_corners(img_resized,sensitivity):
    cornersList = []
    imgGrey = cv2.cvtColor(img_resized,cv2.COLOR_BGR2GRAY)
    corners = cv2.goodFeaturesToTrack(imgGrey,sensitivity,0.01,60)
    corners = np.float32(corners)
    for corner in corners:
        x,y = corner.ravel()
        if x.item() > 325 or x.item() < 55 or y.item() > 1515 or y.item() < 1335:
            cornersList.append((x.item(),y.item()))
    return cornersList

def get_dist_two_points(point1,point2):
    distX = abs(point1[0] - point2[0])
    distY = abs(point1[1] - point2[1])
    dist = math.sqrt(distX**2 + distY**2)
    return dist

def get_edges_pixels(chosen,edge_pixels) :
    biggest_sum = chosen[0][0] + chosen[0][1]
    smallest_sum = chosen[0][0] + chosen[0][1]
    smallest_corner = 0
    biggest_corner = 0
    for edge in range(len(chosen)):
        if (chosen[edge][0] + chosen[edge][1]) > biggest_sum:
            biggest_sum = (chosen[edge][0] + chosen[edge][1])
            biggest_corner = edge
        elif (chosen[edge][0] + chosen[edge][1]) < smallest_sum:
            smallest_sum = (chosen[edge][0] + chosen[edge][1])
            smallest_corner = edge
    for corner in range(len(chosen)):
        if corner != smallest_corner and corner != biggest_corner:
            dist = get_dist_two_points(chosen[corner],chosen[smallest_corner])
            edge_pixels.append(dist)
            dist = get_dist_two_points(chosen[corner],chosen[biggest_corner])
            edge_pixels.append(dist)
    return edge_pixels

def get_relative_length(edge_pixels,refLength):
    ref = (refLength[1] + refLength[0]) / 2
    average_x = (edge_pixels[0] + edge_pixels[3]) / 2
    average_y = (edge_pixels[1] + edge_pixels[2]) / 2
    x = (average_x / ref)
    y = (average_y / ref)
    length = [x * 17/32,y * 17/32]
    return length

def get_refrence_length(image):
    gray = cv2.cvtColor(image,None)
    if ret == True:
        avg_horz = 0
        avg_virt = 0
        edges_horz = 0
        edges_virt = 0
        criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER,criteria)
        for x in range (14):
            if ((x + 1) % 5) != 0 :
                avg_virt += get_dist_two_points(corners2[x][0],corners2[x+1][0])
                edges_virt += 1
            # if the point is in the row skip the comparison as there is no points on the left
            if (x + 5) <= 14 :
                avg_horz += get_dist_two_points(corners2[x][0],corners2[x+5][0])
                edges_horz += 1

    return [avg_horz / edges_horz,avg_virt / edges_virt]

imgpoints = np.load('/content/imgpoints.pkl',allow_pickle=True)
objpoints = np.load('/content/objpoints.pkl',allow_pickle=True)

path = '/content/IMG_4854.JPG'
image = cv2.imread(path)

gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)

ret,mtx,dist,rvecs,tvecs = cv2.calibrateCamera(objpoints,imgpoints,gray.shape[::-1],None,None)

img = cv2.imread('/content/IMG_4854.JPG')
h,w = img.shape[:2]
newcameramtx,roi=cv2.getoptimalNewCameraMatrix(mtx,(w,h),1,h))

# undistort
dst = cv2.undistort(img,newcameramtx)

# crop the image
x,y,w,h = roi
dst = dst[y:y+h,x:x+w]
cv2.imwrite('calibresult.png',dst)


finalImage = cv2.imread('/content/calibresult.png')
grayFinal = cv2.cvtColor(finalImage,cv2.COLOR_BGR2GRAY)

reference_corners = get_refrence_corners(finalImage)
reference_corners = np.float32(reference_corners)

sorted_reference_points = np.array(sorted(reference_corners,key = lambda x: x[1]))

top_view_points = np.float32([(200,1380),(245,(290,(335,(380,(200,1425),1470),1470)])

sorted_top_view_points = top_view_points[top_view_points[:,0].argsort()]
print(sorted_top_view_points)

M,mask = cv2.findHomography(sorted_reference_points,top_view_points,cv2.RANSAC,5.0)


dst = cv2.warpPerspective(finalImage,M,(1080,1920),flags = cv2.INTER_CUBIC,borderMode=cv2.BORDER_CONSTANT,borderValue = [0,0])

dst_path = '/content/dst.jpeg'
cv2.imwrite(dst_path,dst)

corners = get_corners(dst,100)
corners = np.float32(corners)

chosen_corners = [(90,560),(700,570),(150,1510),(632,1510)]

chosen_corners = np.int0(chosen_corners)

edge_pixels = []
edge_pixels = get_edges_pixels(chosen_corners,edge_pixels)

reference_length = get_refrence_length(dst)

measurement = get_relative_length(edge_pixels,reference_length)

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)