[关闭]
@gzm1997 2017-11-29T12:12:15.000000Z 字数 3097 阅读 946

数字媒体技术作业1

树媒技术基础作业


郭柱明 15331094


实验环境

使用python语言,安装了numpy,pillow,opencv模块,版本如下:
image_1c02o27rf1s9i1hjv13aq1ldl1fom9.png-6.3kB


实验步骤

import相关的模块

  1. from PIL import Image
  2. import cv2
  3. import numpy
  4. import math
  5. import collections

边缘提取

  1. #打开原图像
  2. img = cv2.imread("input.jpg")
  3. #用3*3的高斯滤波器进行平滑处理
  4. img = cv2.GaussianBlur(img, (3, 3), 0)
  5. #使用opencv的canny函数进行边缘提取
  6. edges = cv2.Canny(img, 50, 150, apertureSize = 3)

霍夫曼划线

  1. #经验参数
  2. minLineLength = 20
  3. maxLineGap = 20
  4. #使用opencv的HoughLinesP函数检测直线,返回值为直线(x1, y1, x2, y2)的集合,其中(x1, y1)为始点,(x2, y2)为终点
  5. lines = cv2.HoughLinesP(edges, 1, numpy.pi / 180, 80, minLineLength, maxLineGap)

根据斜率和y=kx+b的b值找到纸张四条边上的点

  1. #计算斜率,斜率ks为所有检测到的线的斜率集合
  2. ks = []
  3. for l in lines:
  4. for y1, x1, y2, x2 in l:
  5. k = float(y1 - y2) / float(x1 - x2)
  6. ks.append(k)
  7. #使用collections.Counter计算每个斜率出现的次数
  8. counter = dict(collections.Counter(ks))
  9. #根据直线的斜率出现的次数进行排序,获取次数最多的两个斜率分别为k1,k2
  10. counter = sorted(counter.items(), key = lambda d: d[1], reverse = True)
  11. if len(counter) >= 2:
  12. k1 = counter[0][0]
  13. k2 = counter[1][0]
  14. #根据k1,k2把所有检测到直线的(x1, y1, x2, y2)进行分类,分为point_set1和point_set2,分别代表纸张两对平行线上的点
  15. point_set1 = []
  16. point_set2 = []
  17. for l in lines:
  18. for y1, x1, y2, x2 in l:
  19. tk = float(y1 - y2) / float(x1 - x2)
  20. if abs(tk - k1) <= 0.13:
  21. point_set1.append([x1, y1, x2, y2])
  22. elif abs(tk - k2) <= 0.2:
  23. point_set2.append([x1, y1, x2, y2])
  24. #对每一对平行线上的点根据y=kx+b公式算出其b值,再次分类,l1a和l1b分别表示两条平行线上的点
  25. l1a = []
  26. l1b = []
  27. b1_t = 0
  28. for l in point_set1:
  29. x1 = l[0]
  30. y1 = l[1]
  31. x2 = l[2]
  32. y2 = l[3]
  33. b = ((y1 + y2) - (k1 * (x1 + x2))) / 2
  34. if l1a == [] and l1b == []:
  35. l1a.append([x1, y1, x2, y2])
  36. b1_t = b
  37. elif abs(b - b1_t) <= 5:
  38. l1a.append([x1, y1, x2, y2])
  39. else:
  40. l1b.append([x1, y1, x2, y2])
  41. #对每一对平行线上的点根据y=kx+b公式算出其b值,再次分类,l2a和l2b分别表示两条平行线上的点
  42. l2a = []
  43. l2b = []
  44. b3_t = 0
  45. for l in point_set2:
  46. x1 = l[0]
  47. y1 = l[1]
  48. x2 = l[2]
  49. y2 = l[3]
  50. b = ((y1 + y2) - (k2 * (x1 + x2))) / 2
  51. if l2a == [] and l2b == []:
  52. l2a.append([x1, y1, x2, y2])
  53. b3_t = b
  54. elif abs(b - b3_t) <= 5:
  55. l2a.append([x1, y1, x2, y2])
  56. else:
  57. l2b.append([x1, y1, x2, y2])

