Ask Your Question
2

arclength and contourarea wrong results?

asked 2020-06-23 04:29:57 -0600

rsj44 gravatar image

updated 2020-06-23 05:58:20 -0600

I am using cv2's arclength and contourarea in my python project. To verify the results I've applied both functions to a discretized circle with r=100. The circumference of the circle should be around pi2100 = 628,31 and the area should be approximatly pi*100^2=31415.92.

Getting the circumference and area using cv2:

import numpy as np
import cv2

canvas = np.zeros((500, 500), dtype=np.uint8)
circle = cv2.circle(canvas, (250, 250) , 100, 10, -1)

contours, hierarchy = cv2.findContours(circle, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

for cnt in contours:
    circumference = cv2.arcLength(cnt, True)
    area = cv2.contourArea(cnt)
    print("c: %s" % circumference)
    print("area: %s" % area)

I would expect the estimations to be close to the theoretical value but it returns circumference=661.75 and area=31134, which both have quite a big error.

I've also estimated the area by simply counting the non-zero pixels:

area_nzp = np.count_nonzero(circle)
print(area_nzp)

Which returns area=31417, being much closer to the theoretical value.

I was wondering if anyone could tell me how to use arclength and contourarea in the "correct way" such that the error will become smaller. Thanks in advance.

Edit: Inspired by LBerger's comment I plotted the error between the error of theoretical surface value of the circle vs ContourArea and the area estimated by counting the non-zero pixels. I do not understand why ContourArea's error can be this big. Does anyone know what actually happens when the function is run?

error

edit retag flag offensive close merge delete

Comments

your circle is not an ideal one, but a bresenham approximation

try it with a rectangle, and it'll be exact

also, cv2.CHAIN_APPROX_SIMPLE

berak gravatar imageberak ( 2020-06-23 05:00:13 -0600 )edit

Thanks for your comment. The circle is not ideal but don't you agree that the error is too big? Especially in comparison with the estimation of the area by counting the non-zero pixels

rsj44 gravatar imagersj44 ( 2020-06-23 06:10:02 -0600 )edit

1 answer

Sort by ยป oldest newest most voted
1

answered 2020-06-23 05:22:01 -0600

LBerger gravatar image

updated 2020-06-23 05:23:33 -0600

Discrete geometry is not continuous geometry . you can plot theoritical and measure values :

image description You can estimate surface error using perimeter

For perimeter error is a function of contour length (number of pixel)

import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt

perimeter = []
surface = []
rayon = np.arange(2,450,10)
for r in rayon:
    img = np.zeros((1000,1000),np.uint8)
    img = cv.circle(img, (500, 500), r, 255, -1)
    ctr, hierarchy = cv.findContours(img, cv.RETR_EXTERNAL,  cv.CHAIN_APPROX_NONE) 
    if len(ctr) != 1:
        print('Must not occured')
    for c in ctr:
        surface.append(cv.contourArea(c))        
        perimeter.append(cv.arcLength(c, True))
print(surface)

plt.subplot(2, 1,1)
plt.plot(rayon, surface, 'b',marker = 11)
plt.plot(rayon, np.array(surface) + np.array(perimeter) , 'g',marker = 11)
plt.plot(rayon, rayon**2 * np.pi, 'r',marker = 10)
plt.title('Surface')
plt.ylabel('surface')
plt.xlabel('radius')
plt.legend(['min ContourArea','max ContourArea','theoritical'])
plt.subplot(2, 1,2)
plt.plot(rayon, surface - rayon**2 * np.pi, 'b',marker = 11)
plt.title('Surface error')
plt.ylabel('error')
plt.xlabel('radius')


plt.show()
plt.subplot(2, 1,1)
plt.plot(rayon, perimeter, 'b',marker = 11)
plt.plot(rayon, rayon*2 * np.pi, 'r',marker = 10)
plt.ylabel('perimeter')
plt.xlabel('radius')
plt.legend(['arcLength','theoritical'])
plt.subplot(2, 1,2)
plt.plot(rayon, perimeter - rayon*2 * np.pi, 'b',marker = 11)
plt.title('Perimeter error')
plt.ylabel('error')
plt.xlabel('radius')
plt.show()
edit flag offensive delete link more

Comments

Thank you for your answer. I understand that we are dealing with a discritized version of a circle, but what I don't understand is how the error can be so big. I made a similar plot as you did for the error between the theoretical area value and the value derived by counting the non-zero pixes (https://imgur.com/OiyyYLU).

rsj44 gravatar imagersj44 ( 2020-06-23 05:52:21 -0600 )edit

max surface error is 2piR(pixel^2) where pixel is equal to 1. in % error i/(2Rpixel^2)*100

LBerger gravatar imageLBerger ( 2020-06-23 09:42:11 -0600 )edit

Question Tools

1 follower

Stats

Asked: 2020-06-23 04:29:57 -0600

Seen: 1,427 times

Last updated: Jun 23 '20