内容简介:没有找到关于图像倾斜矫正的综述性文献,那就自己整理一下吧。图像倾斜可以分为两种情况,一种是平面倾斜,这种情况下拍照设备与试卷平行,拍出来的图像只需要进行旋转即可完成矫正;另一种是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]]])
参数说明:
- image:输入图像,二值化图像。
- mode:轮廓检索模式,请参阅 RetrievalModes 。
- method:轮廓近似方法,请参见 ContourApproximationModes 。
如果按照 官方文档 调用,会报错,参考 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。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
注意力经济: 如何把大众的注意力变成生意
吴修铭 / 中信出版集团股份有限公司 / 2018-4-1 / 69
编辑推荐 这本书由万维钢作序,并在《得到》日课中多次推荐!中文版未上市之前,中文前沿媒体就在力推这本书!关于注意力争夺战的历史和现在,作者给了权威的梳理和定位! 百年来,在争夺注意力的战场上,媒体、广告、商人、企业和大众成为博弈的主角。商人是如何在注意力争夺战中获利的?媒体是如何在改变报道形式的?广告是如何进化的?以及,营销是如何变得随处可见、无孔不入的呢?这本书讲述了令商人或企业从吸......一起来看看 《注意力经济: 如何把大众的注意力变成生意》 这本书的介绍吧!