有没有办法可以检测图像方向并将图像旋转到直角?

2024-02-08

我正在制作一个修复扫描文档的脚本,现在我需要一种方法来检测图像方向并旋转图像,以便其旋转正确。

现在我的脚本不可靠而且不够精确。

现在我寻找一条线,它会旋转它正确看到的第一条线,但这几乎不起作用,除了一些图像

img_before = cv2.imread('rotated_377.jpg')

img_gray = cv2.cvtColor(img_before, cv2.COLOR_BGR2GRAY)
img_edges = cv2.Canny(img_gray, 100, 100, apertureSize=3)
lines = cv2.HoughLinesP(img_edges, 1, math.pi / 180.0, 100, minLineLength=100, maxLineGap=5)

angles = []

for x1,y1,x2,y2 in lines[0]:
    angle = math.degrees(math.atan2(y2 - y1, x2 - x1))
    angles.append(angle)

median_angle = np.median(angles)
img_rotated = ndimage.rotate(img_before, median_angle)

print("Angle is {}".format(median_angle))
cv2.imwrite('rotated.jpg', img_rotated)

I want to make a script that gets an image like this one(don't mind the image its for testing purposes) rotated image

并以正确的方式旋转它,这样我就可以获得正确方向的图像。


这是一个有趣的问题,我尝试了多种方法来纠正文档图像的方向,但所有方法都有不同的例外。 我正在分享一种基于文本方向的方法。对于文本区域检测,我使用输入图像的梯度图。

所有其他实现细节都在代码中注释。

请注意,这仅在图像中存在的所有文本具有相同方向时才有效。

#Document image orientation correction
#This approach is based on text orientation

#Assumption: Document image contains all text in same orientation

import cv2
import numpy as np

debug = True

#Display image
def display(img, frameName="OpenCV Image"):
    if not debug:
        return
    h, w = img.shape[0:2]
    neww = 800
    newh = int(neww*(h/w))
    img = cv2.resize(img, (neww, newh))
    cv2.imshow(frameName, img)
    cv2.waitKey(0)

#rotate the image with given theta value
def rotate(img, theta):
    rows, cols = img.shape[0], img.shape[1]
    image_center = (cols/2, rows/2)
    
    M = cv2.getRotationMatrix2D(image_center,theta,1)

    abs_cos = abs(M[0,0])
    abs_sin = abs(M[0,1])

    bound_w = int(rows * abs_sin + cols * abs_cos)
    bound_h = int(rows * abs_cos + cols * abs_sin)

    M[0, 2] += bound_w/2 - image_center[0]
    M[1, 2] += bound_h/2 - image_center[1]

    # rotate orignal image to show transformation
    rotated = cv2.warpAffine(img,M,(bound_w,bound_h),borderValue=(255,255,255))
    return rotated


def slope(x1, y1, x2, y2):
    if x1 == x2:
        return 0
    slope = (y2-y1)/(x2-x1)
    theta = np.rad2deg(np.arctan(slope))
    return theta


def main(filePath):
    img = cv2.imread(filePath)
    textImg = img.copy()

    small = cv2.cvtColor(textImg, cv2.COLOR_BGR2GRAY)

    #find the gradient map
    kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
    grad = cv2.morphologyEx(small, cv2.MORPH_GRADIENT, kernel)

    display(grad)

    #Binarize the gradient image
    _, bw = cv2.threshold(grad, 0.0, 255.0, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
    display(bw)

    #connect horizontally oriented regions
    #kernal value (9,1) can be changed to improved the text detection
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 1))
    connected = cv2.morphologyEx(bw, cv2.MORPH_CLOSE, kernel)
    display(connected)

    # using RETR_EXTERNAL instead of RETR_CCOMP
    # _ , contours, hierarchy = cv2.findContours(connected.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
    contours, hierarchy = cv2.findContours(connected.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) #opencv >= 4.0



    mask = np.zeros(bw.shape, dtype=np.uint8)
    #display(mask)
    #cumulative theta value
    cummTheta = 0
    #number of detected text regions
    ct = 0
    for idx in range(len(contours)):
        x, y, w, h = cv2.boundingRect(contours[idx])
        mask[y:y+h, x:x+w] = 0
        #fill the contour
        cv2.drawContours(mask, contours, idx, (255, 255, 255), -1)
        #display(mask)
        #ratio of non-zero pixels in the filled region
        r = float(cv2.countNonZero(mask[y:y+h, x:x+w])) / (w * h)

        #assume at least 45% of the area is filled if it contains text
        if r > 0.45 and w > 8 and h > 8:
            #cv2.rectangle(textImg, (x1, y), (x+w-1, y+h-1), (0, 255, 0), 2)

            rect = cv2.minAreaRect(contours[idx])
            box = cv2.boxPoints(rect)
            box = np.int0(box)
            cv2.drawContours(textImg,[box],0,(0,0,255),2)

            #we can filter theta as outlier based on other theta values
            #this will help in excluding the rare text region with different orientation from ususla value 
            theta = slope(box[0][0], box[0][1], box[1][0], box[1][1])
            cummTheta += theta
            ct +=1 
            #print("Theta", theta)
            
    #find the average of all cumulative theta value
    orientation = cummTheta/ct
    print("Image orientation in degress: ", orientation)
    finalImage = rotate(img, orientation)
    display(textImg, "Detectd Text minimum bounding box")
    display(finalImage, "Deskewed Image")

