@gzm1997
2017-11-29T12:12:15.000000Z
字数 3097
阅读 946
树媒技术基础作业
郭柱明 15331094
使用python语言,安装了numpy,pillow,opencv模块,版本如下:
import相关的模块
from PIL import Image
import cv2
import numpy
import math
import 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 = 20
maxLineGap = 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,k2
counter = 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 = 0
for l in point_set1:
x1 = l[0]
y1 = l[1]
x2 = l[2]
y2 = l[3]
b = ((y1 + y2) - (k1 * (x1 + x2))) / 2
if l1a == [] and l1b == []:
l1a.append([x1, y1, x2, y2])
b1_t = b
elif 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 = 0
for l in point_set2:
x1 = l[0]
y1 = l[1]
x2 = l[2]
y2 = l[3]
b = ((y1 + y2) - (k2 * (x1 + x2))) / 2
if l2a == [] and l2b == []:
l2a.append([x1, y1, x2, y2])
b3_t = b
elif 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 = 0
num1 = 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 = 0
num2 = 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 = 0
num3 = 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 = 0
num4 = 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) / 2
b_mean2 = (b3 + b4) / 2
x_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)
划线
结果