用Python实现给图片去黑边

这篇具有很好参考价值的文章主要介绍了用Python实现给图片去黑边。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

图片去黑边(只考虑了去水平方向上的黑边)的核心算法是要找到图片顶部或顶部的黑边位置,即两个纵坐标值, 主要用到了canny边缘计算、
houghlines直线检测、easyocr识别等算法。

给图片去黑边的实现逻辑为:

  1. 先进行canny边缘计算,再进行houghlines直线检测,取出图片的水平边缘 如果没有找到水平边缘,那么不做处理

  2. 对目标水平边缘进行过滤和分类
    过滤逻辑是: 一侧为黑色,另一侧非黑色
    分类逻辑是:
    上边是黑色,下边是非黑色的,且位于图片水平中线以上,作为候选上边缘;
    上边是非黑色,下边是黑色的,,且位于图片水平中线以下,作为候选下边缘

  3. 对候选的上下边缘从外向内逐一校验,校验标准是边缘之外不应存在文字(因为图片上的文字对于图片也是有意义的) 也不应存在高度超过一定阈值的元素, 从而得出符合条件且最靠内侧的上下边缘
    如果找不到符合条件的上边缘,那么上边缘就是0
    如果找不到符合条件的下边缘,那么下边缘就是图片高度-1

  4. 根据找出的上线边缘对原图进行裁剪文章来源地址https://www.toymoban.com/news/detail-800207.html

import cv2
import numpy as np
import easyocr


def isPixelBlack(pixel):
    return pixel[0] <= 10 and pixel[1] <= 10 and pixel[2] <= 10


def checkLineIsBlack(img, width, y):
    midX = int((width - 1) / 2)
    pixel = img[y, midX]
    if not isPixelBlack(pixel):
        return False

    for x in range(1, midX + 1):
        if midX - x >= 0:
            leftPixel = img[y, midX - x]
            if not isPixelBlack(leftPixel):
                return False

        if midX + x < width:
            rightPixel = img[y, midX + x]
            if not isPixelBlack(rightPixel):
                return False

    return True


def computeBlackPixelNum(img, fromY, toY, x):
    totalNum = 0
    for y in range(fromY, toY):
        curPixel = img[y, x]
        if isPixelBlack(curPixel):
            totalNum += 1
    return totalNum


# 对于接近顶部或底部的边缘忽略;对于中线附近的边缘也忽略;
def isLevelLineNeedIgnore(height, y):
    if y <= 50 or height - 1 - y <= 50:
        return True

    # 判断y是否介于3/8 到 5/8 的高度之间
    midZoneStart = int(0.4 * height)
    midZoneEnd = int(0.6 * height)

    if y >= midZoneStart and y <= midZoneEnd:
        return True

    return False


# 将宽度的1/6视作最小线段长度
def getMinLineLength(width):
    return int(width / 10)


def computeValidFlag(valid_flag_list, left, right):
    sum = 0
    for index in range(left, right):
        if valid_flag_list[index] > 0:
            sum += 1
    if sum <= 5:
        return 0
    return sum


# 计算水平线的边缘类型: 0=无效   1=潜在的上边缘   2=潜在的下边缘  3 潜在的边缘
def checkEdgeType(valid_flag_list, y, height, init):
    midY = int(height / 2)

    aboveFlag = computeValidFlag(valid_flag_list, max(0, y - 10 - init), y - 10)
    belowFlag = computeValidFlag(valid_flag_list, y + 10, min(y + 10 + init, height - 1))

    if aboveFlag > 0 and belowFlag > 0:
        return 0
    elif aboveFlag > 0 and belowFlag == 0 and y > midY:
        return 2
    elif aboveFlag == 0 and belowFlag > 0 and y < midY:
        return 1
    elif aboveFlag == 0 and belowFlag == 0:
        return 3
    return 0