if __name__ == "__main__":
    filePath = 'D:\data\img6.jpg'
    main(filePath)

这是检测到文本区域的图像,从中我们可以看到一些文本区域丢失了。文本方向检测在整个文档方向检测中起着关键作用,因此根据文档类型,应在文本检测算法中进行一些小调整,以使该方法更好地工作。

Here is the final image with correct orientation Final deskewed image

请建议对此方法进行修改,以使其更加稳健。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

有没有办法可以检测图像方向并将图像旋转到直角? 的相关文章

随机推荐

  • 如何使用 VBA 将 ShapeStyle 应用于 Excel 中图表的特定系列?

    如何使用 vba 以编程方式将 ShapeStyle 应用于单个图表系列中的一组点 看来我需要一个 形状 对象 其中仅包含我尝试格式化的系列中的点 一些信息在这里 http peltiertech com WordPress program
  • 检索网格的内容

    我在用jqGrid http www trirand com jqgridwiki doku php id start在客户端显示值 最初网格是空的 用户内联输入数据 根据要求 我需要在用户提交表单后提交数据 我打算在提交表单之前格式化内容
  • 串行端口重定向或拆分[关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在寻找一本关于如何进行串行端口重定向或端口分割的书和 或代码示例 我编写了很多 com 端口应用程
  • 如何阻止Android硬件后退按钮在react-native的react-navigation中起作用?

    我正在开发一个问答游戏 我使用react navigation来处理导航 我有3个组件 newGame 问题 结果 如果没有 我不希望用户从结果页面返回到问题 问题已经用尽 但是 按后退按钮 Android 硬件 将使他回到问题 然后我尝试
  • Python、Flask客户端ip地址

    我需要记录我使用 Python 和 Flask 创建的 web 应用程序的每个用户的 IP 地址 我在用着 request remote addr 但这会返回应用程序部署到的服务器的 IP 地址 有解决办法吗 如何部署 Flask 应用程序
  • C++ 中静态全局标识符和非静态全局标识符有什么区别?

    有什么区别static全球和非staticC 中的全局标识符 静态将变量的范围限制为相同翻译单位 https stackoverflow com questions 1106149 what is a translation unit in
  • React/redux,显示多个组件,共享相同的操作,但具有不同的状态

    假设我有一个可重复使用的容器 它是一个具有多个页面的向导 向导状态由 redux actions 驱动 当一个动作被触发时 我使用一个减速器来更新我的状态 如果我想要复制多个向导并拥有自己的状态怎么办 我认为必须有一种方法可以让某个动态减速
  • 在nodejs(express)中的router.route()中设置中间件

    我想要它做什么 router post xxxx authorize xxxx function authorize req res next if xxx res send 500 else next 我想检查每条路线的会话 但既然路由器
  • 如何在没有 if 语句的情况下做出决定

    我正在学习 Java 课程 但我们还没有正式学习 if 语句 我在学习的时候看到这个问题 编写一个名为 pay 的方法 它接受两个参数 一个代表助教工资的实数 一个代表助教本周工作时数的整数 该方法应该返回付给TA多少钱 例如 调用 pay
  • @NSManaged 是做什么的?

    我在不同的场合都遇到过这个关键词 我有点知道它应该做什么 但我真的想更好地理解它 我注意到了什么 NSManaged 不是基于文档 而是通过重复使用 它神奇地取代了键值编码 大致相当于 dynamic在 Objective C 中 我不太了
  • 如何在 Haskell 中安装旧版本的 base

    我已经安装了Haskell平台 并且有7 10 3版本的ghci 其中有4 8 2 0版本的base 我需要安装gloss 1 8 哪个需要base 4 7 基础版本 我的问题是 当我已经有了新版本时 如何安装这个旧版本 是否可以 或者我必
  • ms-access:通过打印来填写申请表

    我将打印访问报告 该报告不会印刷成普通的白皮书 它将打印在带有复选框和字段的纸张上 我需要根据访问数据打印这些复选框和字段 有没有任何库可以让这变得更容易 是否有一个功能可以帮助在特定坐标上打印 请注意 我需要在数千份表格上打印 并且我必须
  • 使用准备好的语句后 SELECT LAST_INSERT_ID() 返回 0

    我正在使用 MySQL 和准备好的语句来插入BLOB记录 jpeg 图像 执行准备好的语句后 我发出一个SELECT LAST INSERT ID 它返回 0 在我的代码中 我在执行命令后放置了一个断点 并在 MySQL 命令 监视器 窗口
  • 为什么 Chrome 开发工具显示 200 状态代码而不是 304

    当我用 Chrome 测试缓存处理中的奇怪行为时 我问了一些关于它的问题 here https stackoverflow com questions 67016037 chrome doesnt send if none match he
  • Discord.js V12 粗鲁言语过滤器不起作用

    所以我添加了一个粗鲁的单词过滤器 每当有人说这个单词 小写或大写 时 它就会删除他们的消息并回复一些内容 然后回复会在几秒钟内被删除 这是我当前的代码 但它不读取rudeWords当我在聊天中写下任何粗鲁的话时 它不会做任何事情 clien
  • Rails4:康康舞还是康康康舞?使用 has_secure_password

    我正在尝试实现某种类型的用户 以便用户可以编辑数据 而其他用户只能读取 user rb class User lt ActiveRecord Base has secure password validates presence of em
  • AVAudioRecorder 内存泄漏

    我希望有人能在这件事上支持我 我一直在开发一个应用程序 该应用程序允许最终用户录制一个小音频文件以供以后播放 并且正在测试内存泄漏 当 AVAudioRecorder 的 停止 方法尝试关闭其正在录制的音频文件时 我仍然经常遇到内存泄漏 这
  • create-react-app 返回错误:执行时找不到模块“react-scripts/scripts/init.js”

    当我尝试使用 npm 和yarn 创建一个 React 项目时 它显示以下错误 我尝试重新安装节点并确保它是最新的 以及通过运行 npm install g create react app latest 来创建 react app 我还删
  • glFlush() vs [[self openGLContext]lushBuffer] vs glFinish vs glSwapAPPLE vs aglSwapBuffers

    使用 NSOpenGLView 时有几个类似的 OpenGL 操作 glFlush self openGLContext flushBuffer glFinish glSwap苹果 egl交换缓冲区 何时应该使用其中的每一个 在示例应用程序
  • 有没有办法可以检测图像方向并将图像旋转到直角?

    我正在制作一个修复扫描文档的脚本 现在我需要一种方法来检测图像方向并旋转图像 以便其旋转正确 现在我的脚本不可靠而且不够精确 现在我寻找一条线 它会旋转它正确看到的第一条线 但这几乎不起作用 除了一些图像 img before cv2 im