How to use `cv2.findContours` in different OpenCV versions?
An alternative to work with 2.x 、3.x、4.x is:
cnts, hiers = cv2.findContours(...)[-2:]
Notice:
cv2.findContours
has changed since OpenCV 3.x
, but in OpenCV 4.0
it changes back!!!
In OpenCV 3.4:
findContours(image, mode, method[, contours[, hierarchy[, offset]]]) -> image, contours, hierarchy
In OpenCV 4.0:
findContours(image, mode, method[, contours[, hierarchy[, offset]]]) -> contours, hierarchy
Contours tuple must have length 2 or 3, otherwise OpenCV changed their cv2.findContours return signature yet again- find contour in a specific area
You are using imutils.grab_contours
wrong.
If you do the destructuring yourself, with (cnts, *_) = cv.findContours(...)
, then you don't need imutils
at all.
If you want to use imutils
anyway, you need to pass it the entire tuple (2-tuple or 3-tuple) returned by cv.findContours
, like so: cnts = imutils.grab_contours(cv.findContours(...))
OpenCV version 4.1.0 drawContours error: (-215:Assertion failed) npoints 0 in function 'drawContours'
Depending on the OpenCV version, cv2.findContours()
has varying return signatures.
In OpenCV 3.4.X, cv2.findContours()
returns 3 items
image, contours, hierarchy = cv2.findContours(image, mode, method[, contours[, hierarchy[, offset]]])
In OpenCV 4.1.X, cv2.findContours()
returns 2 items
contours, hierarchy = cv2.findContours(image, mode, method[, contours[, hierarchy[, offset]]])
You can easily obtain the contours regardless of the version like this:
cnts = cv2.findContours(image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
Since the last two values are always the same, we can further condense it into a single line using [-2:]
to extract the contours from the tuple returned by cv2.findContours()
cnts, _ = cv2.findContours(image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2:]
Use cv2.findContours output as plt.contour input
Here is a minimal example with plot
. Please keep in mind that the y-coordinate of opencv and matplotlib have different directions:
import cv2
from matplotlib import pyplot as plt
im = cv2.imread("img.png", cv2.IMREAD_GRAYSCALE)
_, thresh = cv2.threshold(im, 127, 255, cv2.THRESH_BINARY)
contours, _ = cv2.findContours(thresh, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
contour = contours[0]
M = cv2.moments(contour)
x = int(M["m10"] / M["m00"])
y = int(M["m01"] / M["m00"])
xs = [v[0][0] - x for v in contour]
ys = [-(v[0][1] - y) for v in contour]
plt.plot(xs, ys)
plt.grid()
plt.show()
And here is another example with a closed polygon patch:
import cv2
from matplotlib import pyplot as plt
from matplotlib.patches import Polygon
im = cv2.imread("img.png", cv2.IMREAD_GRAYSCALE)
_, thresh = cv2.threshold(im, 127, 255, cv2.THRESH_BINARY)
contours, _ = cv2.findContours(thresh, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
contour = contours[0]
M = cv2.moments(contour)
x = int(M["m10"] / M["m00"])
y = int(M["m01"] / M["m00"])
p = Polygon([(v[0][0] - x, y - v[0][1]) for v in contour], closed=True)
fig, ax = plt.subplots()
ax.add_patch(p)
ax.set_xlim([-80, 80])
ax.set_ylim([-80, 80])
plt.grid()
plt.show()
cv2.findContours function is not working in both versions
This is due to a change in openCV. Since version 4.0 findContours
returns only 2 values: the contours and the hierarchy. Before, in version 3.x, it returned 3 values. You can use the documentation to compare the different versions.
The second code snippet should work when you change your code to:
# find contours
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
Why the first snippet picks a different openCV version can't be determined from the information given.
OpenCV Contours - need more than 2 values to unpack
In OpenCV 2, findContours
returns just two values, contours
and hierarchy
. The error occurs when python tries to assign those two values to the three names given on left in this statement:
image, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
findContours and drawContours errors in opencv 3 beta/python
opencv 3 has a slightly changed syntax here, the return values differ:
cv2.findContours(image, mode, method[, contours[, hierarchy[, offset]]]) → image, contours, hierarchy
Related Topics
Duplicate Items in Legend in Matplotlib
My Py2App App Will Not Open. What's the Problem
How to Generate Random Numbers That Are Different
Is There a Recursive Version of the Dict.Get() Built-In
Converting Between Datetime and Pandas Timestamp Objects
Django.Db.Utils.Operationalerror Could Not Connect to Server
Python: Use MySQLdb to Import a MySQL Table as a Dictionary
Smtplib Sends Blank Message If the Message Contain Certain Characters
Python: Why Does My List Change When I'm Not Actually Changing It
Changing Order of Unit Tests in Python
Find Element's Index in Pandas Series
How to Change the Host and Port That the Flask Command Uses
How to Create a Slug in Django
How to Loop Through a List by Twos