# 挑选合适的上边缘
def pickOutFinalTopY(img, height, width, valid_topY_array, valid_flag_list, reader):
    bestTopY = 0

    matchedTopY = []
    otherTopY = []
    for currentY in valid_topY_array:
        validFlagNum = computeValidFlag(valid_flag_list, 0, currentY - 2)
        if validFlagNum <= 20:
            matchedTopY.append(currentY)
        else:
            otherTopY.append(currentY)

    if len(otherTopY) == 0:
        return matchedTopY[0]
    else:
        matchedTopY.sort()
        if len(matchedTopY) > 0:
            bestTopY = matchedTopY[len(matchedTopY) - 1]
        # 将topY列表升序排列, 逐一验证是否符合条件
        valid_topY_array.sort()
        midX = int(width / 2)
        for candidateY in valid_topY_array:
            if candidateY < bestTopY:
                continue

            sumFlag = computeValidFlag(valid_flag_list, 0, candidateY)
            if sumFlag > 100:
                break

            sumBlack = computeBlackPixelNum(img, 0, candidateY, midX)
            if sumBlack > 100:
                break

            # ocr读取 (0,candidateY) 范围内的子图, 判断是否包含有文字
            # 如果包含了文字,那么就不符合条件
            roi = img[0:candidateY, 0:width]
            result = reader.readtext(roi)
            if len(result) > 0:
                break

            bestTopY = candidateY

    return bestTopY


def pickOutFinalEndY(img, height, width, valid_endY_array, valid_flag_list, reader):
    bestEndY = height - 1

    matchedEndY = []
    otherEndY = []
    for currentY in valid_endY_array:
        validFlagNum = computeValidFlag(valid_flag_list, currentY + 2, height)
        if validFlagNum <= 20:
            matchedEndY.append(currentY)
        else:
            otherEndY.append(currentY)

    if len(otherEndY) == 0:
        return matchedEndY[0]
    else:
        matchedEndY.sort(reverse=True)
        if len(matchedEndY) > 0:
            bestEndY = matchedEndY[0]

        # 将endY列表降序排列, 逐一验证是否符合条件
        valid_endY_array.sort(reverse=True)
        midX = int(width / 2)
        for candidateY in valid_endY_array:
            if candidateY > bestEndY:
                continue

            sum = computeValidFlag(valid_flag_list, candidateY, height)
            if sum > 100:
                break

            sumBlack = computeBlackPixelNum(img, candidateY, height, midX)
            if sumBlack > 100:
                break

            # ocr读取 (candidateY,height) 范围内的子图, 判断是否包含有文字
            # 如果包含了文字,那么就不符合条件
            roi = img[candidateY:height, 0:width]
            result = reader.readtext(roi)
            if len(result) > 0:
                break

            bestEndY = candidateY

    return bestEndY


def computeTopAndEnd(img, height, width, valid_flag_list, level_lines, reader):
    # 1.过滤出有效的边缘
    valid_topY_array = []
    valid_endY_array = []

    midY = int(height / 2)
    for level_line in level_lines:
        x1, y, x2, y2 = level_line[0]

        # 临时划线
        # cv2.line(img, (0, y), (width - 1, y), (0, 0, 255), 1)

        # 先判断是否是有效的边缘,如果是有效的边缘, 再放入候选集合中
        edgeType = checkEdgeType(valid_flag_list, y, height, 50)
        if edgeType == 0:
            continue
        elif edgeType == 1:
            valid_topY_array.append(y)
        elif edgeType == 2:
            valid_endY_array.append(y)
        elif edgeType == 3:
            if y > midY:
                valid_endY_array.append(y)
            elif y < midY:
                valid_topY_array.append(y)

    if len(valid_topY_array) <= 0 and len(valid_endY_array) <= 0:
        return 0, height - 1

    # 2.判断有效的边缘是否可以上边缘或下边缘(这个步骤里可能会用到ocr技术)
    finalTopY = 0
    finalEndY = height - 1
    if len(valid_topY_array) > 0:
        finalTopY = pickOutFinalTopY(img, height, width, valid_topY_array, valid_flag_list, reader)

    if len(valid_endY_array) > 0:
        finalEndY = pickOutFinalEndY(img, height, width, valid_endY_array, valid_flag_list, reader)

    # 3.返回上下黑边纵坐标
    return finalTopY, finalEndY


