文档章节

opencv+python 巧用霍夫变换实现图片旋转角度计算

sskicgah
 sskicgah
发布于 2017/08/19 17:21
字数 1290
阅读 251
收藏 1
点赞 0
评论 0

图片角度不对,需要做校正,校正后ocr识别准确率更高,网上找了一圈,暂时没发现怎么计算图片旋转角度的资料。

首先就是查找怎么做图片旋转,找到2篇文章,4 Point OpenCV getPerspective Transform Example 和 使用 OpenCV 和 Python 对图片进行旋转。第一篇的方法,是先要确定4个角的顶点,要是能确定就轻松多了,放弃。第二篇的方法,就是需要传入旋转角度。

之后就是想怎么计算需要旋转的角度。调查过程中,发现了霍夫变换这个东西,抓住了一点点灵感,灵机一动。这个东西不是可以画一堆的线,有了线,角度很好算,三角函数,tan(角度)=高/长,弧度=角度*180/π。之后继续调查,HoughLines得到的是线的长度和弧度,HoughLinesP得到的是2个点的坐标,于是选定了HoughLines这个方法。

做霍夫变换,模糊这一步的操作是很有必要的,没做模糊,少的都要检测出1900多组的数据,经过一定模糊之后,得到的数据就少多了。那么怎么在检测出来的线里,获取我们需要的角度?需要处理的图是矩形(长方形)的,虽然有一些干扰,最后角度计算对了,还是能调整成比较平整的矩形的。获取到的直线有几十组,经过一些样例图片测试,不能取第一条线,也不能取最后一条线,怎么设计比较好?

把数据按区间分组。这里分组的算法是自己想的,没啥理论依据,就是拍脑袋决定了(数学不够好)。思路:按照弧度分组,0-45, 45-90, 90-135,135-180。为啥只到180?因为多次测试没看到大于180的数据,没看霍夫变换具体的算法,暂时就这么用了。分组之后,怎么选出一个需要的弧度?利用方差,算出分组里方差最小的一组数据,取平均值。之后就用这个平均值当做旋转弧度,有了弧度,第二篇帖子里的旋转参数稍微改一下,传入弧度就可以了。最后一个小细节问题,得到不同的旋转弧度,怎么旋转才是符合我们实际需要的,比如图片是垂直的,怎么转平了,这个的解决办法都是用经验转换,不一定通用,可以根据实际需要再调整。下面上代码,就不贴图了。

# -*- coding: utf-8 -*-
import cv2
import numpy as np
from matplotlib import pyplot as plt
import math

def rotate_about_center2(src, radian, scale=1.):
    #入参:弧度
    w = src.shape[1]
    h = src.shape[0]
    angle = radian * 180 / np.pi
    # now calculate new image width and height
    nw = (abs(np.sin(radian)*h) + abs(np.cos(radian)*w))*scale
    nh = (abs(np.cos(radian)*h) + abs(np.sin(radian)*w))*scale
    # ask OpenCV for the rotation matrix
    rot_mat = cv2.getRotationMatrix2D((nw*0.5, nh*0.5), angle, scale)
    # calculate the move from the old center to the new center combined
    # with the rotation
    rot_move = np.dot(rot_mat, np.array([(nw-w)*0.5, (nh-h)*0.5,0]))
    # the move only affects the translation, so update the translation
    # part of the transform
    rot_mat[0,2] += rot_move[0]
    rot_mat[1,2] += rot_move[1]
    return cv2.warpAffine(src, rot_mat, (int(math.ceil(nw)), int(math.ceil(nh))), flags=cv2.INTER_LANCZOS4)

def get_group(arr):
    #按照4个弧度区间分组,返回不为空的分组数据
    radian_45 = np.pi/4
    radian_90 = np.pi/2
    radian_135 = radian_45 * 3
    radian_180 = np.pi
    ret_arr = [[],[],[],[]]
    for i in range(len(arr)):
        if arr[i] < radian_45:
            ret_arr[0].append(arr[i])
        elif arr[i] < radian_90:
            ret_arr[1].append(arr[i])
        elif arr[i] < radian_135:
            ret_arr[2].append(arr[i])
        else:
            ret_arr[3].append(arr[i])
            
    while [] in ret_arr:
        ret_arr.remove([])
    
    #print ret_arr
    return ret_arr
    
