如何编写用于图像角度计算的脚本?

时间:2017-05-23 08:48:56

标签: python opencv rotation computer-vision opencv-python

我有超过100张图片,每张图片都有不同的角度。我编写了一个基本的python代码,将每个图像从任意角度逐个旋转到零度(我的意思是让它们变平)。我附加的python代码是一个简单的代码,不幸的是它不会自动找到角度,也不会使它完全为零。任何一个图像的任何时候我都应该找到角度并运行代码多次以使其为零(有时我无法使其完全平坦或我们的零度数)。根据我附加的图像,image1是作为输入的样本图像之一,image_2是我想在结尾处作为输出的旋转图像。 我想问任何人可以帮我修改当前代码或者为我提供新的python代码(我更喜欢新代码),我可以让我的图像从任何角度旋转到零度。 如果你愿意,请随时向我询问更多解释。

我的opencv-python代码是:

import cv2
import numpy as np
img = cv2.imread('image1.tif')
num_rows, num_cols = img.shape[:2]
rotation_matrix = cv2.getRotationMatrix2D((num_cols/2, num_rows/2),69.4, 1)
img_rotation = cv2.warpAffine(img, rotation_matrix, (num_cols, num_rows))
cv2.imshow('Rotation', img_rotation)
cv2.imwrite('image_2.tif',img_rotation)
cv2.waitKey()

注意:输入和输出图像已删除。

2 个答案:

答案 0 :(得分:1)

它绝对不是最强大的方法,但也许可以选择:

  1. 假设边界全是黑色
  2. 识别图像的最顶部(x0,y0)/最右侧(x1,y1)角落
  3. 计算旋转角度为alpha = math.atan2(x1-x0,y1-y0)
  4. 我下载了你的数字(它在imgur上被转换为png)并用以下方法测试了程序:

    #!/usr/bin/env python
    import cv2
    import math
    
    import numpy as np
    
    img = cv2.imread('test.png')
    H, W = img.shape[:2]
    
    x0,y0 = None,None
    x1,y1 = None,None
    
    #scan all rows starting with the first
    for i in range(0, H):
        row = img[i].sum(axis=1)
        s = np.sum(row)
        if s:
            #if there is at least one non-black pixel, mark
            #its position
            x0 = np.max(np.where(row>0))
            y0 = i
            break
    
    #scan all columns starting with the right-most one
    for j in range(W-1,-1,-1):
        col = img[:,j,:].sum(axis=1)
        s = np.sum(col)
        if s:
            #mark the position of the first non-black pixel
            x1 = j
            y1 = np.min(np.where(col>0))
            break
    
    dx = x1 - x0
    dy = y1 - y0
    
    alpha = math.atan2(dx, dy) / math.pi * 180
    
    rotation_matrix = cv2.getRotationMatrix2D((W/2, H/2), -alpha, 1)
    img_rotation = cv2.warpAffine(img, rotation_matrix, (W, H))
    cv2.imwrite('image_2.tif',img_rotation)
    

    编辑:

    如果"角落"以前的方法可能不准确像素也是黑色,因此计算出的角度会被偏置。稍微更精确的方法可以如下:

    1. 确定"鞋帮"矩形的边界(即,定义边缘的像素的坐标)
    2. 取x轴上投影的边缘
    3. 拟合坐标以计算定义边缘的线的斜率
    4. 实施:

      #!/usr/bin/env python
      import cv2
      import math
      
      import numpy as np
      
      img = cv2.imread('test.png')
      H, W = img.shape[:2]
      
      data = []
      for j in range(0, W):
          col = img[:,j,:].sum(axis=1)
          s = np.sum(col)
          if not s:
              continue
      
          for i in range(0, H):
              if col[i] > 0:
                  data.append((j, i))
                  break
      
      y_min, min_pos = None, None
      for idx, (x, y) in enumerate(data):
          if y_min is None or y < y_min:
              y_min = y
              min_pos = idx
      
      N = len(data)
      if min_pos > N - min_pos:
          data = data[:min_pos]
      else:
          data = data[min_pos:]
      
      data = np.asarray(data).T
      coeffs = np.polyfit(data[0], data[1], 1)
      alpha = math.atan(coeffs[0]) / math.pi * 180
      
      print(alpha)
      
      rotation_matrix = cv2.getRotationMatrix2D((W/2, H/2), alpha, 1)
      img_rotation = cv2.warpAffine(img, rotation_matrix, (W, H))
      cv2.imwrite('image_2.tif',img_rotation)
      

答案 1 :(得分:0)

找到角度的另一种方法是(假设图像在黑色背景上):

  1. 将图像转换为灰度
  2. 使用阈值
  3. 分割图像
  4. 查找图像的轮廓
  5. 找到适合轮廓的椭圆参数

    import cv2
    import numpy as np
    
    image = cv2.imread("DlYEa.png")
    
    gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
    
    num_rows, num_cols = image.shape[:2]
    _, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY)
    
    img, contours, hier = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    
    cnt = contours[0]
    (x, y), (Ma, ma), angle = cv2.fitEllipse(cnt)
    
    angle = int(angle - 90)
    
    rotation_matrix = cv2.getRotationMatrix2D((num_cols/2, num_rows/2), angle, 1)
    img_rotation = cv2.warpAffine(image, rotation_matrix, (num_cols, num_rows))
    
    cv2.imshow("rotation", img_rotation)
    cv2.waitKey()
    cv2.destroyAllWindows()