【问题标题】:Rotate Image to align features with X-axis in OpenCV Python在 OpenCV Python 中旋转图像以将特征与 X 轴对齐
【发布时间】:2021-05-25 17:50:47
【问题描述】:

在下面的显微镜图像中,我使用 OpenCV 中的形态学算子提取了水平白线网格。我无法完全摆脱噪音,这就是为什么中间有一些白线。网格线需要平行于 x 轴。在显微读取过程中,无法保证完美的并行性。在这种情况下,线条从左到右略微向上移动。 如何使用 OpenCV 或任何其他 Python 包将线条重新对齐到 x 轴,使它们与图像的上下边缘平行?

我对 OpenCV 比较陌生,所以如果有人能告诉我哪些操作或功能有助于解决这个问题,我将不胜感激。

谢谢!

【问题讨论】:

  • 你想在形态学操作之前还是之后做对齐?可以上传预处理后的图片吗?
  • 为什么对齐?这足以建立网格顺序。提取与每个标记条相关的各个 ROI。
  • @ChristophRackwitz 你是对的。对于这个示例,这种方法也可以工作,实际上是我最初的方法。但这张图片只是样本的一个区域。其他区域有比这更多的嘈杂线,因此网格会丢失。所以我想找一个像这个一样网格线清晰可辨的区域,提取旋转矩阵,然后旋转整个图像。如果网格线平行于 x 轴,即使它们在噪声中不可见,也很容易跟踪它们。

标签: python opencv


【解决方案1】:

您可以拟合线条、获取平均角度并旋转图像。

建议的解决方案使用以下阶段:

  • 阈值(二值化)图像。
  • 应用闭合形态操作来连接线。
  • 寻找轮廓。
  • 迭代轮廓并为每个轮廓拟合一条线。
    计算每条线的角度,并构建角度列表。
  • 计算“接近中间角”的角度的平均角度。
  • 按平均角度旋转图像。

代码如下:

import cv2
import numpy as np
import math

img = cv2.imread("input.png", cv2.IMREAD_GRAYSCALE)  # Read input image as grayscale.

threshed = cv2.threshold(img, 0, 255, cv2.THRESH_OTSU)[1]  # threshold (binarize) the image

# Apply closing for connecting the lines
threshed = cv2.morphologyEx(threshed, cv2.MORPH_CLOSE, np.ones((1, 10)))

# Find contours
contours = cv2.findContours(threshed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[-2]  # [-2] indexing takes return value before last (due to OpenCV compatibility issues).

img2 = cv2.cvtColor(threshed, cv2.COLOR_GRAY2BGR)  # BGR image - used for drawing

angles = []  # List of line angles.

# Iterate the contours and fit a line for each contour
# Remark: consider ignoring small contours
for c in contours:
    vx, vy, cx, cy = cv2.fitLine(c, cv2.DIST_L2, 0, 0.01, 0.01) # Fit line
    w = img.shape[1]
    cv2.line(img2, (int(cx-vx*w), int(cy-vy*w)), (int(cx+vx*w), int(cy+vy*w)), (0, 255, 0))  # Draw the line for testing
    ang = (180/np.pi)*math.atan2(vy, vx) # Compute the angle of the line.
    angles.append(ang)

angles = np.array(angles)  # Convert angles to NumPy array.

# Remove outliers and 
lo_val, up_val = np.percentile(angles, (40, 60))  # Get the value of lower and upper 40% of all angles (mean of only 10 angles)
mean_ang = np.mean(angles[np.where((angles >= lo_val) & (angles <= up_val))])

print(f'mean_ang = {mean_ang}')  # -0.2424

M = cv2.getRotationMatrix2D((img.shape[1]//2, img.shape[0]//2), mean_ang, 1)  # Get transformation matrix - for rotating by mean_ang

img = cv2.warpAffine(img, M, (img.shape[1], img.shape[0]), cv2.INTER_CUBIC) # Rotate the image

# Display results
cv2.imshow('img2', img2)
cv2.imshow('img', img)
cv2.waitKey()
cv2.destroyAllWindows()

结果:
img2(用于测试):

img(旋转后):


注意:

  • 该代码只是一个示例 - 我不希望它能够解决您所有的显微镜图像。

【讨论】:

    最近更新 更多