# 对于无边缘的纵坐标, 重新计算该纵坐标上是否存在非黑像素
def recomputeValidFlagList(img, height, width, valid_flag_list):
    for y in range(0, height):
        if valid_flag_list[y] == 0:
            lineBlackFlag = checkLineIsBlack(img, width, y)
            if not lineBlackFlag:
                valid_flag_list[y] = 1


def recognizeImageValidZone(imagePath, reader):
    # 读取图片
    img = cv2.imread(imagePath)
    # 获取图像尺寸
    height, width = img.shape[:2]

    edges = cv2.Canny(img, 100, 200)
    lines = cv2.HoughLinesP(edges, 1, np.pi / 180, 100, minLineLength=getMinLineLength(width), maxLineGap=10)

    if lines is None:
        print(imagePath + "不存在直线")
        return 0, height - 1

    levelLines = []
    for line in lines:
        x1, y1, x2, y2 = line[0]
        if y1 != y2:
            continue

        if isLevelLineNeedIgnore(height, y1):
            continue
        # print(f"水平直线===================={y1}")
        # cv2.line(img, (x1, y1), (x2, y2), (0, 255, 0), 2)
        levelLines.append(line)

    if len(levelLines) == 0:
        print(imagePath + "-----不存在水平直线")
        return 0, height - 1

    # 计算标识数组,用于标识各行是否存在非黑像素
    valid_flag_list = [0 for _ in range(height)]
    # 遍历边缘检测后的图像,找到边缘像素的坐标
    for y in range(edges.shape[0]):
        for x in range(edges.shape[1]):
            if edges[y][x] != 0:  # 如果当前像素不是背景(即边缘)
                valid_flag_list[y] = 1
                break

    recomputeValidFlagList(img, height, width, valid_flag_list)

    return computeTopAndEnd(img, height, width, valid_flag_list, levelLines, reader)


def doDropForImage(srcDir, srcFile, targetDir, reader):
    # 读取图片
    img = cv2.imread(srcDir + srcFile)
    # 获取图像尺寸
    height, width = img.shape[:2]
    # 获取起止的纵坐标
    startY, overY = recognizeImageValidZone(srcDir + srcFile, reader)
    crop_img = img[startY:overY + 1, 0:width]
    cv2.imwrite(targetDir + srcFile + "_dealed.jpg", crop_img)


def preDropForImage(srcDir, srcFile, targetDir, reader):
    # 读取图片
    img = cv2.imread(srcDir + srcFile)
    # 获取图像尺寸
    height, width = img.shape[:2]
    # 获取起止的纵坐标
    startY, overY = recognizeImageValidZone(srcDir + srcFile, reader)
    # 标记一下图片边缘
    if startY != 0:
        cv2.line(img, (0, startY), (width - 1, startY), (0, 255, 0), 2)
    if overY != height - 1:
        cv2.line(img, (0, overY), (width - 1, overY), (0, 255, 0), 2)

    if startY == 0 and overY == height - 1:
        cv2.imwrite(targetDir + 'unchanged/' + srcFile + "_dealed.jpg", img)
    else:
        cv2.imwrite(targetDir + 'changed/' + srcFile, img)


reader = easyocr.Reader(['ch_sim', 'en'], gpu=False)
preDropForImage('E:/black/sample_images_black/', "1.jpg", 'E:/black/success_dealed/', reader)



