Python中如何使用OpenCV去除图片底部的横线?

20180114113101

低端有一条很小的蓝线请问如何去掉?

这个是原图请问如何去出掉低端的横线。


Python中如何使用OpenCV去除图片底部的横线?
12 回复

直接用 PIL 不行吗


import cv2
import numpy as np

def remove_bottom_lines(image_path, output_path, line_thickness=2, margin=10):
    """
    去除图片底部的横线
    
    参数:
        image_path: 输入图片路径
        output_path: 输出图片路径
        line_thickness: 检测线条的厚度阈值
        margin: 从底部开始检测的区域高度
    """
    # 读取图片
    img = cv2.imread(image_path)
    if img is None:
        raise ValueError("无法读取图片,请检查路径")
    
    # 转换为灰度图
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    # 获取图片尺寸
    height, width = gray.shape
    
    # 提取底部区域(最后margin行)
    bottom_region = gray[height - margin:, :]
    
    # 使用Canny边缘检测
    edges = cv2.Canny(bottom_region, 50, 150, apertureSize=3)
    
    # 使用霍夫变换检测直线
    lines = cv2.HoughLinesP(edges, 1, np.pi/180, threshold=50,
                           minLineLength=width*0.3, maxLineGap=10)
    
    # 如果没有检测到直线,直接保存原图
    if lines is None:
        cv2.imwrite(output_path, img)
        print("未检测到横线")
        return img
    
    # 创建掩码
    mask = np.ones_like(img) * 255
    
    # 标记检测到的横线区域
    for line in lines:
        x1, y1, x2, y2 = line[0]
        # 将局部坐标转换为全局坐标
        y1 += height - margin
        y2 += height - margin
        
        # 计算线条角度(只处理接近水平的线)
        angle = np.abs(np.arctan2(y2 - y1, x2 - x1) * 180 / np.pi)
        if angle < 10 or angle > 170:  # 接近水平线
            # 扩展线条区域
            y_center = (y1 + y2) // 2
            top = max(0, y_center - line_thickness)
            bottom = min(height, y_center + line_thickness)
            mask[top:bottom, :] = 0
    
    # 使用inpainting修复被标记的区域
    mask_gray = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
    result = cv2.inpaint(img, mask_gray, inpaintRadius=3, flags=cv2.INPAINT_TELEA)
    
    # 保存结果
    cv2.imwrite(output_path, result)
    return result

# 使用示例
if __name__ == "__main__":
    input_img = "input.jpg"  # 你的输入图片
    output_img = "output.jpg"  # 输出图片
    
    try:
        result = remove_bottom_lines(input_img, output_img, margin=20)
        print(f"处理完成,结果已保存到 {output_img}")
    except Exception as e:
        print(f"处理失败: {e}")

核心思路:

  1. 用Canny检测底部边缘
  2. 用霍夫变换找横线
  3. 创建掩码标记线条区域
  4. 用inpainting智能填充

参数调整建议:

  • margin:根据横线位置调整检测区域高度
  • line_thickness:根据线条粗细调整
  • minLineLength:调整检测线条的最小长度

一句话建议: 先用小margin值试效果,再逐步调整参数。

height 高于某个定值,如果 RGB 颜色不是白色,填充这个像素为白色,收工

数数那是多少像素,然后 rect,把上面的部分截取出来,或者直接把下面的全部写成相同像素

如果图片只有这条横线,而且一定是最底端,图片都这么大,那么你直接把最底端的像素的颜色都设置成背景颜色就好了

如果这条横线还会在其他地方,你可以用 HoughLineP (设置 threshold 和 minLineLength 俩参数),找最长的那条直线,因为斜率一定是 0,所以 HoughLineP 对应的第一个点的纵坐标就是直线的那个位置

是这样的, 主要有多个图片, 这个只是一个个例, 而且高度多少不一定, 可能多点, 可能少点, 三楼的方法 ok 但是感觉代码还是写的有点死, ok 我先试下谢谢。

5 楼哈夫变换线识别可解,简单点的话就遍历一遍就行了

opencv 运行下面代码,可以看到如图
http://image.xujialiang.net/[email protected]
很容易看出从第一行开始切割。。



import cv2
import numpy as np
import matplotlib.pyplot as plt


ori_img = cv2.imread(’./TestData/’ + ‘111.png’)


im_gray = cv2.cvtColor(ori_img, cv2.COLOR_BGR2GRAY)
im_at_mean = cv2.adaptiveThreshold(im_gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 5, 10)
cv2.imshow(‘im_at_mean’ , im_at_mean)

im_at_mean_inv = cv2.bitwise_not(im_at_mean)
horizontal_sum = np.sum(im_at_mean_inv, axis=1)
plt.plot(horizontal_sum, range(horizontal_sum.shape[0]))
plt.gca().invert_yaxis()
plt.show()

cv2.waitKey(0)
cv2.destroyAllWindows()

上面打错一个字。。。很容易看出从第几行开始切割。。

可以统计每行的 RGB 色彩的数量,如果某一行同一颜色的数据和列数差不多(可以设置个阈值),就可以把这行看做是一条横线,直接切掉或者修改这行颜色即可。

不用 opencv 也行的。
读取一下像素值。大于多少高度(避免把字给处理了),颜色值低于 255(阈值自己设置)的都置位 255

回到顶部