繁体   English   中英

使用 OpenCV(基于霍夫变换或其他功能)编写稳健(颜色和大小不变)的圆检测

[英]Writing robust (color and size invariant) circle detection with OpenCV (based on Hough transform or other features)

我编写了以下非常简单的 python 代码来查找图像中的圆圈:

import cv
import numpy as np

WAITKEY_DELAY_MS = 10
STOP_KEY = 'q'

cv.NamedWindow("image - press 'q' to quit", cv.CV_WINDOW_AUTOSIZE);
cv.NamedWindow("post-process", cv.CV_WINDOW_AUTOSIZE);

key_pressed = False
while key_pressed != STOP_KEY:

    # grab image
    orig = cv.LoadImage('circles3.jpg')

    # create tmp images
    grey_scale = cv.CreateImage(cv.GetSize(orig), 8, 1)
    processed = cv.CreateImage(cv.GetSize(orig), 8, 1)


    cv.Smooth(orig, orig, cv.CV_GAUSSIAN, 3, 3)

    cv.CvtColor(orig, grey_scale, cv.CV_RGB2GRAY)

    # do some processing on the grey scale image
    cv.Erode(grey_scale, processed, None, 10)
    cv.Dilate(processed, processed, None, 10)
    cv.Canny(processed, processed, 5, 70, 3)
    cv.Smooth(processed, processed, cv.CV_GAUSSIAN, 15, 15)

    storage = cv.CreateMat(orig.width, 1, cv.CV_32FC3)

    # these parameters need to be adjusted for every single image
    HIGH = 50
    LOW = 140

    try: 
        # extract circles
        cv.HoughCircles(processed, storage, cv.CV_HOUGH_GRADIENT, 2, 32.0, HIGH, LOW)

        for i in range(0, len(np.asarray(storage))):
            print "circle #%d" %i
            Radius = int(np.asarray(storage)[i][0][2])
            x = int(np.asarray(storage)[i][0][0])
            y = int(np.asarray(storage)[i][0][1])
            center = (x, y)

            # green dot on center and red circle around
            cv.Circle(orig, center, 1, cv.CV_RGB(0, 255, 0), -1, 8, 0)
            cv.Circle(orig, center, Radius, cv.CV_RGB(255, 0, 0), 3, 8, 0)

            cv.Circle(processed, center, 1, cv.CV_RGB(0, 255, 0), -1, 8, 0)
            cv.Circle(processed, center, Radius, cv.CV_RGB(255, 0, 0), 3, 8, 0)

    except:
        print "nothing found"
        pass

    # show images
    cv.ShowImage("image - press 'q' to quit", orig)
    cv.ShowImage("post-process", processed)

    cv_key = cv.WaitKey(WAITKEY_DELAY_MS)
    key_pressed = chr(cv_key & 255)

从以下两个示例中可以看出,“寻圈质量”差异很大:

情况1:

输入1检测1后处理1

案例2:

输入2检测2后处理2

Case1 和 Case2 基本上是同一张图片,但是算法检测的圆还是不同的。 如果我向算法展示具有不同大小圆圈的图像,则圆圈检测甚至可能完全失败。 这主要是由于需要为每张新图片单独调整HIGHLOW参数。

因此我的问题是:使这个算法更健壮的各种可能性是什么? 它应该是大小和颜色不变的,以便检测不同颜色和不同大小的不同圆圈。 也许使用霍夫变换不是最好的做事方式? 有更好的方法吗?

以下内容基于我作为视觉研究员的经验。 从您的问题来看,您似乎对可能的算法和方法感兴趣,而只是对一段有效的代码感兴趣。 首先,我为您的示例图像提供了一个快速而肮脏的 Python 脚本,并显示了一些结果以证明它可能会解决您的问题。 在解决这些问题之后,我尝试回答您关于稳健检测算法的问题。

快速结果

一些带有检测到的圆圈的示例图像(除您之外的所有图像均从 flickr.com 下载并获得 CC 许可)(无需更改/调整任何参数,正是使用以下代码提取所有图像中的圆圈): 样本图像中检测到的斑点 1在样本图像 2 中检测到斑点很多圈子flickr 图像中的斑点 1

代码(基于 MSER Blob Detector)

这是代码:

import cv2
import math
import numpy as np