根据公式y=kx+b对纸每条张边上的直线求b值,用b1,b2,b3,b4表示

  1. #根据公式y=kx+b对l1a这条纸张边上的直线求b值,用b1表示
  2. b1 = 0
  3. num1 = len(l1a)
  4. for l in l1a:
  5. x1 = l[0]
  6. y1 = l[1]
  7. x2 = l[2]
  8. y2 = l[3]
  9. b1 += ((y1 + y2) - (k1 * (x1 + x2))) / (2 * num1)
  10. #根据公式y=kx+b对l1b这条纸张边上的直线求b值,用b2表示
  11. b2 = 0
  12. num2 = len(l1b)
  13. for l in l1b:
  14. x1 = l[0]
  15. y1 = l[1]
  16. x2 = l[2]
  17. y2 = l[3]
  18. b2 += ((y1 + y2) - (k1 * (x1 + x2))) / (2 * num2)
  19. #根据公式y=kx+b对l2a这条纸张边上的直线求b值,用b3表示
  20. b3 = 0
  21. num3 = len(l2a)
  22. for l in l2a:
  23. x1 = l[0]
  24. y1 = l[1]
  25. x2 = l[2]
  26. y2 = l[3]
  27. b3 += ((y1 + y2) - (k2 * (x1 + x2))) / (2 * num3)
  28. #根据公式y=kx+b对l2b这条纸张边上的直线求b值,用b4表示
  29. b4 = 0
  30. num4 = len(l2b)
  31. for l in l2b:
  32. x1 = l[0]
  33. y1 = l[1]
  34. x2 = l[2]
  35. y2 = l[3]
  36. b4 += ((y1 + y2) - (k2 * (x1 + x2))) / (2 * num4)
  37. print("x1, y1, x2, y2", x1, y1, x2, y2)

求出纸张的中点和跟垂直方向的倾斜角度

  1. #跟据两对平行线中间的平行线相交得到一点,那点为纸张中点
  2. b_mean1 = (b1 + b2) / 2
  3. b_mean2 = (b3 + b4) / 2
  4. x_center = int((b_mean2 - b_mean1) / (k1 - k2))
  5. y_center = int(k1 * x_center + b_mean1)
  6. #求出纸张的宽和高
  7. height = int(abs(b3 - b4) / math.pow((math.pow(k2, 2) + 1), 0.5))
  8. width = int(abs(b1 - b2) / math.pow((math.pow(k1, 2) + 1), 0.5))
  9. #求出纸张跟垂直方向偏离的角度
  10. theta = numpy.pi / 2 - math.atan(k2)

构造旋转矩阵,使用cv2.warpAffine函数旋转图像

  1. #建立旋转矩阵mapping,把纸张上的像素点映射到输出图像中
  2. def subimage(image, center, theta, width, height):
  3. v_x = (math.cos(theta), math.sin(theta))
  4. v_y = (-math.sin(theta), math.cos(theta))
  5. s_x = center[0] - v_x[0] * ((width-1) / 2) - v_y[0] * ((height-1) / 2)
  6. s_y = center[1] - v_x[1] * ((width-1) / 2) - v_y[1] * ((height-1) / 2)
  7. mapping = numpy.array([[v_x[0],v_y[0], s_x], [v_x[1],v_y[1], s_y]])
  8. return cv2.warpAffine(image, mapping, (width, height), flags = cv2.WARP_INVERSE_MAP, borderMode = cv2.BORDER_REPLICATE)
  9. #打开图像
  10. im = cv2.imread('input.jpg')
  11. #进行图像旋转
  12. patch = subimage(im, (y_center, x_center), theta, width, height)
  13. #展示结果图像
  14. cv2.imshow('patch.jpg', patch)

实验结果

划线
line.jpg-117.4kB
结果
patch.jpg-43.7kB

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注