到了这里,关于用Python实现给图片去黑边的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Python怎么将pdf转为图片?Python如何实现pdf文件转图片

    而pdf则是用来保存一些内容已经确定好的数据,因为pdf是无法直接修改内容的,所以也会经常将pdf转为图片来保存。本文就将会来介绍一下pdf转图片的方法,往下看看吧。 1.pdf转图片的话主要实现所需要的模块叫做PyMuPDF,它就是用来操作pdf文件的,通过pip工具下载安装即可。

    2024年02月11日
    浏览(49)
  • Python实现:图片叠加与融合

    Python实现:图片叠加与融合 在图像处理和计算机视觉中,图像的叠加和融合是一项重要的功能。通过叠加和融合不同的图像,我们可以实现许多有趣的应用,例如将两张图片叠加成一张,比较两幅图片的相似度等等。 Python作为一种高级编程语言,提供了丰富的图像处理和计

    2024年02月11日
    浏览(28)
  • Python实现图片二值化

    图像二值化就是将图像上的像素点的“灰度值”设置为[0, 0, 0]或[255, 255, 255],即要么纯黑,要么纯白。 通过二值化,能更好地分析物体的形状和轮廓。 二值化的实现一般有: 全局阈值法、自适应阈值法、OTSU二值化等 (1)全局阈值法 就是选定一个全局阈值,大于这个值的色

    2024年02月11日
    浏览(45)
  • Python实现图片亮度调整算法

    Python实现图片亮度调整算法 图片亮度调整是图像处理中常用的技术之一。通过改变图片的亮度,可以使得图片更清晰、更具艺术效果。下面将介绍如何使用Python实现这一功能。 首先,我们需要导入Python中的图像处理库PIL: 接下来,我们需要打开一张图片,并进行亮度调整。

    2024年02月08日
    浏览(26)
  • python实现图片转视频功能

    PyCharm ,将会带来全新的写作体验; 安装OpenCV库

    2024年02月12日
    浏览(22)
  • Window安装Python和开发Pycharm

    准备:  1:安装Python环境    https://www.python.org/downloads/windows/ 2:  下载Pycharm   https://www.jetbrains.com/pycharm/download/other.html 

    2024年01月22日
    浏览(36)
  • 如何在Python中获取图片分辨率?——Python实现获取图片分辨率的代码及详解。

    如何在Python中获取图片分辨率?——Python实现获取图片分辨率的代码及详解。 在进行图片处理或者图片分析的时候,获取图片的分辨率信息是必不可少的。Python提供了许多库可以方便地获取图片的分辨率信息。在本文中,我们将详细介绍如何使用Python实现获取图片分辨率的功

    2024年02月07日
    浏览(36)
  • 用python实现文本/图片生成视频

    使用Python来生成视频通常涉及到使用一些专门的库,比如 OpenCV 或者 moviepy。下面是一个简单的例子,使用OpenCV和PIL(Python Imaging Library)来创建一个视频。 python复制代码 import cv2 import numpy as np from PIL import Image import os # 图片路径列表 image_list = [\\\'img1.jpg\\\', \\\'img2.jpg\\\', \\\'img3.jpg\\\'] # 视频

    2024年01月17日
    浏览(73)
  • 人工智能——“kmeans实现图片分割”(Python实现)

    (2)边缘分割:对图像边缘进行检测,即检测图像中灰度值发生跳变的地方,则为一片 区域的边缘。 (3)直方图法:对图像的颜色建立直方图,而直方图的波峰波谷能够表示一块区域的颜 色值的范围,来达到分割的目的。 (4)特定理论:基于 聚类分析 、小波变换等理论完成图像

    2024年04月17日
    浏览(27)
  • 【Python爬虫开发实战①】使用urllib以及XPath爬取可爱小猫图片

    个人主页 :为梦而生~ 关注我一起学习吧! 专栏 :python网络爬虫从基础到实战 欢迎订阅!后面的内容会越来越有意思~ 往期推荐 : 【Python爬虫开发基础⑦】urllib库的基本使用 【Python爬虫开发基础⑧】XPath库及其基本用法 我们在之前已经有8篇文章讲述基础知识了,下面我们

    2024年02月11日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包