Ask Your Question
1

Python equivalent of vector<vector<Point≫?

asked 2018-02-13 16:09:57 -0600

AcrimoniousMirth gravatar image

Can't seem to find the equivalent of this:

 vector<vector<Point≫vectImage

as written by findContour. Is it vectImage = array{array{Point}}? If so can I:

  • Extract the Points (x and y)
  • Create a similar array: array{array{x,y,z}}
  • Append each Point's x and y values as well as an additional z

I hope I'm on the right track here, forgive my learning curve; I'm relatively new to programming at this level, let alone OpenCV.

Thank you for all the help :)

edit retag flag offensive close merge delete

1 answer

Sort by » oldest newest most voted
2

answered 2018-02-13 16:17:56 -0600

updated 2018-02-13 19:04:32 -0600

Refer to the Python documentation/tutorial.

When dealing with documentations in general, you want to understand the underlying use then figure out a way of doing it in another language. For this case for instance, in the C++ API you have to define the type. But in Python, this is not the case. This achieves the same task as the C++ version.

image, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

Now the contours are stored inside contours

EDIT I

A couple things.

  1. In OpenCV-Python, all images are stored as numpy arrays.
  2. Due to (1), on top of all the built-in OpenCV functionalities, you can leverage numpy's optimized library to perform quick array manipulations as well. My advise is that you familiarize yourself first with Numpy before moving on to OpenCV.

With that said, here's a small code snippet that addresses your problem and the comments should be self-explanatory.

# findContours returns a tuple
# The first index of this tuple is the image
# Second one holds the actual contours
# The last one gives the respective hierarchy of the contours
image, cnts, hierarchy = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
                        cv2.CHAIN_APPROX_SIMPLE)

# from all the contours, extract the largest based off of the area
c = max(cnts, key=cv2.contourArea)

# this will show you that it is an n-dimensional array
print 'Type of c', type(c)
print type(c[0]) # recall that this is a n-dimensional array so we
# have accessed the first row
print c[0][0] # for this row, extract the first column.
# Here is were you have accessed the x, y coordinates.

# Normally, you want this to be stored as a tuple 
# to preserve that beautiful (x, y) notation
point = tuple(c[0][0])
x, y = point # there are your coordinates
# you could also do point[0], point[1] to access the x and y respectively.
print x, y

Happy coding!

Cheers :)

edit flag offensive delete link more

Comments

Yes, that's true. And though the code snippet given is different from 80% of the examples given in some way or other (probably due to versioning), I understand that part. What I don't understand is how to access the underlying data; the Points, the X,Y coordinates of the vertices that define the contours. It's that data that's crucial to my program, as demonstrated by the list of operations I need to perform.

AcrimoniousMirth gravatar imageAcrimoniousMirth ( 2018-02-13 16:22:54 -0600 )edit

Also as a general rule I don't ask the forums till I'm at least 2 pages through google search results, because by then its clear the information isn't readily available or I'm failing to grasp the concept on a fundamental level :)

AcrimoniousMirth gravatar imageAcrimoniousMirth ( 2018-02-13 16:25:00 -0600 )edit

@AcrimoniousMirth check my edit

eshirima gravatar imageeshirima ( 2018-02-13 19:04:58 -0600 )edit

@eshirima thank you very very much, that was rather informative to read and I look forward to trying it out when I leave university this afternoon :) I’m a bit rushed for time given this is for my honours project but I’ll try and read up on Numpy in more detail too, as you say it will be very helpful. It’s very useful to know that the values before =findContours are tuples! My worry with using them later on is that they’re unordered and uneditable, right? I’ll comment again in more detail when I’m not half-paying attention to injection moulding :)

AcrimoniousMirth gravatar imageAcrimoniousMirth ( 2018-02-14 04:30:58 -0600 )edit

Ok, so c[0] is the "point" level? i.e. the index that holds the X and Y values?