d_red = cv2.cv.RGB(150, 55, 65)
l_red = cv2.cv.RGB(250, 200, 200)

orig = cv2.imread("c.jpg")
img = orig.copy()
img2 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

detector = cv2.FeatureDetector_create('MSER')
fs = detector.detect(img2)
fs.sort(key = lambda x: -x.size)

def supress(x):
        for f in fs:
                distx = f.pt[0] - x.pt[0]
                disty = f.pt[1] - x.pt[1]
                dist = math.sqrt(distx*distx + disty*disty)
                if (f.size > x.size) and (dist<f.size/2):
                        return True

sfs = [x for x in fs if not supress(x)]

for f in sfs:
        cv2.circle(img, (int(f.pt[0]), int(f.pt[1])), int(f.size/2), d_red, 2, cv2.CV_AA)
        cv2.circle(img, (int(f.pt[0]), int(f.pt[1])), int(f.size/2), l_red, 1, cv2.CV_AA)

h, w = orig.shape[:2]
vis = np.zeros((h, w*2+5), np.uint8)
vis = cv2.cvtColor(vis, cv2.COLOR_GRAY2BGR)
vis[:h, :w] = orig
vis[:h, w+5:w*2+5] = img

cv2.imshow("image", vis)
cv2.imwrite("c_o.jpg", vis)
cv2.waitKey()
cv2.destroyAllWindows()

如您所见,它基于MSER blob 检测器。 除了简单地映射到灰度之外,代码不会对图像进行预处理。 因此,预计在您的图像中会丢失那些微弱的黄色斑点。

理论

简而言之:除了仅提供两个没有描述的示例图像之外,您不会告诉我们您对问题的了解。 在这里,我解释了为什么我以我的拙见,在询问什么是解决问题的有效方法之前获得有关问题的更多信息很重要。

回到主要问题:解决这个问题的最佳方法是什么? 让我们把它看成一个搜索问题。 为了简化讨论,假设我们正在寻找具有给定大小/半径的圆。 因此,问题归结为找到中心。 每个像素都是一个候选中心,因此,搜索空间包含所有像素。

P = {p1, ..., pn} 
P: search space
p1...pn: pixels

为了解决这个搜索问题,应该定义另外两个函数:

E(P) : enumerates the search space
V(p) : checks whether the item/pixel has the desirable properties, the items passing the check are added to the output list

假设算法的复杂度无关紧要,可以使用穷举搜索或蛮力搜索,其中 E 获取每个像素并传递给 V。在实时应用程序中,减少搜索空间并优化 V 的计算效率很重要.

我们离主要问题越来越近了。 我们如何定义 V,更准确地说,候选者的哪些属性应该是度量,以及如何解决将它们分成合意和不合意的二分法问题。 最常见的方法是找到一些属性,这些属性可用于基于属性的度量来定义简单的决策规则。 这就是你通过反复试验所做的。 您正在通过从正面和负面示例中学习来编程分类器。 这是因为您使用的方法不知道您想要做什么。 您必须调整/调整决策规则的参数和/或预处理数据,以便减少用于二分法问题的方法所使用的(理想候选者的)属性的变化。 您可以使用机器学习算法为给定的一组示例找到最佳参数值。 您可以使用从决策树到遗传编程的大量学习算法来解决这个问题。 您还可以使用学习算法为多种圆检测算法找到最佳参数值,并查看哪种算法的准确性更高。 这为您只需要收集样本图像的学习算法承担了主要负担。

另一个经常被忽视的提高鲁棒性的方法是利用额外容易获得的信息。 如果您以几乎为零的额外努力知道圆圈的颜色,则可以显着提高检测器的准确度。 如果您知道圆在平面上的位置并且想要检测成像的圆,您应该记住这两组位置之间的转换是由 2D 单应性描述的。 并且可以仅使用四个点来估计单应性。 然后,您可以提高鲁棒性以获得坚如磐石的方法。 特定领域知识的价值常常被低估。 这样看,在第一种方法中,我们尝试基于有限数量的样本来近似一些决策规则。 在第二种方法中,我们知道决策规则,只需要找到一种方法在算法中有效地利用它们。

概括

总而言之,有两种方法可以提高解决方案的准确性/稳健性:

  1. 基于工具:找到更易于使用的算法/参数数量更少/调整算法/使用机器学习算法自动化此过程
  2. 基于信息的:您是否使用了所有现成的信息? 在问题中,您没有提及您对问题的了解。

