opencv+python 巧用霍夫變換實現圖片旋轉角度計算

圖片角度不對,須要作校訂,校訂後ocr識別準確率更高,網上找了一圈,暫時沒發現怎麼計算圖片旋轉角度的資料。html

首先就是查找怎麼作圖片旋轉,找到2篇文章,4 Point OpenCV getPerspective Transform Example 和 使用 OpenCV 和 Python 對圖片進行旋轉。第一篇的方法,是先要肯定4個角的頂點,要是能肯定就輕鬆多了,放棄。第二篇的方法,就是須要傳入旋轉角度。python

以後就是想怎麼計算須要旋轉的角度。調查過程當中,發現了霍夫變換這個東西,抓住了一點點靈感,靈機一動。這個東西不是能夠畫一堆的線,有了線,角度很好算,三角函數,tan(角度)=高/長,弧度=角度*180/π。以後繼續調查,HoughLines獲得的是線的長度和弧度,HoughLinesP獲得的是2個點的座標,因而選定了HoughLines這個方法。算法

作霍夫變換,模糊這一步的操做是頗有必要的,沒作模糊,少的都要檢測出1900多組的數據,通過必定模糊以後,獲得的數據就少多了。那麼怎麼在檢測出來的線裏,獲取咱們須要的角度?須要處理的圖是矩形(長方形)的,雖然有一些干擾,最後角度計算對了,仍是能調整成比較平整的矩形的。獲取到的直線有幾十組,通過一些樣例圖片測試,不能取第一條線,也不能取最後一條線,怎麼設計比較好?app

把數據按區間分組。這裏分組的算法是本身想的,沒啥理論依據,就是拍腦殼決定了(數學不夠好)。思路:按照弧度分組,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 。測試

後續的實驗過程當中,圖片旋轉的結果,基本都能旋轉平整了,只有小部分的圖片偏轉的幾度,以後再考慮如何去掉這種干擾。ui

完。設計

相關文章
相關標籤/搜索