def get_min_var_avg(arr):
    #按照不同弧度区间分组,返回方差最小的一个分组的弧度平均值
    group_arr = get_group(arr)
    var_arr = []
    if len(group_arr) <= 1:
        var_arr = group_arr
    else:
        var_arr = [np.var(group_arr[i]) for i in range(len(group_arr))]
    min_var = 10000
    min_i = 0
    for i in range(len(var_arr)):
        if var_arr[i] < min_var:
            min_var = var_arr[i]
            min_i = i
    #print min_var, i
    avg = np.mean(group_arr[min_i])
    return avg

def get_rotate_radian(radian, reverse = False):
    #旋转弧度转换
    radian_45 = np.pi/4
    radian_90 = np.pi/2
    radian_135 = radian_45 * 3
    radian_180 = np.pi
    ret_radian = 0
    if radian < radian_45:
        ret_radian = radian
    elif radian < radian_90:
        ret_radian = radian - radian_90
    elif radian < radian_135:
        ret_radian = radian - radian_90
    else:
        ret_radian = radian - radian_180
        
    if reverse:
        ret_radian += radian_90
    print ret_radian
    return ret_radiana

def rotate():
    image = cv2.imread("pic/test012.jpg", 0)
    
    print image.shape
    
    #高斯模糊
    blur = cv2.GaussianBlur(image,(7,7),0)#自己调整,经验数据
    cv2.imshow('image',blur)
    cv2.waitKey(0)
    #Canny边缘检测
    canny = cv2.Canny(blur, 20, 150, 3)
    lines = cv2.HoughLines(canny, 1, np.pi/180, 118)#自己调整,经验数据
    
    #求平均弧度
    l = len(lines[0])
    print l
    
    theta_arr = [lines[0][i][1] for i in range(l)]
    print theta_arr
    rotate_theta = get_min_var_avg(theta_arr)
    print rotate_theta
    
    #print lines

    '''for line in lines[0]:
        rho = line[0]
        theta = line[1]
        
        a = np.cos(theta)
        b = np.sin(theta)
        x0 = a*rho
        y0 = b*rho
        cv2.line(image, (int(x0 - 1000*b), int(y0 + 1000*a)), (int(x0 + 1000*b), int(y0 - 1000*a)), (0,255,0), 2)
        #cv2.imshow('image',image)
        #cv2.waitKey(0)'''
    
    img2 = rotate_about_center2(image, get_rotate_radian(rotate_theta, image.shape[0] > image.shape[1])) # hight > width

    plt.imshow(img2)
    plt.show()

if __name__ == '__main__':
    rotate()

有段注释的代码,是用来画霍夫线的,代码参考 Hough Line Transform 。

后续的实验过程中,图片旋转的结果,基本都能旋转平整了,只有小部分的图片偏转的几度,之后再考虑如何去掉这种干扰。

完。

© 著作权归作者所有

共有 人打赏支持
sskicgah
粉丝 7
博文 43
码字总数 32720
作品 0
福州
程序员
OpenCV基于傅里叶变换进行文本的旋转校正

本文描述一种利用OpenCV及傅里叶变换识别图片中文本旋转角度并自动校正的方法,由于对C#比较熟,因此本文将使用OpenCVSharp。 文章参考了http://johnhany.net/2013/11/dft-based-text-rotati...

BoyTNT ⋅ 2015/07/24 ⋅ 0

[图像识别] 1、如何识别一个指针式的时种的时间?

目录 一、算法基本原理 1、图片预处理 2、找表盘 3、找指针 4、指针映射 5、求时间 二、算法流程图 三、程序关键函数说明 1、Canny 2、HoughCircles 3、HoughLines2 4、MyLine类 5、平面几何...

史迪奇2号 ⋅ 2017/08/05 ⋅ 0

车牌识别及验证码识别的一般思路

