I am trying to use HogDescriptor and I am getting this error. I saw in the document that the constructor can take more then one argument. I am working in python 3.6 and opencv 3.2
This is my code:
def _extract_feature(X): """Performs feature extraction :param X: data (rows=images, cols=pixels) :param feature: which feature to extract - "hog": HOG features :returns: X (rows=samples, cols=features) """ X = [cv2.cvtColor(x, cv2.COLOR_BGR2GRAY) for x in X] # operate on smaller image small_size = (32, 32) X = [cv2.resize(x, small_size) for x in X] # histogram of gradients block_size = (small_size[0] / 2, small_size[1] / 2) block_stride = (small_size[0] / 4, small_size[1] / 4) cell_size = block_stride num_bins = 9 hog = cv2.HOGDescriptor(small_size, block_size, block_stride, cell_size, num_bins) X = [hog.compute(x) for x in X] X = [x.flatten() for x in X] return X
So why am I getting the error:
TypeError: HogDescriptor takes at most 1 argument (5 given)
Update: I installed python 2.7 and tried it and it works.
The issue you're observing is due to combination of several factors:
- PEP-238
- Mapping to Python and dispatching of overloaded C++ functions (as done in OpenCV)
Division in Python
The meaning of operator /
has changed between Python 2.x and Python 3.x.
From PEP-238:
- Classic division will remain the default in the Python 2.x series; true division will be standard in Python 3.0
For example, in Python 2.x you have
>>> small_size = (32, 32) >>> block_size = (small_size[0] / 2, small_size[1] / 2) >>> print(block_size) (16, 16)
And in Python 3.x you have
>>> small_size = (32, 32) >>> block_size = (small_size[0] / 2, small_size[1] / 2) >>> print(block_size) (16.0, 16.0)
In order to get the same result, your Python 3.x code would need to use operator //
>>> small_size = (32, 32) >>> block_size = (small_size[0] // 2, small_size[1] // 2) >>> print(block_size) (16, 16)
Mapping and Handling of Overloads
Without going into detail (that would warrant a separate question), the overload resolution depends on the types of arguments. The matching of types is quite strict, e.g. you may not pass a floating point number to an integer argument.
The C++ signature of the constructor in question (truncated to only the relevant arguments) is
HOGDescriptor (Size _winSize , Size _blockSize , Size _blockStride , Size _cellSize , int _nbins, ...)
cv::Size
is a class that contains two integers. In the Python API, it is represented as a tuple containing two integers.
Therefore, to call this overload in Python, we need to provide:
- 4x a tuple containing two integers (for
_winSize
, _blockSize
, _blockStride
, and _cellSize
) - 1x an integer (for
_nbins
)
We can test this out in the Python interpreter.
>>> import cv2 >>> cv2.HOGDescriptor((1,1),(1,1),(1,1),(1,1),1) <HOGDescriptor 0393D0F0>
This matches our expectations. Let's try some other options.
>>> cv2.HOGDescriptor((1,1,1),(1,1),(1,1),(1,1),1) TypeError: HOGDescriptor() takes at most 1 argument (5 given) >>> cv2.HOGDescriptor((1,),(1,1),(1,1),(1,1),1) TypeError: HOGDescriptor() takes at most 1 argument (5 given)
We see the tuples need to have 2 values, no more, no less.
>>> cv2.HOGDescriptor([1,1],(1,1),(1,1),(1,1),1) TypeError: HOGDescriptor() takes at most 1 argument (5 given)
Lists won't do, it has to be a tuple.
>>> cv2.HOGDescriptor((1.0,1.0),(1,1),(1,1),(1,1),1) TypeError: HOGDescriptor() takes at most 1 argument (5 given)
Tuples of floats won't work either.
>>> cv2.HOGDescriptor((1,1),(1,1),(1,1),(1,1),1.0) TypeError: HOGDescriptor() takes at most 1 argument (5 given)
Nor can we substitute an float for an integer.
Pulling it All Together
Considering the above, in terms of the values you pass the constructor, the two variants are:
- Python 2.x:
cv2.HOGDescriptor((32,32),(16,16),(8,8),(8,8),9)
- Python 3.x:
cv2.HOGDescriptor((32,32),(16.0,16.0),(8.0,8.0),(8.0,8.0),9)
We can clearly see that the parameters in Python 3.x don't satisfy the requirements of the overload.
As to why we get the misleading error message, that seems like another topic warranting a separate question, and I haven't done all the research necessary to answer this authoritatively.
HOGDescriptor is an overloaded function.
If you look at the c++ documentation, it shows 4 versions - one with no parameters, one with 12, one with string and one with an option I'm not immediately familiar with.
You've tried to use one with 5 arguments. There isn't a function for that. You need to use either none, all 12 or one. If you look at this StackOverflow question, this person has supplied an xml file for the control specification - this fits the string filename option and hence is a valid function.