对于您共享的这两张图像,我将使用斑点检测器而不是 HT 方法。 对于背景减法,我建议尝试估计背景的颜色,因为在这两个图像中,它不会变化,而圆圈的颜色会有所不同。 而且大部分地区都是空的。

这是一个很好的建模问题。 我有以下建议/想法:

  1. 将图像拆分为 RGB,然后进行处理。
  2. 预处理。
  3. 动态参数搜索。
  4. 添加约束。
  5. 确定您要检测的内容。

更详细地:

1:如其他答案所述,直接转换为灰度会丢弃太多信息 - 任何与背景亮度相似的圆圈都将丢失。 单独或在不同的颜色空间中考虑颜色通道要好得多。 这里有两种方法:在每个预处理过的通道上HoughCircles执行HoughCircles ,然后组合结果,或者,处理通道,然后组合它们,然后操作HoughCircles 在下面的尝试中,我尝试了第二种方法,拆分为 RGB 通道,处理,然后组合。 组合时要小心过度饱和图像,我使用cv.And来避免这个问题(在这个阶段我的圆圈总是白色背景上的黑色圆环/圆盘)。

2:预处理非常棘手,而且通常最好玩。 我使用了AdaptiveThreshold ,这是一种非常强大的卷积方法,它可以通过基于局部平均值对像素进行阈值处理来增强图像中的边缘(类似的过程也发生在哺乳动物视觉系统的早期通路中)。 这也很有用,因为它减少了一些噪音。 我只通过一次使用dilate/erode 我保留了其他参数,就像你拥有它们一样。 似乎在HoughCircles之前使用Canny确实对查找“实心圆”有很大帮助,因此最好保留它。这种预处理非常繁重,可能会导致误报和更多“斑点圆”,但在我们的情况下这也许是可取的?

3:正如您所指出的,需要针对每个图像调整 HoughCircles 参数param2 (您的参数LOW )以获得最佳解决方案,实际上来自文档

它越小,检测到的假圆就越多。

问题是每个图像的最佳位置都不同。 我认为这里最好的方法是设置一个条件并搜索不同的param2值,直到满足这个条件。 您的图像显示非重叠圆,当param2太低时,我们通常会得到大量重叠圆。 所以我建议搜索:

非重叠和非包含圆的最大数量

所以我们一直用不同的param2值调用 HoughCircles 直到满足。 我在下面的示例中这样做,只是通过增加param2直到它达到阈值假设。 如果您执行二分搜索以查找何时满足,这将更快(并且相当容易做到),但是您需要小心异常处理,因为 opencv 经常为param2无辜外观值抛出错误(至少在我的安装)。 我们非常有用的一个不同的条件是圆的数量。

4:我们可以向模型添加更多约束吗? 我们可以告诉我们的模型的东西越多,我们就能让它检测圆的任务变得容易。 例如,我们是否知道:

  • 圈数。 - 即使是上限或下限也是有帮助的。
  • 圆圈、背景或“非圆圈”的可能颜色。
  • 它们的尺寸。
  • 它们可以出现在图像中的位置。

5:您图像中的某些斑点只能松散地称为圆圈! 考虑第二张图片中的两个“非圆形斑点”,我的代码找不到它们(很好!),但是……如果我对它们进行“Photoshop”处理,使它们更圆,我的代码可以找到它们……也许如果你想检测不是圆圈的东西,像Tim Lukins这样的不同方法可能会更好。

问题

通过进行大量预处理AdaptiveThresholding和“Canny”,图像中的特征可能会出现大量失真,这可能导致错误的圆检测或错误的半径报告。 例如,加工后的大型实心圆盘可能会出现环,因此 HughesCircles 可能会找到内环。 此外,即使是文档也指出:

...通常该函数可以很好地检测圆的中心,但是它可能无法找到正确的半径。

如果您需要更准确的半径检测,我建议使用以下方法(未实现):

  • 在原始图像上,来自报告的圆心的光线跟踪,在一个扩展的十字中(4 条光线:上/下/左/右)
  • 在每个 RGB 通道中单独执行此操作
  • 以合理的方式为每条光线的每个通道组合此信息(即根据需要翻转、偏移、缩放等)
  • 取每条光线前几个像素的平均值,使用它来检测光线发生显着偏差的位置。
  • 这 4 个点是圆周上点的估计值。
  • 使用这四个估计值来确定更准确的半径和中心位置(!)。
  • 这可以通过使用扩展环而不是四条射线来概括。

