检测图像的最外边缘并基于它进行绘图

时间:2017-12-12 16:45:43

标签: python opencv math image-processing angle

我正在开发一个可以通过图像计算肘关节角度的项目。我挣扎的部分是图像处理。

目前使用英特尔实感R200在Python中执行此操作(尽管我可以使用图像输入)。

我试图检测左图像的边缘,这样我就可以获得中心图像,旨在提取外部轮廓( >右图):

知道从角度出来的两个管道的两侧将是平行的(两个橙色侧面和两个绿色侧面平行于相同的颜色)...

...我试图从两对颜色等距离构建2个点的位点,然后“推断”到中间位置'为了计算角度:

我已经到了第二张图片,并且不可靠,直到第三张图片。我对建议非常开放,非常感谢任何帮助。

6 个答案:

答案 0 :(得分:3)

我会使用以下方法尝试找到问题中提供的四行。

<强> 1。阅读图像,并将其转换为灰度

import cv2
import numpy as np
rgb_img = cv2.imread('pipe.jpg')
height, width = gray_img.shape
gray_img = cv2.cvtColor(rgb_img, cv2.COLOR_BGR2GRAY)

<强> 2。在图像顶部添加一些白色填充(只是为了有一些额外的背景)

white_padding = np.zeros((50, width, 3))
white_padding[:, :] = [255, 255, 255]
rgb_img = np.row_stack((white_padding, rgb_img))

结果图片 - white padded image 3.反转灰度图像并在顶部应用黑色填充

gray_img = 255 - gray_img
gray_img[gray_img > 100] = 255
gray_img[gray_img <= 100] = 0
black_padding = np.zeros((50, width))
gray_img = np.row_stack((black_padding, gray_img))

Black padded image

4.使用形态学关闭来填充图像中的孔 -

kernel = np.ones((30, 30), np.uint8)
closing = cv2.morphologyEx(gray_img, cv2.MORPH_CLOSE, kernel)

closed image 5.使用Canny边缘检测 -

在图像中查找边缘
edges = cv2.Canny(closing, 100, 200)

pipe edges image 6.现在,我们可以使用openCV的HoughLinesP函数来查找给定图像中的行 -

minLineLength = 500
maxLineGap = 10
lines = cv2.HoughLinesP(edges, 1, np.pi / 180, 50, None, 50, 100)
all_lines = lines[0]
for x1,y1,x2,y2 in lines[0]:
    cv2.line(rgb_img,(x1,y1),(x2,y2),(0,0,255),2)

enter image description here 7.现在,我们必须找到最右边的两条水平线和两条最底部的垂直线。对于水平线,我们将使用两个(x2,x1)按降序对线进行排序。此排序列表中的第一行将是最右边的垂直线。如果我们采用接下来的两行,它们将是最右边的水平线。

all_lines_x_sorted = sorted(all_lines, key=lambda k: (-k[2], -k[0]))
for x1,y1,x2,y2 in all_lines_x_sorted[1:3]:
    cv2.line(rgb_img,(x1,y1),(x2,y2),(0,0,255),2)

horizontal lines image 8.同样,可以使用y1坐标按降序对行进行排序,排序列表中的前两行将是最下面的垂直行。

all_lines_y_sorted = sorted(all_lines, key=lambda k: (-k[1]))
for x1,y1,x2,y2 in all_lines_y_sorted[:2]:
    cv2.line(rgb_img,(x1,y1),(x2,y2),(0,0,255),2)

vertical lines image 9.两行图像 -

final_lines = all_lines_x_sorted[1:3] + all_lines_y_sorted[:2]

final lines

因此,获得这4行可以帮助您完成剩下的任务。

答案 1 :(得分:2)

似乎第二张图像的Hough transform应该给出两个强垂直(在Theta-Rho空间中)的簇,它们对应于平行线束。所以你可以确定主要方向。

以下是使用第二张图片和OpenCV函数HoughLines

进行快速测试的结果

enter image description here

然后,我计算了范围为0..180的所有方向(舍入为整数度)的行和带有count>1的打印结果。我们显然可以看到更大的计数在86-87和175-176度(注意差不多90度)