Then c[0][0] is accessing the first index within that "point", i.e. the X value?

Thus c[0][1] would return the Y value, c[0][3] would return an out of range error?

And then to access the 2nd "point" X value would be c[1][0]

(just making sure I'm on the right page) :)

To then iterate and append through:

z = 1                 # For example
xyz = {}             
xyzPoints = {}   # Add z dimension to each value

for i in range (c):
     x, y = tuple(c[i][0])
     xyz[0], [1], [2] = x, y, z
     xyzPoints[i] = xyz

     # OR: xyzPoints[i][0],[i][1],[i][2] = x, y, z

Correct? :) Thank you for your patience!

AcrimoniousMirth gravatar imageAcrimoniousMirth ( 2018-02-14 11:30:09 -0600 )edit

EDIT: read above {} as [], still adjusting to the different notations, sorry!

It looks like I'm slightly off... what I said is true but its wrapped in another array, which I assume is meant to represent the contour (as each contour would be best held as a separate array to maintain individuality)?

So instead of c[point[x][y]] its actually c[contour[point[x][y]]]??

This makes what you said make more sense. Am I right in assuming the uppermost array is indeed the "contour"?

Thanks again. It's nice to have some clear data given and I'm finding writing out my understanding is helping clarify it :)

AcrimoniousMirth gravatar imageAcrimoniousMirth ( 2018-02-14 12:18:19 -0600 )edit

1: I do not really understand what you are trying to achieve with this but xyz[0], [1], [2] = x, y, z makes no sense. What you want is xyz[0], xyz[1], xyz[2] = x, y, z. 2: I would recommend you print out the returned value of c then print out c[0], then c[0][1] etc for you to truly understand what is happening. This will help you understand 2D arrays.

eshirima gravatar imageeshirima ( 2018-02-14 13:08:25 -0600 )edit
  1. Okay, for some background: My honours project is to create a 3D scanner-Printer hybrid in order to aid in the creation of prosthetic limbs. Patient sticks stump in, scan is taken, scan is used to make a prosthetic that fits perfectly, prosthetic is printed on the same machine. I've designed 3D printers before, both for myself and for startup companies, the design is a cinch, the programming is the main challenge! :)

The best way to do this, it turns out, is to have two lasers scanning from either side (call them front and back) and moving along that axis. Perpendicular are two cameras (in sides left and right) which for every distance the scanners move will take a photo of the silhouette the laser line creates. By using OpenCV and lumpy I can extract the lines and create an STL :)

AcrimoniousMirth gravatar imageAcrimoniousMirth ( 2018-02-14 15:17:19 -0600 )edit

2: my printout

contour:  [[[  0   0]]
[[ 95   0]]
[[ 96   1]]
..., 
[[638 170]]
[[639 169]]
[[639   0]]]
contour[1]:  [[95  0]]
contour[1][0]:  [95  0]
contour[1][0][0]:  95

contour[1][1] doesn't work (obviously). So it looks like each is double-stacked (contour[1] and contour[1][0] are effectively the same). And thank you for clarifying that, your help is very much appreciated :)

AcrimoniousMirth gravatar imageAcrimoniousMirth ( 2018-02-14 15:27:19 -0600 )edit

@AcrimoniousMirth I am not exactly sure what you meant by contour[1] and contour[1][0] are effectively the same but contour[1] != contour[1][0]. contour[1] returns an n-dimensional array plus you are simply accessing the contents inside the first row of the container contour. contour[1][0] returns the exact element in row 1 at column 0. I highly recommend you stop working on the OpenCV and review 2D-arrays then move on to n-dimensional arrays. Or else you'll just be guessing and end up confused the entire time.

eshirima gravatar imageeshirima ( 2018-02-14 20:10:47 -0600 )edit

Question Tools

1 follower

Stats

Asked: 2018-02-13 16:09:57 -0600

Seen: 9,607 times

Last updated: Feb 13 '18