this has nothing to do with 2D/3D.
findContours gives you the coordinates of the boundary pixels of the blob. that’s different from the boundary itself.
you should consider the contours to mean this:
generally, pixel centers are integer values. pixel corners/edges sit half fractions away from the grid.
this way, if one were to draw a polygon from that contour data, which means drawing 1-pixel lines on those coordinates, one would get the blob boundary exactly.
I don’t think OpenCV has a function to calculate an offset on a contour, or to tell findContours to emit pixel edge coordinates.
OpenCV’s somewhat neglected and sloppy in those old parts, which also includes drawing (line thickness…). I’ve tried to call attention to it for bug fixes but some people flat out refused to understand what I was showing them. getStructuringElement for an ellipse also returns atrocious results but nobody else complains so nobody must be caring about precision.
calculating an offset to a contour isn’t a trivial operation. I think this would be solved better by an extension and flag to findContours so it emits pixel border coordinates.
here’s some demo of its behavior:
>>> im
array([[ 0, 0, 0, 0, 0],
[ 0, 255, 255, 0, 0],
[ 0, 255, 255, 255, 0],
[ 0, 255, 0, 0, 0],
[ 0, 0, 0, 0, 0]], dtype=uint8)
>>> cv.findContours(im, cv.RETR_LIST, cv.CHAIN_APPROX_NONE)
([array([[[1, 1]],
[[1, 2]],
[[1, 3]],
[[2, 2]],
[[3, 2]],
[[2, 1]]], dtype=int32)], array([[[-1, -1, -1, -1]]], dtype=int32))