line 
angle : count
84: 3
85: 3
86: 8
87: 12
88: 3
102: 3
135: 3
140: 2
141: 2
165: 2
171: 4
172: 2
173: 2
175: 7
176: 17
177: 3

注意:我使用了HoughLines函数使用的任意Delphi示例并添加了方向计数。您可以获取this Python example并为theta值构建直方图

答案 2 :(得分:2)

正如你所看到的,二进制图像中的直线不是那么直,也有很多类似的线。因此,直接在此类图片上HoughLine a bad choice(3*w/4, h*2/3),而不是责任。

我尝试对图片进行二进制,删除左上角区域img = cv2.imread("img04.jpg", 0) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) th, threshed = cv2.threshold(gray, 100, 255, cv2.THRESH_BINARY_INV|cv2.THRESH_OTSU) H,W = img.shape[:2] threshed[:H*2//3,:W*3//4] = 0 cv2.imwrite("regions.png", threshed) ,然后我得到两个不同的区域:

enter image description here

<ion-buttons right>
<button ....>1</button>
<button ....>2</button>
<button ....>3</button>
</ion-buttons>

然后你可以随意做其他的后期步骤。

答案 3 :(得分:1)

目前尚不清楚这种几何形状是否固定或是否可能采用其他布局。

由于背景对象具有出色的对比度,您可以通过沿探测线找到第一个和最后一个过渡来检测几个点。

成对点给你一个方向。更多的点可以让你进行线条拟合,你可以使用橙色和绿色区域的所有点。甚至可以同时安装两条平行线。

请注意,如果您只需要一个角度,则无需找到管的轴。

enter image description here

答案 4 :(得分:1)

这已经有很多好的答案,但是没有人接受。我尝试了一些不同的东西,所以即使问题陈旧,也要考虑发布它。至少其他人可能会觉得这很有用。这仅适用于样本图像中的均匀背景。

  • 检测兴趣点(尝试不同的兴趣点检测器。我使用FAST)
  • 找到这些点的最小封闭三角形
  • 找到这个三角形的最大角度(是吗?)

这将给你一个粗略的估计。

对于样本图像,代码给出

90.868604
42.180990
46.950407

代码位于c++。如果您觉得有用,可以轻松移植它。

triangle

// helper function:
// finds a cosine of angle between vectors
// from pt0->pt1 and from pt0->pt2
static double angle( Point2f pt1, Point2f pt2, Point2f pt0 )
{
    double dx1 = pt1.x - pt0.x;
    double dy1 = pt1.y - pt0.y;
    double dx2 = pt2.x - pt0.x;
    double dy2 = pt2.y - pt0.y;
    return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);
}

int _tmain(int argc, _TCHAR* argv[])
{
    Mat rgb = imread("GmHqQ.jpg");

    Mat im;
    cvtColor(rgb, im, CV_BGR2GRAY);

    Ptr<FeatureDetector> detector = FastFeatureDetector::create();
    vector<KeyPoint> keypoints;
    detector->detect(im, keypoints);

    drawKeypoints(im, keypoints, rgb, Scalar(0, 0, 255));

    vector<Point2f> points;
    for (KeyPoint& kp: keypoints)
    {
        points.push_back(kp.pt);
    }

    vector<Point2f> triangle(3);
    minEnclosingTriangle(points, triangle);

    for (size_t i = 0; i < triangle.size(); i++)
    {
        line(rgb, triangle[i], triangle[(i + 1) % triangle.size()], Scalar(255, 0, 0), 2);
        printf("%f\n", acosf( angle(triangle[i], 
            triangle[(i + 1) % triangle.size()], 
            triangle[(i + 2) % triangle.size()]) ) * 180 / CV_PI);
    }

    return 0;
}

答案 5 :(得分:0)

可悲的是,你的方法不起作用,因为你通过这种方法计算的角度只是相机保持与关节平面完全垂直的实际角度。您需要在图像中使用参考方块,以便能够计算相机所处的角度,以便能够校正相机角度。参考方块必须与管接头放在同一平面上。