图像倾斜矫正

栏目: 编程工具 · 发布时间: 6年前

内容简介:没有找到关于图像倾斜矫正的综述性文献,那就自己整理一下吧。图像倾斜可以分为两种情况,一种是平面倾斜,这种情况下拍照设备与试卷平行,拍出来的图像只需要进行旋转即可完成矫正;另一种是Z轴倾斜,这种情况下拍照设备与试卷存在一定的角度,拍出来的图像要先进行透视变换,然后再进行旋转等操作才可以完成矫正。图像倾斜矫正关键在于根据图像特征自动检测出图像倾斜方向和倾斜角度。

没有找到关于图像倾斜矫正的综述性文献,那就自己整理一下吧。

图像倾斜可以分为两种情况,一种是平面倾斜,这种情况下拍照设备与试卷平行,拍出来的图像只需要进行旋转即可完成矫正;另一种是Z轴倾斜,这种情况下拍照设备与试卷存在一定的角度,拍出来的图像要先进行透视变换,然后再进行旋转等操作才可以完成矫正。

图像倾斜矫正关键在于根据图像特征自动检测出图像倾斜方向和倾斜角度。

对于平面倾斜,先利用边缘(轮廓)检测算法算法找到图像的边界,然后利用 Radon变换法(基于投影的方法)Hough变换法 、线性回归法等找到倾斜角度,然后再利用 仿射变换 进行旋转。

对于Z轴倾斜,先利用边缘(轮廓)检测算法找到图像的边界,然后利用 透视变换 把视平面上的点投影到现实平面,然后再利用仿射变换进行旋转。

实践

边缘检测

# -*- coding: utf-8 -*-

import numpy as np
import cv2

img = cv2.imread('../image/tilt.jpg')
GrayImage = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

CannyImage = cv2.Canny(GrayImage,50, 150, apertureSize=3)

cv2.imshow('gray',GrayImage)
cv2.imshow('canny',CannyImage)
cv2.waitKey(0)

图像倾斜矫正 图像倾斜矫正

edges=cv.Canny(image, threshold1, threshold2[, edges[, apertureSize[, L2gradient]]]) 参数说明:

  • image:输入图像。
  • threshold1:最小阈值。
  • threshold2:最大阈值。
  • apertureSize:Sobel算子的孔径大小。

更多内容参考:

以上代码,调用了OpenCV中的canny方法找到了边缘,但是,文字的边缘也被显示出来了。那么,怎么去掉文字边缘,只要长方形框的边缘呢?OpenCV也提供了方法,使用findContours来查找轮廓,使用drawContours来绘制轮廓。

# -*- coding: utf-8 -*-

import numpy as np
import cv2

img = cv2.imread('../image/tilt.jpg')
GrayImage = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
CannyImage = cv2.Canny(GrayImage,50, 150, apertureSize=3)
ret,BinImage=cv2.threshold(CannyImage,127,255,cv2.THRESH_BINARY)

