首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将四边形(四边形)拟合成一个小块

将四边形(四边形)拟合成一个小块
EN

Stack Overflow用户
提问于 2016-12-14 08:32:12
回答 2查看 6.5K关注 0票数 10

在应用了不同的过滤和分割技术之后,我得到了这样的图像:

我可以访问一些轮廓检测函数,这些函数返回该对象边缘上的点列表,或者返回一个合适的多边形(但有许多边,超过4)。我想要一个四边形来适应这个形状,因为我知道它是一个鞋盒的正面,应该是一个四边形。由于透视视图,并行性是不保守的,所以我现在没有约束,只需要包含这个框的四个线段。

到目前为止,我所能找到的只是矩形拟合,它并没有真正返回我需要的结果,因为它迫使拟合的四边形是矩形的。

如果我能接触到相机与鞋盒的相对角度,并且知道鞋盒与相机之间的距离,我就能生成一个单形矩阵,并将图像扭曲,使鞋盒再次呈现长方形,但目前我无法获取这些信息,并希望完全基于视觉。

有什么已知的方法来解决这个问题吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-12-14 12:45:30

我建议采取以下步骤:

  1. threshold()图像
  2. 图像 -这将移除分割顶部和底部部分的黑线,并在下部去除更深的伪影。
  3. findContours()使用设置只检索外部轮廓(RETR_EXTERNAL)并简化输出(CHAIN_APPROX_SIMPLE)
  4. 进一步处理等高线

步骤1:阈值

代码语言:javascript
复制
# threshold image
ret,thresh = cv2.threshold(img,127,255,0)
cv2.imshow('threshold ',thresh)

步骤2:扩展

代码语言:javascript
复制
# dilate thresholded image - merges top/bottom 
kernel = np.ones((3,3), np.uint8)
dilated = cv2.dilate(thresh, kernel, iterations=3)
cv2.imshow('threshold dilated',dilated)

步骤3:查找轮廓

