Python 旋转不完整的长方体,使其垂直

Python 旋转不完整的长方体,使其垂直,python,opencv,image-processing,Python,Opencv,Image Processing,我有一个x射线图像的数据集,我正试图通过旋转图像使手臂垂直并裁剪任何多余空间的图像来清理它。以下是数据集中的一些示例: 我目前正在研究出计算x射线角度的最佳方法,并基于此旋转图像 我目前的方法是使用hough变换检测扫描所在矩形边的直线,并基于该直线旋转图像 我尝试在canny边缘检测器的输出上运行hough变换,但对于矩形边缘模糊的图像(如第一幅图像)来说,这种方法效果不太好 我不能使用cv的框检测,因为有时扫描周围的矩形有一个离开屏幕的边缘 因此,我目前使用自适应阈值来找到长方体的边缘,然

我有一个x射线图像的数据集,我正试图通过旋转图像使手臂垂直并裁剪任何多余空间的图像来清理它。以下是数据集中的一些示例:

我目前正在研究出计算x射线角度的最佳方法,并基于此旋转图像

我目前的方法是使用hough变换检测扫描所在矩形边的直线,并基于该直线旋转图像

我尝试在canny边缘检测器的输出上运行hough变换,但对于矩形边缘模糊的图像(如第一幅图像)来说,这种方法效果不太好

我不能使用cv的框检测,因为有时扫描周围的矩形有一个离开屏幕的边缘

因此,我目前使用自适应阈值来找到长方体的边缘,然后对其进行中值滤波,并尝试在其中找到最长的线,但有时错误的线是最长的,并且图像旋转完全错误

由于soem扫描具有不同的亮度,因此使用自适应阈值

我目前的实施是:

def get_lines(img):
  #threshold
  thresh = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 15, 4.75)
  median = cv2.medianBlur(thresh, 3)
  # detect lines
  lines = cv2.HoughLines(median, 1, np.pi/180, 175)
  return sorted(lines, key=lambda x: x[0][0], reverse=True)

def rotate(image, angle):
  (h, w) = image.shape[:2]
  (cX, cY) = (w // 2, h // 2)

  M = cv2.getRotationMatrix2D((cX, cY), angle, 1.0)
  cos = np.abs(M[0, 0])
  sin = np.abs(M[0, 1])

  nW = int((h * sin) + (w * cos))
  nH = int((h * cos) + (w * sin))

  M[0, 2] += (nW / 2) - cX
  M[1, 2] += (nH / 2) - cY

  return cv2.warpAffine(image, M, (nW, nH))

def fix_rotation(input):
  lines = get_lines(input)
  rho, theta = lines[0][0]
  return rotate_bound(input, theta*180/np.pi)
并产生以下结果:

当它出错时:


我想知道是否有更好的技术可以用来提高性能,旋转后裁剪图像的最佳方法是什么?

您可以使用图像矩来计算旋转角度。 使用opencv函数,计算二阶中心矩以构造协方差矩阵,然后获得方向,如图像矩wiki页面所示。 从opencv
获取标准化中心矩
nu20
nu11
nu02
。然后将方向计算为

0.5*arctan(2*nu11/(nu20-nu02))

有关详细信息,请参阅给定的链接

可以使用原始图像本身或预处理图像来计算方向。看看哪一个给你更好的准确性,并使用它


至于边界框,旋转图像后,假设使用预处理的图像,获取旋转图像的所有非零像素坐标,并使用opencv计算其垂直边界框。

想法是使用手臂本身的斑点并在其周围拟合椭圆。然后,提取其长轴。我很快在Matlab中测试了这个想法,而不是OpenCV。这就是我所做的,您应该能够使用OpenCV的等效函数来实现类似的输出

首先,通过大津计算输入的阈值。然后对阈值添加一些偏差以找到更好的分割,并使用该值对图像进行阈值设置

在伪代码中:

//the bias value
threshBias = 0.4;

//get the binary threshold via otsu: 
thresholdLevel = graythresh( grayInput, “otsu” );

//add bias to the original value
thresholdLevel = thresholdLevel - threshSensitivity * thresholdLevel;

//get the fixed binary image: 
thresholdLevel = imbinarize( grayInput, thresholdLevel );
小水滴过滤后,这是输出:

现在,获取轮廓/斑点,并为每个轮廓拟合一个椭圆。请在此处查看OpenCV示例:

您将得到两个椭圆:

我们正在寻找最大的椭圆,一个面积最大,长轴和短轴最大的椭圆。我使用每个椭圆的宽度和高度来过滤结果。然后将目标椭圆涂成绿色。最后,我得到目标椭圆的长轴,这里用黄色表示:

现在,要在OpenCV中实现这些想法,您有以下选项:

  • 使用
    fitEllipse
    查找椭圆。此函数的返回值 函数是一个
    RotatedRect
    对象。这里存储的数据是 椭圆的顶点

  • 您可以尝试使用
    minareact
    ,而不是拟合椭圆 查找包围blob的最小面积的旋转矩形


共享链接以下载一些原始图像。请看,@karlphillip链接到一些图像是盒子的边缘肯定是人造的,不打算用于此任务。。。我想该方法应该使用实际的手臂并将其与轴对齐?谢谢你的回答,你能详细说明如何使用力矩来找到图像的旋转吗?@user6817585请按照我上面给出的方法进行操作。“中心力矩”部分给出了一个例子,清楚地解释了如何做到这一点。