_, contours, _= cv2.findContours(BinImage, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

cv2.imshow('bin',BinImage)
cv2.drawContours(img, contours, -1, (0,255, 0), 1)
cv2.imshow('edge',img)
cv2.waitKey(0)

图像倾斜矫正

contours, hierarchy = cv.findContours(image, mode, method[, contours[, hierarchy[, offset]]]) 参数说明:

如果按照 官方文档 调用,会报错,参考 ValueError: too many values to unpack 解决。实际上,这是因为opencv3之后该函数的返回值有三个,而官方文档有多个版本,比如 这一版 中就说明了有三个参数。

计算倾斜角

以上,已经找到了图片的边缘,接下来计算倾斜角度。

# -*- coding: utf-8 -*-

import numpy as np
import cv2

img = cv2.imread('../image/tilt.jpg')
GrayImage = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
CannyImage = cv2.Canny(GrayImage,50, 150, apertureSize=3)
ret,BinImage=cv2.threshold(CannyImage,127,255,cv2.THRESH_BINARY)

lines = cv2.HoughLinesP(BinImage, 1, np.pi / 180, 160, minLineLength=200, maxLineGap=180)

# 寻找长度最长的线
distance = []
for line in lines:
    x1, y1, x2, y2 = line[0]
    dis = np.sqrt(pow((x2 - x1), 2) + pow((y2 - y1), 2))
    distance.append(dis)
max_dis_index = distance.index(max(distance))
max_line = lines[max_dis_index]
x1, y1, x2, y2 = max_line[0]

# 获取旋转角度
angle = cv2.fastAtan2((y2 - y1), (x2 - x1))
print(angle)

以上代码,很尴尬,并不是利用findContours的结果进行计算的,而是一个新的思路。为什么没有使用contours?因为不会写代码。。。如果要继续findContours思路,那么可以参考 图像矫正技术深入探讨 进行改写。

仿射变换

求出倾斜角度之后,利用仿射变换进行旋转。

# 计算图片中心
centerpoint = (img.shape[1]/2,img.shape[0]/2)
# 获取旋转矩阵
rotate_mat = cv2.getRotationMatrix2D(centerpoint,angle,1.0)
correct_image = cv2.warpAffine(img,rotate_mat,(img.shape[1],img.shape[0]),borderValue =(255,255,255) )

cv2.imshow('right',correct_image)
cv2.waitKey(0)

图像倾斜矫正

Z轴倾斜

import cv2
import numpy as np

def gray_and_bin(init_img):
    gray_img = cv2.cvtColor(init_img, cv2.COLOR_BGR2GRAY)
    blur_img = cv2.GaussianBlur(gray_img, (3, 3), 0)                     # 高斯模糊去噪(设定卷积核大小影响效果)
    canny_img = cv2.Canny(blur_img, 35, 189, apertureSize=3)
    _, bin_img = cv2.threshold(canny_img, 127, 255, cv2.THRESH_BINARY)  # 设定阈值165(阈值影响开闭运算效果)
    return gray_img, bin_img

def points_and_box(init_img, bin_img):
    image, contours, hierarchy = cv2.findContours(bin_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    c = sorted(contours, key=cv2.contourArea, reverse=True)[0]   # 计算最大轮廓的旋转包围盒
    rect = cv2.minAreaRect(c)                                    # 获取包围盒(中心点,宽高,旋转角度)
    box = np.int0(cv2.boxPoints(rect))                           # box
    # box_img = cv2.drawContours(init_img.copy(), [box], -1, (0, 0, 255), 2)
    # cv2.imshow('box',box_img)

    empty_img = np.zeros(init_img.shape, np.uint8) # 创建空白图像
    empty_img[...] = 255 # 设置白底
    # cv2.imshow('test',empty_img)
    cv2.drawContours(empty_img, contours, -1, (0, 0, 0), 1) # 在空白图像上绘制试卷轮廓
    # cv2.imshow('edge', empty_img)
    _, bin_img2 = gray_and_bin(empty_img)
    # cv2.imshow('bin',bin_img2)
    lines = cv2.HoughLinesP(bin_img2, 1, np.pi / 180, 100, minLineLength=200, maxLineGap=10)

    for i in range(int(np.size(lines) / 4)):
        for x1, y1, x2, y2 in lines[i]:
            cv2.line(empty_img, (x1, y1), (x2, y2), (255, 255, 0), 1)
    # cv2.imshow('line',empty_img)

    points = None
    if len(contours) > 0:
        contours = sorted(contours, key=cv2.contourArea, reverse=True)
        for c in contours:
            peri = cv2.arcLength(c, True)  # 轮廓按大小降序排序
            approx = cv2.approxPolyDP(c, 0.02 * peri, True)  # 获取近似的轮廓
            if len(approx) == 4:  # 近似轮廓有四个顶点
                points = approx
                break

    print('piont[0]', points[0]) # 左下
    print('piont[1]', points[1]) # 左上
    print('piont[2]', points[2]) # 右上
    print('piont[3]', points[3]) # 右下

    print('box[0]:', box[0]) # 右下
    print('box[1]:', box[1]) # 右上
    print('box[2]:', box[2]) # 左上
    print('box[3]:', box[3]) # 左下

    return points,box

def perspective_transform(box,points,init_img):

    # 原图中试卷的四个顶点
    pts1 = np.float32([points[0], points[1], points[2], points[3]])
    # box中的四个顶点
    pts2 = np.float32([box[3], box[2], box[1], box[0]])

    # 生成透视变换矩阵;进行透视变换
    M = cv2.getPerspectiveTransform(pts1,pts2)
    result_img = cv2.warpPerspective(init_img, M, (1200, 1300))

    return result_img

if __name__=='__main__':
    init_img = cv2.imread('../image/init.jpg')
    gray_img, bin_img = gray_and_bin(init_img)
    points, box = points_and_box(init_img,bin_img)
    result_img = perspective_transform(box,points,init_img)
    # cv2.imshow('init',init_img)
    cv2.namedWindow('result', 0)
    cv2.resizeWindow('result', 640, 1200)
    cv2.imshow('result', result_img)
    # cv2.imwrite('result.jpg',result_img)
    cv2.waitKey(0)

图像倾斜矫正

图像倾斜矫正 以上结果,并不是很理想。透视矫正完成了,但是存在黑边白边,试卷长宽比例也有问题,也没有进行平面倾斜矫正。就先这样吧,作为一个小白,做成这样已经很不容易了。

更多内容参考 利用opencv库,实现校正图片中的A4纸用numpy+OpenCV快速实现矫正图像的功能OpenCV—python图像矫正对倾斜的图像进行修正——基于opencv透视变换

后记

图像倾斜矫正这部分,是图像预处理中的一个难点。以上,虽然实现了基本的图像倾斜矫正算法,但是算法原理还需要进一步学习。而且,上面的代码中使用的图片都是理想的,干扰很小,而实际拍摄的图片,除了目标物体(试卷),还会出现其他物体,比如签字笔文具盒等等。所以,后续还需要考虑其他物体的干扰。

另外,发现OpenCV成为了开发过程中的瓶颈,想要实现一些功能,每次都要求助于百度谷歌。因此,必须找时间系统学习一下OpenCV。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

XML Hacks

XML Hacks

Michael Fitzgerald / O'Reilly Media, Inc. / 2004-07-27 / USD 24.95

Developers and system administrators alike are uncovering the true power of XML, the Extensible Markup Language that enables data to be sent over the Internet from one computer platform to another or ......一起来看看 《XML Hacks》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

随机密码生成器
随机密码生成器

多种字符组合密码

SHA 加密
SHA 加密

SHA 加密工具