本文源自我之前花了2天时间做的一个简单的车牌识别系统。那个项目,时间太紧,样本也有限,达不到对方要求的95%识别率(主要对于车牌来说,D,0,O,I,1等等太相似了。然后,汉字的识别难度也...

最美的回忆 ⋅ 2017/01/13 ⋅ 0

OpenCV 几何变换-图像旋转

OpenCV提供了warpAffine函数实现图片仿射变换功能,我们可以利用这个函数实现图像旋转,函数原型为: 其中第一,二个参数是输入和输出的图像; 第三个参数仿射变换矩阵; 第四个参数为变换后...

chaipp0607 ⋅ 2017/03/18 ⋅ 0

有没有人实现过文本行倾斜角的检测

由于扫描文档有倾斜角存在,我们的任务是检测出文本行倾斜角度并校正,但是霍夫变换是针对直线的,我不知道如何把文本行转换为直线,求指导

freehezhan ⋅ 2013/12/16 ⋅ 0

图像验证码识别(八)——字符归一化

前面提到了将验证码上的字符分割成一个单独的字符图片并且保存,但是扣下来的字符串可能会有倾斜的现象,因为现在很多网页验证码为了防止破解都对字符进行了一定的扭曲和旋转,即使是同一个网...

moki_oschina ⋅ 2016/11/29 ⋅ 0

C#中基于GDI+(Graphics)图像处理系列之任意角度旋转图像

简介 图像旋转功能在实际使用中出现得不多,Image自带RotateFlip方法可以简单的实现90、180等角度的旋转或者翻转,但是如果要实现任意角度的旋转该怎么做?对于一个有经验的同学估计不到半天...

lhtzbj12 ⋅ 2017/01/05 ⋅ 0

radon变换用于车牌图像倾斜矫正

本文转载至:https://www.cnblogs.com/virqin/archive/2012/05/22/2514083.html Radon变换定义:下图显示了在指定的旋转角度的单一投影。间距为1个像素的平行光穿过图像,则radon变换计算穿过...

qq_38211852 ⋅ 05/25 ⋅ 0

Android使用Canvas和Path自定义绘制动画

1. 动画类型 在开发中,完成设计师设计的动画的途径有很多种。 (1). 属性动画(Property Animtion) Creates an animation by modifying an object's property values over a set period of...

雨打空城 ⋅ 05/22 ⋅ 0

css实现图片背景填充的正六边形

最近有个需求需要实现带有图片背景的正六边形,这里记录一下我自己实现的方法。 我项目里的最终效果大概是这样子的,这里我们只演示实现一个正六边形。 六边形的实现原理其实就是通过旋转三个...

sundaypig ⋅ 2017/11/27 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

聊聊spring cloud的HystrixCircuitBreakerConfiguration

序 本文主要研究一下spring cloud的HystrixCircuitBreakerConfiguration HystrixCircuitBreakerConfiguration spring-cloud-netflix-core-2.0.0.RELEASE-sources.jar!/org/springframework/......

go4it ⋅ 46分钟前 ⋅ 0

二分查找

二分查找,也称折半查找、二分搜索,是一种在有序数组中查找某一特定元素的搜索算法。搜素过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜素过程结束;如果某一特定元素大于...

人觉非常君 ⋅ 今天 ⋅ 0

VS中使用X64汇编

需要注意的是,在X86项目中,可以使用__asm{}来嵌入汇编代码,但是在X64项目中,再也不能使用__asm{}来编写嵌入式汇编程序了,必须使用专门的.asm汇编文件来编写相应的汇编代码,然后在其它地...

simpower ⋅ 今天 ⋅ 0

ThreadPoolExecutor

ThreadPoolExecutor public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, ......

4rnold ⋅ 昨天 ⋅ 0

Java正无穷大、负无穷大以及NaN

问题来源:用Java代码写了一个计算公式,包含除法和对数和取反,在页面上出现了-infinity,不知道这是什么问题,网上找答案才明白意思是负的无穷大。 思考:为什么会出现这种情况呢?这是哪里...

young_chen ⋅ 昨天 ⋅ 0

前台对中文编码,后台解码

前台:encodeURI(sbzt) 后台:String param = URLDecoder.decode(sbzt,"UTF-8");

west_coast ⋅ 昨天 ⋅ 0

实验楼—MySQL基础课程-挑战3实验报告

按照文档要求创建数据库 sudo sercice mysql startwget http://labfile.oss.aliyuncs.com/courses/9/createdb2.sqlvim /home/shiyanlou/createdb2.sql#查看下数据库代码 代码创建了grade......

zhangjin7 ⋅ 昨天 ⋅ 0

一起读书《深入浅出nodejs》-node模块机制

node 模块机制 前言 说到node,就不免得提到JavaScript。JavaScript自诞生以来,经历了工具类库、组件库、前端框架、前端应用的变迁。通过无数开发人员的努力,JavaScript不断被类聚和抽象,...

小草先森 ⋅ 昨天 ⋅ 0

Java桌球小游戏

其实算不上一个游戏,就是两张图片,不停的重画,改变ball图片的位置。一个左右直线碰撞的,一个有角度碰撞的。 左右直线碰撞 package com.bjsxt.test;import javax.swing.*;import j...

森林之下 ⋅ 昨天 ⋅ 0

你真的明白RPC 吗?一起来探究 RPC 的实质

你真的明白RPC 吗?一起来探究 RPC 的实质 不论你是科班出身还是半路转行,这么优秀的你一定上过小学语文,那么对扩句和缩句你一定不陌生。缩句就是去除各种修饰提炼出一句话的核心,而不失基...

AI9o後 ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部