@gzm1997
2017-11-29T04:12:15.000000Z
字数 3097
阅读 1210
树媒技术基础作业
郭柱明 15331094
使用python语言,安装了numpy,pillow,opencv模块,版本如下:
import相关的模块
from PIL import Imageimport cv2import numpyimport mathimport collections
边缘提取
#打开原图像img = cv2.imread("input.jpg")#用3*3的高斯滤波器进行平滑处理img = cv2.GaussianBlur(img, (3, 3), 0)#使用opencv的canny函数进行边缘提取edges = cv2.Canny(img, 50, 150, apertureSize = 3)
霍夫曼划线
#经验参数minLineLength = 20maxLineGap = 20#使用opencv的HoughLinesP函数检测直线,返回值为直线(x1, y1, x2, y2)的集合,其中(x1, y1)为始点,(x2, y2)为终点lines = cv2.HoughLinesP(edges, 1, numpy.pi / 180, 80, minLineLength, maxLineGap)
根据斜率和y=kx+b的b值找到纸张四条边上的点
#计算斜率,斜率ks为所有检测到的线的斜率集合ks = []for l in lines:for y1, x1, y2, x2 in l:k = float(y1 - y2) / float(x1 - x2)ks.append(k)#使用collections.Counter计算每个斜率出现的次数counter = dict(collections.Counter(ks))#根据直线的斜率出现的次数进行排序,获取次数最多的两个斜率分别为k1,k2counter = sorted(counter.items(), key = lambda d: d[1], reverse = True)if len(counter) >= 2:k1 = counter[0][0]k2 = counter[1][0]#根据k1,k2把所有检测到直线的(x1, y1, x2, y2)进行分类,分为point_set1和point_set2,分别代表纸张两对平行线上的点point_set1 = []point_set2 = []for l in lines:for y1, x1, y2, x2 in l:tk = float(y1 - y2) / float(x1 - x2)if abs(tk - k1) <= 0.13:point_set1.append([x1, y1, x2, y2])elif abs(tk - k2) <= 0.2:point_set2.append([x1, y1, x2, y2])#对每一对平行线上的点根据y=kx+b公式算出其b值,再次分类,l1a和l1b分别表示两条平行线上的点l1a = []l1b = []b1_t = 0for l in point_set1:x1 = l[0]y1 = l[1]x2 = l[2]y2 = l[3]b = ((y1 + y2) - (k1 * (x1 + x2))) / 2if l1a == [] and l1b == []:l1a.append([x1, y1, x2, y2])b1_t = belif abs(b - b1_t) <= 5:l1a.append([x1, y1, x2, y2])else:l1b.append([x1, y1, x2, y2])#对每一对平行线上的点根据y=kx+b公式算出其b值,再次分类,l2a和l2b分别表示两条平行线上的点l2a = []l2b = []b3_t = 0for l in point_set2:x1 = l[0]y1 = l[1]x2 = l[2]y2 = l[3]b = ((y1 + y2) - (k2 * (x1 + x2))) / 2if l2a == [] and l2b == []:l2a.append([x1, y1, x2, y2])b3_t = belif abs(b - b3_t) <= 5:l2a.append([x1, y1, x2, y2])else:l2b.append([x1, y1, x2, y2])
根据公式y=kx+b对纸每条张边上的直线求b值,用b1,b2,b3,b4表示
#根据公式y=kx+b对l1a这条纸张边上的直线求b值,用b1表示b1 = 0num1 = len(l1a)for l in l1a:x1 = l[0]y1 = l[1]x2 = l[2]y2 = l[3]b1 += ((y1 + y2) - (k1 * (x1 + x2))) / (2 * num1)#根据公式y=kx+b对l1b这条纸张边上的直线求b值,用b2表示b2 = 0num2 = len(l1b)for l in l1b:x1 = l[0]y1 = l[1]x2 = l[2]y2 = l[3]b2 += ((y1 + y2) - (k1 * (x1 + x2))) / (2 * num2)#根据公式y=kx+b对l2a这条纸张边上的直线求b值,用b3表示b3 = 0num3 = len(l2a)for l in l2a:x1 = l[0]y1 = l[1]x2 = l[2]y2 = l[3]b3 += ((y1 + y2) - (k2 * (x1 + x2))) / (2 * num3)#根据公式y=kx+b对l2b这条纸张边上的直线求b值,用b4表示b4 = 0num4 = len(l2b)for l in l2b:x1 = l[0]y1 = l[1]x2 = l[2]y2 = l[3]b4 += ((y1 + y2) - (k2 * (x1 + x2))) / (2 * num4)print("x1, y1, x2, y2", x1, y1, x2, y2)
求出纸张的中点和跟垂直方向的倾斜角度
#跟据两对平行线中间的平行线相交得到一点,那点为纸张中点b_mean1 = (b1 + b2) / 2b_mean2 = (b3 + b4) / 2x_center = int((b_mean2 - b_mean1) / (k1 - k2))y_center = int(k1 * x_center + b_mean1)#求出纸张的宽和高height = int(abs(b3 - b4) / math.pow((math.pow(k2, 2) + 1), 0.5))width = int(abs(b1 - b2) / math.pow((math.pow(k1, 2) + 1), 0.5))#求出纸张跟垂直方向偏离的角度theta = numpy.pi / 2 - math.atan(k2)
构造旋转矩阵,使用cv2.warpAffine函数旋转图像
#建立旋转矩阵mapping,把纸张上的像素点映射到输出图像中def subimage(image, center, theta, width, height):v_x = (math.cos(theta), math.sin(theta))v_y = (-math.sin(theta), math.cos(theta))s_x = center[0] - v_x[0] * ((width-1) / 2) - v_y[0] * ((height-1) / 2)s_y = center[1] - v_x[1] * ((width-1) / 2) - v_y[1] * ((height-1) / 2)mapping = numpy.array([[v_x[0],v_y[0], s_x], [v_x[1],v_y[1], s_y]])return cv2.warpAffine(image, mapping, (width, height), flags = cv2.WARP_INVERSE_MAP, borderMode = cv2.BORDER_REPLICATE)#打开图像im = cv2.imread('input.jpg')#进行图像旋转patch = subimage(im, (y_center, x_center), theta, width, height)#展示结果图像cv2.imshow('patch.jpg', patch)
划线
结果
