The issue you're observing is due to combination of several factors:
- PEP-238 – Changing the Division Operator
- 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.