首页 > 技术文章 > 基于opencv + python的激光线交点坐标提取

sophomores 2021-11-20 18:47 原文

环境:

Pycharm

python3.9

opencv4.5.4

此文章只描述技术思路,不讲解相关原理

问题描述

从如下图像中提取激光交点的坐标:

解决

​ 我们要提取的是激光线交点的坐标,首先要找到激光线,通过直线的方程即可得到激光线的交点。

提取直线之前的预处理

  1. 根据激光线的颜色来提取激光线,激光线都是单色的,可以从RGB或者HSV模型中提取出单一颜色(一般来说,是在HSV模型中提取),即可得到只含有中心线的图片, 这种方法每次都需要调整要查找的颜色,颜色范围选取的好坏直接决定了处理效果的好坏(这种做法,我没有做出来)
  2. 通过传统的,滤波、二值化、腐蚀、膨胀操作,来获得较为干净的图片。这种做法可以处理第一章图像,但,在第二张图像转换为灰度图后,由于文字的灰度和激光线的灰度差不多,在二值化时会无法消除文字的影响,进而后续的hough变换中会影响直线的识别,效果不是很好
  3. 使用Canny边缘检测作为二值化的方法,需要调整的参数少,二值化的效果也比较好,但仍然无法消除文字对图像的影响

以上是寻找直线之前的预处理,在预处理中,还是没有克服文字对激光线的影响,在文字影响小的情况下,使用Canny检测可以有效的获得二值化的图像,对于文字对识别影响较大的图片,需要对文字另做处理

文字消除

对图二做边缘检测后,得到如下图像

可以看到文字会对直线的识别造成影响,分析文字和激光线,文字是弯曲的,激光线大致只有两个方向,沿x轴方向或者沿y轴方向,有倾斜,但没有弯曲,这时可以考虑使用Sobel算子对图像进行处理,但实际操作中,Sobel也会提取文字的一部分,使文字产生缺失,后续的膨胀效果不好。

对文字的处理,最后是在滤波中处理的,使用高斯滤波,选取较大的核即将直线滤除掉得到只有文字的图片

通过对只含有文字的图片进行膨胀操作(注意:opencv中膨胀操作默认是对黑色部分进行膨胀,这里我们希望对白色部分进行膨胀,所以使用的是腐蚀的函数),得到文字区域

得到腐蚀后的图片后我们将两长图片进行比较,在原图像中, 将文字区域的像素全部设置为0(黑色)即可,消除文字的影响

提取直线

一般采用Hough变换(霍夫变换)来提取直线

提取交点坐标

这里用两种提取交点坐标的方法

  1. 通过直线方程获得,检测到的直线可能会有多根,可以将同一方向上的直线进行合并,最后只剩下两个方向上的两条直线计算交点

  2. 通过角点检测来获得坐标,在一张空白的图像上,根据直线方程获得只含有直线的图像,然后检测图像的角点,选取前4个角点坐标,进行平均,即可得到中心点坐标

通过四个角点(红色),来逼近真正的交点(绿色)

相关代码

import cv2.cv2 as cv
import numpy as np


'''
    图片2的文字太清晰了,所以先提取文字,然后多次膨胀,找到文字所在的区域,在Canny边缘检测得到的图像上
    将文字所在区域全置为0(黑色), 这样就有效的消除了文字对图像的影响

'''


def hough2les(rho, theta, w):
    a = np.cos(theta)
    b = np.sin(theta)
    x0 = a * rho
    y0 = b * rho
    x1 = int(x0 + w * (-b))
    y1 = int(y0 + w * a)
    x2 = int(x0 - w * (-b))
    y2 = int(y0 - w * a)

    k = float(y2 - y1) / float(x2 - x1)
    b = -1*x1*k + y1
    return k, b



src = cv.imread('./Photo/5.jpg', cv.IMREAD_COLOR)
high, width, channel = src.shape
hs_img = cv.cvtColor(src, cv.COLOR_RGB2GRAY)
# cv.imshow('hs', hs_img)
# cv.waitKey(0)

# 高斯滤波
Gaus_img = cv.GaussianBlur(hs_img, (7, 7), 1.5)
# cv.imshow('gauss', hs_img)
# cv.waitKey(0)

# Canny边缘检测
mask_img = cv.Canny(Gaus_img, 130, 142)
cv.imshow('edge', mask_img)
cv.waitKey(0)

elememt_1 = cv.getStructuringElement(cv.MORPH_RECT, (3, 3))

dilation_img = cv.dilate(mask_img, elememt_1, iterations=10)

cv.imshow('di_img', dilation_img)
cv.waitKey(0)

edge_img = cv.Canny(hs_img, 130, 140)
cv.imshow('edge_img', edge_img)
cv.waitKey(0)


for i in range(high):
    for j in range(width):
        if dilation_img[i][j] == 255:
            edge_img[i][j] = 0

cv.imshow('edge_1_img', edge_img)
cv.waitKey(0)

# 霍夫变换
# p 的间隔为0.45 角度间隔为 1度, 长度大于100才被认为是直线
lines = cv.HoughLines(edge_img, 0.45, np.pi / 180, 100)
# print(lines)

show_img = np.zeros((high, width), np.uint8)

# result_line_array = []
for i in range(len(lines)):
    for rho, theta in lines[i]:
        a = np.cos(theta)
        b = np.sin(theta)
        x0 = a * rho
        y0 = b * rho
        x1 = int(x0 + width * (-b))
        y1 = int(y0 + width * a)
        x2 = int(x0 - width * (-b))
        y2 = int(y0 - width * a)

        cv.line(show_img, (x1, y1), (x2, y2), (255, 255, 255), 1)

# 角点检测
# 检测四个点,0.01是品质因数0.1-0.01之间, 10是两个点之间的最小距离
corners = cv.goodFeaturesToTrack(show_img, 4, 0.01, 1)

x_value = 0.0
y_value = 0.0
for i in corners:
    x, y = i.ravel()
    x_value += x
    y_value += y
    # print('交点:{},{}\n'.format(x, y))

x_value /= len(corners)
y_value /= len(corners)
cv.circle(src, (int(x_value), int(y_value)), 3, 255, -1)
print('交点:{},{}\n'.format(x_value, y_value))
cv.imshow('result', src)
cv.waitKey(0)

推荐阅读