结果

最后的代码在很多时候都做得很好,这些例子是用如下所示的代码完成的:

检测第一张图片中的所有圆圈:在此处输入图片说明

应用canny过滤器之前预处理图像的外观(不同色环高度可见):在此处输入图片说明

在第二张图像中检测除两个(斑点)之外的所有物体:在此处输入图片说明

改变了第二张图像(斑点是圆形的,大椭圆形变得更圆,从而改善检测),全部检测到:在此处输入图片说明

在康定斯基这幅画中检测中心方面做得很好(由于边界条件,我找不到同心环)。在此处输入图片说明

代码:

import cv
import numpy as np

output = cv.LoadImage('case1.jpg')
orig = cv.LoadImage('case1.jpg')

# create tmp images
rrr=cv.CreateImage((orig.width,orig.height), cv.IPL_DEPTH_8U, 1)
ggg=cv.CreateImage((orig.width,orig.height), cv.IPL_DEPTH_8U, 1)
bbb=cv.CreateImage((orig.width,orig.height), cv.IPL_DEPTH_8U, 1)
processed = cv.CreateImage((orig.width,orig.height), cv.IPL_DEPTH_8U, 1)
storage = cv.CreateMat(orig.width, 1, cv.CV_32FC3)

def channel_processing(channel):
    pass
    cv.AdaptiveThreshold(channel, channel, 255, adaptive_method=cv.CV_ADAPTIVE_THRESH_MEAN_C, thresholdType=cv.CV_THRESH_BINARY, blockSize=55, param1=7)
    #mop up the dirt
    cv.Dilate(channel, channel, None, 1)
    cv.Erode(channel, channel, None, 1)

def inter_centre_distance(x1,y1,x2,y2):
    return ((x1-x2)**2 + (y1-y2)**2)**0.5

def colliding_circles(circles):
    for index1, circle1 in enumerate(circles):
        for circle2 in circles[index1+1:]:
            x1, y1, Radius1 = circle1[0]
            x2, y2, Radius2 = circle2[0]
            #collision or containment:
            if inter_centre_distance(x1,y1,x2,y2) < Radius1 + Radius2:
                return True

def find_circles(processed, storage, LOW):
    try:
        cv.HoughCircles(processed, storage, cv.CV_HOUGH_GRADIENT, 2, 32.0, 30, LOW)#, 0, 100) great to add circle constraint sizes.
    except:
        LOW += 1
        print 'try'
        find_circles(processed, storage, LOW)
    circles = np.asarray(storage)
    print 'number of circles:', len(circles)
    if colliding_circles(circles):
        LOW += 1
        storage = find_circles(processed, storage, LOW)
    print 'c', LOW
    return storage

def draw_circles(storage, output):
    circles = np.asarray(storage)
    print len(circles), 'circles found'
    for circle in circles:
        Radius, x, y = int(circle[0][2]), int(circle[0][0]), int(circle[0][1])
        cv.Circle(output, (x, y), 1, cv.CV_RGB(0, 255, 0), -1, 8, 0)
        cv.Circle(output, (x, y), Radius, cv.CV_RGB(255, 0, 0), 3, 8, 0)

#split image into RGB components
cv.Split(orig,rrr,ggg,bbb,None)
#process each component
channel_processing(rrr)
channel_processing(ggg)
channel_processing(bbb)
#combine images using logical 'And' to avoid saturation
cv.And(rrr, ggg, rrr)
cv.And(rrr, bbb, processed)
cv.ShowImage('before canny', processed)
# cv.SaveImage('case3_processed.jpg',processed)
#use canny, as HoughCircles seems to prefer ring like circles to filled ones.
cv.Canny(processed, processed, 5, 70, 3)
#smooth to reduce noise a bit more
cv.Smooth(processed, processed, cv.CV_GAUSSIAN, 7, 7)
cv.ShowImage('processed', processed)
#find circles, with parameter search
storage = find_circles(processed, storage, 100)
draw_circles(storage, output)
# show images
cv.ShowImage("original with circles", output)
cv.SaveImage('case1.jpg',output)

