是否有类似于 OpenCV findContours 的函数来检测曲线并用样条替换点?

sta*_*ter 6 python opencv matplotlib scipy

我正在尝试拍摄下面的图像,跟踪白色形状,并将生成的路径导出为 pdf。我遇到的问题是 findContours 似乎只能找到沿形状边缘的点。是否有类似于 findContours 的解决方案,可以检测形状中的曲线并在有曲线的地方用样条替换其点?如果我使用 scipy.interpolate 它会忽略直线并将整个轮廓变成一个大的弯曲形状,这也不好。我需要可以同时做两件事的东西。

import numpy as np
import cv2
from scipy.interpolate import splprep, splev
from pyx import *
import matplotlib.pyplot as plt

#read in image file                                                             
original = cv2.imread('test.jpg')

#blur the image to smooth edges                                                 
im = cv2.medianBlur(original,5)

#threshold the image                                                            
imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imgray,170,255,cv2.THRESH_BINARY)                                                             

#findContours                                                                   
im2, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_\
APPROX_SIMPLE)

#drawContours
cv2.drawContours(original, [approx], -1, (0,255,0), 3)                          
cv2.imshow("Imageee", original)                                                 
cv2.waitKey(0)
Run Code Online (Sandbox Code Playgroud)

Kin*_*t 金 5

除了使用cv2.findContourswith flagcv2.CHAIN_APPROX_SIMPLE来近似轮廓外,我们还可以手动完成。

  1. cv2.findContours与标志一起使用cv2.CHAIN_APPROX_NONE来查找轮廓。
  2. 用于cv2.arcLength计算轮廓长度。
  3. 使用cv2.approxPoolyDP手动近似轮廓epsilon = eps * arclen

这是以下情况下的结果之一eps=0.005

在此输入图像描述

更多结果:

在此输入图像描述


#!/usr/bin/python3
# 2018.01.04 13:01:24 CST
# 2018.01.04 14:42:58 CST

import cv2
import numpy as np
import os
img = cv2.imread("test.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret,threshed = cv2.threshold(gray,170,255,cv2.THRESH_BINARY)

# find contours without approx
cnts = cv2.findContours(threshed,cv2.RETR_LIST,cv2.CHAIN_APPROX_NONE)[-2]

# get the max-area contour
cnt = sorted(cnts, key=cv2.contourArea)[-1]

# calc arclentgh
arclen = cv2.arcLength(cnt, True)

# do approx
eps = 0.0005
epsilon = arclen * eps
approx = cv2.approxPolyDP(cnt, epsilon, True)

# draw the result
canvas = img.copy()
for pt in approx:
    cv2.circle(canvas, (pt[0][0], pt[0][1]), 7, (0,255,0), -1)

cv2.drawContours(canvas, [approx], -1, (0,0,255), 2, cv2.LINE_AA)

# save
cv2.imwrite("result.png", canvas)
Run Code Online (Sandbox Code Playgroud)


tfv*_*tfv 3

我认为你的问题实际上由两个问题组成。

第一个问题是提取轮廓,您可以使用 findContour 函数来实现:

import numpy as np

print cv2.__version__

rMaskgray = cv2.imread('test.jpg', 0)
(thresh, binRed) = cv2.threshold(rMaskgray, 200, 255, cv2.THRESH_BINARY)

_, Rcontours, hier_r = cv2.findContours(binRed,cv2.RETR_CCOMP,cv2.CHAIN_APPROX_SIMPLE)
r_areas = [cv2.contourArea(c) for c in Rcontours]
max_rarea = np.argmax(r_areas)
CntExternalMask = np.ones(binRed.shape[:2], dtype="uint8") * 255

contour= Rcontours[max_rarea]
cv2.drawContours(CntExternalMask,[contour],-1,0,1)
print "These are the contour points:"
print c
print
print "shape: ", c.shape

for p in contour:
    print p[0][0]
    cv2.circle(CntExternalMask, (p[0][0], p[0][1]), 5, (0,255,0), -1)

cv2.imwrite("contour.jpg", CntExternalMask)
cv2.imshow("Contour image", CntExternalMask)                                                 
cv2.waitKey(0)
Run Code Online (Sandbox Code Playgroud)

如果执行该程序,轮廓点将打印为点坐标列表。

您选择的轮廓近似方法会影响实际使用的插值(以及找到的点数),如此处所述。我在使用近似方法 cv2.CHAIN_APPROX_SIMPLE 找到的点处添加了小点。您会看到直线已经是近似的。

在此输入图像描述

不过,我可能不完全理解你的第二步。您想要省略其中一些点,用样条线部分替换点列表。根据您的最终意图,可能有不同的方法来做到这一点。您只想替换直线吗?如果更换弯曲零件,允许的误差范围是多少?