代码语言:javascript
复制
# find contours
contours, hierarchy = cv2.findContours(dilated,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(img, contours, 0, (255,255,255), 3)
print "contours:",len(contours)
print "largest contour has ",len(contours[0]),"points"

注意,首先扩展,然后使用简单的外部轮廓可以使您的形状,但它仍然是相当复杂的(共279点)

从现在开始,您可以进一步处理轮廓特征。有一些可供选择的办法,例如:

a:拿到最低工资。面积矩形

代码语言:javascript
复制
# minAreaRect
rect = cv2.minAreaRect(contours[0])
box = cv2.cv.BoxPoints(rect)
box = np.int0(box)
cv2.drawContours(img,[box],0,(255,255,255),3)

可能很有用,但并不完全是你所需要的。

b:凸壳

代码语言:javascript
复制
# convexHull
hull = cv2.convexHull(contours[0])
cv2.drawContours(img, [hull], 0, (255,255,255), 3)
print "convex hull has ",len(hull),"points"

更好,但你还有22分要处理,而且不太紧

c:简化等高线

代码语言:javascript
复制
# simplify contours

epsilon = 0.1*cv2.arcLength(contours[0],True)
approx = cv2.approxPolyDP(contours[0],epsilon,True)
cv2.drawContours(img, [approx], 0, (255,255,255), 3)
print "simplified contour has",len(approx),"points"

这可能就是你想要的:只要4分。如果你需要更多的分数,你可以使用epsilon值。

记住,现在你有了一个四边形,但是图片是扁平的:没有关于透视/3D旋转的信息。

完整的OpenCV Python代码清单(如有需要,请使用该引用来适应c++/java/等):

代码语言:javascript
复制
import numpy as np
import cv2

img = cv2.imread('XwzWQ.png',0)

# threshold image
ret,thresh = cv2.threshold(img,127,255,0)
cv2.imshow('threshold ',thresh)

# dilate thresholded image - merges top/bottom 
kernel = np.ones((3,3), np.uint8)
dilated = cv2.dilate(thresh, kernel, iterations=3)
cv2.imshow('threshold dilated',dilated)

# find contours
contours, hierarchy = cv2.findContours(dilated,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
# cv2.drawContours(img, contours, 0, (255,255,255), 3)
print "contours:",len(contours)
print "largest contour has ",len(contours[0]),"points"

# minAreaRect
# rect = cv2.minAreaRect(contours[0])
# box = cv2.cv.BoxPoints(rect)
# box = np.int0(box)
# cv2.drawContours(img,[box],0,(255,255,255),3)

# convexHull
# hull = cv2.convexHull(contours[0])
# cv2.drawContours(img, [hull], 0, (255,255,255), 3)
# print "convex hull has ",len(hull),"points"

# simplify contours
epsilon = 0.1*cv2.arcLength(contours[0],True)
approx = cv2.approxPolyDP(contours[0],epsilon,True)
cv2.drawContours(img, [approx], 0, (255,255,255), 3)
print "simplified contour has",len(approx),"points"


# display output 
cv2.imshow('image',img)

cv2.waitKey(0)
cv2.destroyAllWindows()
票数 33
EN

Stack Overflow用户

发布于 2022-11-29 21:14:23

一个更准确的方法,以适应任意掩码四边形是使用技术来自目标图像面积最大化的优化视图

这是输出-

代码语言:javascript
复制
import cv2
import numpy as np
import sympy


def appx_best_fit_ngon(mask_cv2, n: int = 4) -> list[(int, int)]:
    # convex hull of the input mask
    mask_cv2_gray = cv2.cvtColor(mask_cv2, cv2.COLOR_RGB2GRAY)
    contours, _ = cv2.findContours(
        mask_cv2_gray, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE
    )
    hull = cv2.convexHull(contours[0])
    hull = np.array(hull).reshape((len(hull), 2))

    # to sympy land
    hull = [sympy.Point(*pt) for pt in hull]

    # run until we cut down to n vertices
    while len(hull) > n:
        best_candidate = None

        # for all edges in hull ( <edge_idx_1>, <edge_idx_2> ) ->
        for edge_idx_1 in range(len(hull)):
            edge_idx_2 = (edge_idx_1 + 1) % len(hull)

            adj_idx_1 = (edge_idx_1 - 1) % len(hull)
            adj_idx_2 = (edge_idx_1 + 2) % len(hull)

            edge_pt_1 = sympy.Point(*hull[edge_idx_1])
            edge_pt_2 = sympy.Point(*hull[edge_idx_2])
            adj_pt_1 = sympy.Point(*hull[adj_idx_1])
            adj_pt_2 = sympy.Point(*hull[adj_idx_2])

            subpoly = sympy.Polygon(adj_pt_1, edge_pt_1, edge_pt_2, adj_pt_2)
            angle1 = subpoly.angles[edge_pt_1]
            angle2 = subpoly.angles[edge_pt_2]

            # we need to first make sure that the sum of the interior angles the edge
            # makes with the two adjacent edges is more than 180°
            if sympy.N(angle1 + angle2) <= sympy.pi:
                continue

            # find the new vertex if we delete this edge
            adj_edge_1 = sympy.Line(adj_pt_1, edge_pt_1)
            adj_edge_2 = sympy.Line(edge_pt_2, adj_pt_2)
            intersect = adj_edge_1.intersection(adj_edge_2)[0]

            # the area of the triangle we'll be adding
            area = sympy.N(sympy.Triangle(edge_pt_1, intersect, edge_pt_2).area)
            # should be the lowest
            if best_candidate and best_candidate[1] < area:
                continue

            # delete the edge and add the intersection of adjacent edges to the hull
            better_hull = list(hull)
            better_hull[edge_idx_1] = intersect
            del better_hull[edge_idx_2]
            best_candidate = (better_hull, area)

        if not best_candidate:
            raise ValueError("Could not find the best fit n-gon!")

        hull = best_candidate[0]

    # back to python land
    hull = [(int(x), int(y)) for x, y in hull]

    return hull

这是我用来生成这个图像的代码-

代码语言:javascript
复制
hull = appx_best_fit_ngon(mask_cv2)

for idx in range(len(hull)):
    next_idx = (idx + 1) % len(hull)
    cv2.line(mask_cv2, hull[idx], hull[next_idx], (0, 255, 0), 1)

for pt in hull:
    cv2.circle(mask_cv2, pt, 2, (255, 0, 0), 2)
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41138000

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档