cv.WaitKey(0)

啊,是的……圆问题的旧颜色/大小不变量(又名霍夫变换太具体且不稳健)……

过去,我更多地依赖 OpenCV 的结构和形状分析功能。 您可以从“samples”文件夹中了解可能的内容 - 特别是fitellipse.pysquares.py

为了您的说明,我提供了这些示例的混合版本,并基于您的原始来源。 检测到的轮廓为绿色,拟合的椭圆为红色。

在此处输入图片说明

它还没有完全到位:

  • 预处理步骤需要稍微调整以检测更微弱的圆圈。
  • 您可以进一步测试轮廓以确定它是否是圆形...

祝你好运!

import cv
import numpy as np

# grab image
orig = cv.LoadImage('circles3.jpg')

# create tmp images
grey_scale = cv.CreateImage(cv.GetSize(orig), 8, 1)
processed = cv.CreateImage(cv.GetSize(orig), 8, 1)

cv.Smooth(orig, orig, cv.CV_GAUSSIAN, 3, 3)

cv.CvtColor(orig, grey_scale, cv.CV_RGB2GRAY)

# do some processing on the grey scale image
cv.Erode(grey_scale, processed, None, 10)
cv.Dilate(processed, processed, None, 10)
cv.Canny(processed, processed, 5, 70, 3)
cv.Smooth(processed, processed, cv.CV_GAUSSIAN, 15, 15)

#storage = cv.CreateMat(orig.width, 1, cv.CV_32FC3)
storage = cv.CreateMemStorage(0)

contours = cv.FindContours(processed, storage, cv.CV_RETR_EXTERNAL)
# N.B. 'processed' image is modified by this!

#contours = cv.ApproxPoly (contours, storage, cv.CV_POLY_APPROX_DP, 3, 1) 
# If you wanted to reduce the number of points...

cv.DrawContours (orig, contours, cv.RGB(0,255,0), cv.RGB(255,0,0), 2, 3, cv.CV_AA, (0, 0)) 

def contour_iterator(contour):
  while contour:
    yield contour
    contour = contour.h_next()

for c in contour_iterator(contours):
  # Number of points must be more than or equal to 6 for cv.FitEllipse2
  if len(c) >= 6:
    # Copy the contour into an array of (x,y)s
    PointArray2D32f = cv.CreateMat(1, len(c), cv.CV_32FC2)

    for (i, (x, y)) in enumerate(c):
      PointArray2D32f[0, i] = (x, y)

    # Fits ellipse to current contour.
    (center, size, angle) = cv.FitEllipse2(PointArray2D32f)

    # Convert ellipse data from float to integer representation.
    center = (cv.Round(center[0]), cv.Round(center[1]))
    size = (cv.Round(size[0] * 0.5), cv.Round(size[1] * 0.5))

    # Draw ellipse
    cv.Ellipse(orig, center, size, angle, 0, 360, cv.RGB(255,0,0), 2,cv.CV_AA, 0)

# show images
cv.ShowImage("image - press 'q' to quit", orig)
#cv.ShowImage("post-process", processed)
cv.WaitKey(-1)

编辑:

只是更新一下,我相信所有这些答案的一个主要主题是,有许多进一步的假设和约束可以应用于您试图识别为循环的内容 我自己的回答没有任何借口 - 无论是在低级预处理还是高级几何拟合中。 事实上,由于绘制方式或图像的非仿射/投影变换,以及它们渲染/捕获方式的其他属性(颜色、噪声、照明、边缘厚度) - 仅在一张图像中就会产生任意数量的可能候选圆。

