这个是个人感觉自由度最大的,应该也是可以达到的精度上限最高的,也支持图像的旋转,如果筛选直线的方法得当对于线的相交角度也没特殊要求,但是手动计算量也较大;本人实现的取四条直线的方法具有局限性,这里只写思路
cv::Canny
取边界cv.HoughLinesP
拟合直线优势:即使只识别到两条最大不相似直线(例如求十字中心,最长且接近垂直的两条线一定是符合需求的)也可以计算出来一个附近值,偏差大致为线宽/2(假设十字线等宽)
坑处:如果需要低画质高精度,基本达不到,摄像头像素变化严重,边界也会波动,部分直线斜率一直波动
使用OpenCV自带的库整个流程计算较快,较为简单
cv::Canny
取边界(X1+X2)/2
(y1+y2)/2
优点:流程简单、计算速度快
缺点:不支持旋转,只支持横向纵向交叉,如果目标太窄、边界毛糙容易有较大误差
cv.adaptiveThreshold
取边界拟合四线交点取中
优点:支持旋转等
缺点:筛选直线能气死,不过自适应阈值得到的图片进行拟合直线要比直接灰度图提取边界拟合要规整
cv.adaptiveThreshold
(X1+X2)/2
(y1+y2)/2
优点:流程简单、计算速度快
缺点:不支持旋转,只支持横向纵向交叉
from ast import main
import cv2 as cv
import os
import numpy as np
import matplotlib.pyplot as plt
# 获取文件夹下所有文件
def get_file_list(path):
file_list = []
for root, dirs, files in os.walk(path):
for file in files:
file_list.append(os.path.join(root, file))
return file_list
def remove_contours(img,area):
contours, _ = cv.findContours(img, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
n = len(contours) # 轮廓的个数
cv_contours = []
for contour in contours:
area = cv.contourArea(contour)
if area <= area:
cv_contours.append(contour)
else:
continue
cv.fillPoly(img, cv_contours, (0, 0, 0))
def local_adapt_threshold(image, flag = True):
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
if flag:
# 求边界
binary = cv.Canny(gray, 50, 150, apertureSize=3)
else:
# 自适应阈值图片二值化
binary = cv.adaptiveThreshold(
gray, 255, cv.ADAPTIVE_THRESH_MEAN_C, cv.THRESH_BINARY_INV, 11, 5)
# 闭运算
kernel = cv.getStructuringElement(cv.MORPH_RECT, (3, 3))
binary = cv.morphologyEx(binary, cv.MORPH_CLOSE, kernel)
# thinning图片细化
binary = cv.ximgproc.thinning(
binary, thinningType=cv.ximgproc.THINNING_ZHANGSUEN)
# 横向白点像素直方图
histx = cv.reduce(binary, 0, cv.REDUCE_AVG).reshape(-1)
# 纵向白点像素直方图
histy = cv.reduce(binary, 1, cv.REDUCE_AVG).reshape(-1)
# 绘制直方图
# plt.subplot(2, 2, 1)
# plt.plot(histx)
# plt.title("h")
# plt.subplot(2, 2, 2)
# plt.plot(histy)
# plt.title("v")
# plt.show()
# 分别获取数量最大的两列
x_max = np.argmax(histx)
y_max = np.argmax(histy)
# 获取数量第二大的两列
x_second = np.argpartition(histx, -2)[-2]
y_second = np.argpartition(histy, -2)[-2]
print(x_max, y_max, x_second, y_second)
# 求中心点
x_center = int((x_max + x_second) / 2)
y_center = int((y_max + y_second) / 2)
print(x_center, y_center)
# 绘制中心点
cv.circle(image, (x_center, y_center), 5, (0, 0, 255), -1)
cv.circle(binary, (x_center, y_center), 5, (255), -1)
# 重设大小
image = cv.resize(image, (0, 0), fx=0.5, fy=0.5)
binary = cv.resize(binary, (0, 0), fx=0.5, fy=0.5)
cv.imshow("image", image)
cv.imshow("binary", binary)
cv.waitKey(0)
if __name__ == "__main__":
img = cv.imread('D:/TEST/test1.jpg')
# local_adapt_threshold(img, True)
local_adapt_threshold(img, False)
为什么第一个会偏呢?因为它有一条线占了两个像素行,并且像素点数量都很多