目录
直线拟合,算出离群点
岭回归拟合直线:
直线拟合,算出离群点
import cv2
import numpy as np
# 输入的点
points = np.array([
[51, 149],
[122, 374],
[225, 376],
[340, 382],
[463, 391],
[535, 298],
[596, 400],
[689, 406],
[821, 407]
], dtype=np.float32)
# 使用 RANSAC 算法拟合直线,并返回内点和离群点
def fit_line_ransac(points, max_iters=1000, threshold=10):
"""
使用 RANSAC 算法拟合直线,并判断离群点
:param points: 输入的点集,形状为 (N, 2)
:param max_iters: 最大迭代次数
:param threshold: 内点阈值
:return: 拟合直线的斜率和截距 (k, b), 内点索引, 离群点索引
"""
best_k, best_b = 0, 0
best_inliers = []
max_inliers = 0
for _ in range(max_iters):
# 随机选择两个点
sample_indices = np.random.choice(len(points), 2, replace=False)
sample = points[sample_indices]
x1, y1 = sample[0]
x2, y2 = sample[1]
# 计算直线的斜率和截距
if x1 == x2: # 垂直线
k = float('inf')
b = x1
else:
k = (y2 - y1) / (x2 - x1)
b = y1 - k * x1
# 计算所有点到直线的距离
distances = np.abs(k * points[:, 0] - points[:, 1] + b) / np.sqrt(k**2 + 1)
# 统计内点
inliers = np.where(distances < threshold)[0]
# 更新最佳模型
if len(inliers) > max_inliers:
max_inliers = len(inliers)
best_k, best_b = k, b
best_inliers = inliers
# 离群点 = 所有点 - 内点
outliers = np.setdiff1d(np.arange(len(points)), best_inliers)
return (best_k, best_b), best_inliers, outliers
# 使用 OpenCV 绘制点、拟合直线和内点/离群点
def draw_points_and_line(image, points, inliers, outliers, k, b, color_line=(255, 0, 0), color_inliers=(0, 255, 0), color_outliers=(0, 0, 255)):
"""
使用 OpenCV 绘制点、拟合直线和内点/离群点
:param image: 背景图像
:param points: 输入的点集
:param inliers: 内点索引
:param outliers: 离群点索引
:param k: 直线斜率
:param b: 直线截距
:param color_line: 直线颜色 (BGR)
:param color_inliers: 内点颜色 (BGR)
:param color_outliers: 离群点颜色 (BGR)
"""
# 绘制内点
for i in inliers:
x, y = points[i]
cv2.circle(image, (int(x), int(y)), 5, color_inliers, -1)
# 绘制离群点
for i in outliers:
x, y = points[i]
cv2.circle(image, (int(x), int(y)), 5, color_outliers, -1)
# 绘制拟合直线
x_min, x_max = int(np.min(points[:, 0])), int(np.max(points[:, 0]))
y_min = int(k * x_min + b)
y_max = int(k * x_max + b)
cv2.line(image, (x_min, y_min), (x_max, y_max), color_line, 2)
# 创建背景图像
image_width = 1000 # 图像宽度
image_height = 600 # 图像高度
background = np.zeros((image_height, image_width, 3), dtype=np.uint8) # 黑色背景
# 使用 RANSAC 算法拟合直线,并判断离群点
(k, b), inliers, outliers = fit_line_ransac(points)
print(f"RANSAC 拟合直线: y = {k:.2f}x + {b:.2f}")
print(f"内点索引: {inliers}")
print(f"离群点索引: {outliers}")
# 绘制点、拟合直线和内点/离群点
draw_points_and_line(background, points, inliers, outliers, k, b)
# 显示图像
cv2.imshow("RANSAC Line Fitting with OpenCV", background)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 保存图像
cv2.imwrite("ransac_line_fitting_opencv.jpg", background)
岭回归拟合直线:
import cv2
import numpy as np
from sklearn.linear_model import Ridge
# 生成带噪声的点
np.random.seed(42)
num_points = 100
x = np.linspace(0, 10, num_points)
y = 2 * x + 1 + np.random.normal(0, 1, num_points) # y = 2x + 1 + 噪声
# 将 x 转换为二维数组(因为 sklearn 需要二维输入)
X = x.reshape(-1, 1)
# 使用岭回归拟合直线
ridge = Ridge(alpha=1.0) # alpha 是正则化强度
ridge.fit(X, y)
# 获取拟合的斜率和截距
slope = ridge.coef_[0]
intercept = ridge.intercept_
# 打印拟合结果
print(f"拟合直线方程: y = {slope:.2f}x + {intercept:.2f}")
# 计算拟合直线的两个端点
x_min, x_max = 0, 10
y_min = slope * x_min + intercept
y_max = slope * x_max + intercept
# 将点缩放到图像尺寸
scale = 40 # 缩放因子
image_width = 640
image_height = 480
# 创建一个空白图像用于可视化
image = np.zeros((image_height, image_width, 3), dtype=np.uint8)
# 绘制点
for xi, yi in zip(x, y):
cv2.circle(image, (int(xi * scale), int(yi * scale)), 3, (0, 255, 0), -1)
# 绘制拟合的直线
pt1 = (int(x_min * scale), int(y_min * scale))
pt2 = (int(x_max * scale), int(y_max * scale))
cv2.line(image, pt1, pt2, (0, 0, 255), 2)
# 显示图像
cv2.imshow("Ridge Regression Line Fit", image)
cv2.waitKey(0)
cv2.destroyAllWindows()