还有更复杂的技术。 但他们会让你付出代价。 我个人喜欢 @fraxel 使用自适应阈值的想法。 这是快速、可靠且相当稳健的。 然后,您可以使用椭圆轴的简单比率测试进一步测试最终轮廓(例如使用 Hu 矩)或拟合 - 例如(((最小(大小)/最大(大小))> 0.7)。

与计算机视觉一样,实用主义、原则和简约之间存在紧张关系。 正如我喜欢告诉那些认为 CV 很容易的人,事实并非如此——它实际上是一个著名的AI 完整问题。 在此之外,您通常可以期待的最好的东西在大多数情况下都有效。

查看您的代码,我注意到以下内容:

  • 灰度转换。 我理解你为什么这样做,但意识到你在那里丢弃信息。 正如您在“后期处理”图像中看到的那样,黄色圆圈的强度与背景相同,只是颜色不同。

  • 去除噪声后的边缘检测(erae/dilate)。 这不应该是必要的; Canny 应该解决这个问题。

  • Canny 边缘检测。 你的“开放”圆有两条边,一条内边和一条外边。 由于它们相当接近,Canny 高斯滤波器可能会将它们加在一起。 如果不是,您将有两条边靠在一起。 即在 Canny 之前,你有空心圆和实心圆。 之后,您分别有 0/2 和 1 条边。 由于 Hough 再次调用 Canny,在第一种情况下,两条边可能会被平滑在一起(取决于初始宽度),这就是核心 Hough 算法可以相同对待空心圆和实心圆的原因。

所以,我的第一个建议是改变灰度映射。 不要使用强度,而是使用色调/饱和度/值。 此外,使用差分方法 - 您正在寻找边缘。 因此,计算HSV变换,平滑副本,然后取原始副本和平滑副本之间的差异。 这将为您提供每个点的dH, dS, dV值(色调、饱和度、值的局部变化)。 平方和相加得到一维图像,在所有边缘(内部和外部)附近都有峰值。

我的第二个建议是本地规范化,但我不确定这是否有必要。 这个想法是你并不特别关心你得到的边缘信号的确切值,无论如何它应该是二进制的(边缘与否)。 因此,您可以通过除以局部平均值(其中局部是边缘大小的数量级)来标准化每个值。

如您所知,霍夫变换使用“模型”来查找(通常)边缘检测图像中的某些特征。 HoughCircles的情况下,该模型是一个完美的圆。 这意味着可能不存在可以使其检测图片中更不规则和椭圆形的圆圈而不增加误报数量的参数组合。 另一方面,由于底层投票机制的原因,一个非封闭的正圆或带有“凹痕”的正圆可能会持续出现。 因此,根据您的预期输出,您可能想或不想使用此方法。

也就是说,我看到了一些可以帮助您使用此功能的方法:

  1. HoughCircles内部调用Canny ,所以我想你可以忽略那个调用。
  2. param1 (您称之为HIGH )通常初始化为200左右的值。 它用作内部调用Canny的参数: cv.Canny(processed, cannied, HIGH, HIGH/2) 像这样自己运行Canny以查看设置HIGH如何影响 Hough 变换处理的图像可能会有所帮助。
  3. param2 (您称之为LOW )通常在值100附近初始化。 它是霍夫变换累加器的投票阈值。 将其设置得更高意味着更多的误报,更低的误报。 我相信这是您想要开始摆弄的第一个。

参考: http : //docs.opencv.org/3.0-beta/modules/imgproc/doc/feature_detection.html#houghcircles

更新:实心圆:使用霍夫变换找到圆形后,您可以通过对边界颜色进行采样并将其与假设的圆内的一个或多个点进行比较来测试它们是否被填充。 或者,您可以将假定圆圈内的一个或多个点与给定的背景颜色进行比较。 如果前一个比较成功,则圆圈被填充,如果替代比较失败,则圆圈被填充。

好的,看看图片。 我建议使用**Active Contours**

  • 活动轮廓 活动轮廓的好处是它们几乎完美地适合任何给定的形状。 无论是正方形还是三角形,在您的情况下,它们都是完美的候选者。
  • 如果您能够提取圆的中心,那就太好了。 活动轮廓始终需要一个起点,它们可以从该点开始增长或缩小以适应。 中心不必总是与中心对齐。 稍微偏移一下还是可以的。
  • 在您的情况下,如果您让轮廓从中心向外生长,它们将停留在圆形边界上。
  • 请注意,增长或收缩的活动轮廓使用气球能量,这意味着您可以设置轮廓的方向,向内或向外。
  • 您可能需要使用灰度渐变图像。 但是你仍然可以尝试颜色。 如果有效!
  • 如果您不提供中心,请投入大量活动轮廓,然后增长/缩小。 固定的轮廓被保留,未固定的轮廓被丢弃。 这是一种蛮力方法。 会不会占用CPU。 但是需要更仔细的工作以确保您留下正确的轮廓并丢弃坏的轮廓。

我希望通过这种方式您可以解决问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM