先用灰度平均值二值化,然后在图片上纵向找出每一行的分割点使图片两边的差异最大,然后把它们连起来成为一条直线
import cv2
import numpy as np
# 读取图像并转换为灰度图
image = cv2.imread('1.jpg', cv2.IMREAD_GRAYSCALE)
# 计算灰度图的平均值
mean_gray_value = np.mean(image)
# 使用平均灰度值作为阈值进行二值化
_, binary = cv2.threshold(image, mean_gray_value, 255, cv2.THRESH_BINARY)
# 获取图像的高度和宽度
height, width = binary.shape
# 存储分割点的坐标
split_points = []
# 定义一个函数来计算给定分割点的左右侧差异
def calculate_variance_difference(row, x):
left_side = row[:x]
right_side = row[x:]
if len(left_side) == 0 or len(right_side) == 0:
return 0
variance_left = np.count_nonzero(left_side)/len(left_side)
variance_right = np.count_nonzero(right_side)/len(right_side)
return abs(variance_left - variance_right)
# 遍历每一行,寻找最佳分割点
for y in range(height):
row = binary[y, :]
best_x = None
max_diff = 0
for x in range(width//2-100, width//2+100): ### 根据实际情况调整范围!!
diff = calculate_variance_difference(row, x)
if diff > max_diff:
max_diff = diff
best_x = x
if best_x is not None:
split_points.append((best_x, y))
# 将分割点转换为NumPy数组
split_points_np = np.array(split_points)
# 拟合直线
if len(split_points_np) >= 2: # 至少需要两个点才能拟合一条直线
[vx, vy, x0, y0] = cv2.fitLine(split_points_np, cv2.DIST_L2, 0, 0.01, 0.01)
lefty = int((-x0*vy/vx) + y0)
righty = int(((width-x0)*vy/vx) + y0)
else:
print("无法拟合直线,因为分割点不足")
exit()
# 绘制直线
color_image = cv2.cvtColor(binary, cv2.COLOR_GRAY2BGR) # 转换为彩色以便绘制不同颜色的线
cv2.line(color_image, (0, lefty), (width-1, righty), (0, 255, 0), 2)
# 显示结果
cv2.imshow('Image with Split Line', color_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 如果需要保存分割后的图像
cv2.imwrite('image_with_split_line.jpg', color_image)
好的,谢谢,虽然拟合的精度在图像的某些地方效果不是那么好
@仟树: 这个方法找到的点,一般都在分割线的一边,因为分割线是黑色的有宽度,分割线会被划分到灰度较大的那一边,把点往灰度较大的那边偏移一点,然后再拟合效果会好一些.
@www378660084: 好的,谢谢
灰度转换、二值化、边界获取(opencv有边界获取函数)
二值化噪声太多,滤波也没用
如果总是这种图像,直接一个像素从左到右遍历取个阈值就出来了
是直接设定阈值二值化的意思吗,这样好像也不行