1

I previously posted here

And I've seen this post

Despite the great information provided by the community, I have been unable to smoothly trace an image using cv2.findContours(). While in my previous post I asked about generating splines to smoothly trace curves, my focus now is to get a smooth trace of an object, regardless of how many points are generated for the contour. I consistently get results with jagged edges:

enter image description here

My desired output would be something similar to this, which I've manually created in Adobe Illustrator:

enter image description here

I have experimented extensively with blurring and thresholding, and have been unable to get a smooth outline. I am running openCV version 3.3.0.

import numpy as np
import cv2
import math
from reportlab.lib.pagesizes import letter
from reportlab.pdfgen import canvas

print(cv2.__version__)

im = cv2.imread('img.jpg')

# orient the image properly                                                      
# grab the dimensions of the image and calculate the center                     
# of the image                                                                  
(h, w) = im.shape[:2]
center = (w / 2, h / 2)

# rotate the image 180 degrees                                               
M = cv2.getRotationMatrix2D(center, 180, 1.0)
rotated = cv2.warpAffine(im, M, (w, h))

# flip the image across                                                          
flippedColor = cv2.flip(rotated, 1) #for testing                                
imgray = cv2.cvtColor(rotated, cv2.COLOR_BGR2GRAY)
flipped = cv2.flip(imgray, 1)

(thresh, binRed) = cv2.threshold(flipped, 180, 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(flippedColor,[contour],-1,(255,0,0),1)
statequarter
  • 141
  • 2
  • 9

2 Answers2

2

I can use this code to show you that effect.

import cv2

img = cv2.imread(r'E:/test_opencv/images/0ub4h.jpg')
imgray = cv2.cvtColor( img, cv2.COLOR_BGR2GRAY )
ret, thresh = cv2.threshold( imgray, 220, 255, cv2.THRESH_BINARY )
cv2.imshow('1',cv2.resize(thresh,(600,400)))
_, countours, hierarchy = cv2.findContours( thresh, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE )
cnt = sorted(countours, key=cv2.contourArea)[-1]
epsilon = 0.1 * cv2.arcLength( countours[0], True )
approx = cv2.approxPolyDP( cnt, epsilon, True )
cv2.drawContours( img, [approx],-1, (0, 255, 0), 3 )
cv2.imshow( "Contour", cv2.resize(img,(600,400)) )
cv2.imwrite(r'E:/test.jpg',img)
cv2.waitKey( 0 )
cv2.destroyAllWindows()

enter image description here

2

This is my result. The green contour is the original, while the red contour is approximated and the gray dots are the approximated dots.

enter image description here


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

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

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

# approx the contour
epsilon = arclen * 0.001
epsilon = arclen * 0.0001
approx = cv2.approxPolyDP(cnt, epsilon, True)

cv2.drawContour(img, [approx], -1, (0,0,255), 1)

cv2.imwrite("res.png", img)

More details refer to my another answer: Is there a function similar to OpenCV findContours that detects curves and replaces points with a spline?

enter image description here

Kinght 金
  • 17,681
  • 4
  • 60
  • 74
  • Details refer to my another another link https://stackoverflow.com/questions/47936474/is-there-a-function-similar-to-opencv-findcontours-that-detects-curves-and-repla/48090026#48090026 – Kinght 金 Jan 04 '18 at 06:47
  • Have you had any luck with adaptive thresholding? – statequarter Jan 04 '18 at 15:32