opencv 图像最外边缘的检测与绘图

5f0d552i  于 2023-10-24  发布在  其他
关注(0)|答案(6)|浏览(150)

我正在做一个可以通过图像计算肘关节Angular 的项目。我正在努力的部分是图像处理。
目前在Python中使用英特尔实感R200(尽管可以认为我使用的是图像输入)。
我试图检测 * 左图像 * 的边缘,这样我就可以得到 * 中心图像 ,旨在提取外部轮廓( 右图像 *):

知道从Angular 出来的两个管道的边会平行(两个橙子边和两个绿色边平行于同一颜色).

.我试图构建2轨迹的点等距的两对颜色,然后'外推到中间',以计算Angular :

我已经得到了第二张图片,不可靠的是,我已经得到了第三张图片。我非常愿意接受建议,并将非常感谢任何帮助。

disho6za

disho6za1#

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

1.读取图片,转换为灰度

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

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

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

结果图像-x1c 0d1x 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))

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

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


5.使用Canny边缘检测查找图像中的边缘-

edges = cv2.Canny(closing, 100, 200)


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)

x1c4d 1x 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)


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)


9.两行图像-

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

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

agxfikkp

agxfikkp2#

这已经有很多好的答案了,但是没有一个被接受。我尝试了一些不同的东西,所以即使这个问题是旧的,我也想把它贴出来。至少其他人可能会觉得这很有用。只有当有像示例图像中一样漂亮的统一背景时,这才有效。

  • 检测兴趣点(尝试不同的兴趣点检测器。我使用FAST)
  • 求这些点的最小包围三角形
  • 求这个三角形的最大角(是吗?)

这将给你一个粗略的估计给予。
对于示例图像,代码给出

90.868604
42.180990
46.950407

代码在c++中。如果你觉得有用的话,你可以很容易地移植它。

// 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;
}
eoigrqb6

eoigrqb63#

目前还不清楚这种几何形状是否是固定的,或者其他布局是否可行。
由于对象与背景的对比度非常好,因此可以通过沿探测线找到第一个和最后一个过渡沿着来检测几个点。
成对的点给予方向。更多的点允许您进行线拟合,并且您可以使用橙子和绿色区域中的所有点。甚至可以同时拟合两条平行线。
请注意,如果您只需要一个Angular ,则不需要找到管的轴。

xggvc2p6

xggvc2p64#

正如你所看到的,二值图像中的线并不是那么直,而且有很多线是相似的。所以直接在这样的图像上做HoughLinea 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)

然后你可以做其他步骤后,你喜欢的。

ki0zmccv

ki0zmccv5#

看起来第二幅图的Hough transform应该给予两个强垂直(在Theta-Rho空间中)簇,对应于平行线束,所以你可以确定主方向。
下面是我使用第二个图像和OpenCV函数HoughLines进行快速测试的结果

然后我计算了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

注意事项:我已经使用任意 Delphi HoughLines函数用法和添加方向计数的例子。您可以获得this Python example并为theta值构建直方图

r6hnlfcb

r6hnlfcb6#

可悲的是,你的方法不起作用,因为如果相机与接头平面完全垂直,那么通过这种方法计算的Angular 只是实际Angular 。你需要在图像中使用参考正方形,以便能够计算相机的Angular ,从而能够校正相机Angular 。参考正方形必须放置在与管道相同的平面上关节

相关问题