Add python binding for LineIterator#24261
Conversation
1f8d338 to
23335e3
Compare
asmorkalov
left a comment
There was a problem hiding this comment.
The proposal looks good! Please remove not related renaming in the class interface. Such changes does not bring value, but makes merges 4.x->5.x and conflict resolution harder.
review 2
review 2
opencv-alalek
left a comment
There was a problem hiding this comment.
It make sense to add simple Python test to avoid regressions.
Does Python types work as expected?
add a test in /modules/python/test?
What do you mean? May be Next() method should become next()? |
|
add a test in /modules/python/test? - yes. |
|
|
||
| /** @brief next pixel. Use for python binding. | ||
| */ | ||
| CV_WRAP Point Next() { |
There was a problem hiding this comment.
use next() - OpenCV uses camelCase naming convention for functions
modules/imgproc/src/drawing.cpp
Outdated
| Ptr<LineIterator> lineiterator = makePtr<LineIterator>(pt1, pt2, connectivity, leftToRight); | ||
| return lineiterator; |
There was a problem hiding this comment.
| Ptr<LineIterator> lineiterator = makePtr<LineIterator>(pt1, pt2, connectivity, leftToRight); | |
| return lineiterator; | |
| return makePtr<LineIterator>(pt1, pt2, connectivity, leftToRight); |
samples/python/lineiterator.py
Outdated
| img = cv.imread(cv.samples.findFile('butterfly.jpg')) | ||
| pt1 = (30, 40) | ||
| pt2 = (200, 90) | ||
| h = cv.LineIterator_create(pt1, pt2) |
There was a problem hiding this comment.
prefer to use .create notation instead of _create
| h = cv.LineIterator_create(pt1, pt2) | |
| h = cv.LineIterator.create(pt1, pt2) |
samples/python/lineiterator.py
Outdated
| cv.destroyAllWindows() | ||
| pt1 = (40, 80) | ||
| pt2 = (30, 200) | ||
| h = cv.LineIterator_create(pt1, pt2) |
There was a problem hiding this comment.
| h = cv.LineIterator_create(pt1, pt2) | |
| h = cv.LineIterator.create(pt1, pt2) |
| @param leftToRight If true, the line is traversed from the leftmost endpoint to the rightmost | ||
| endpoint. Otherwise, the line is traversed from \p pt1 to \p pt2. | ||
| */ | ||
| LineIterator( const Mat& img, Point pt1, Point pt2, |
There was a problem hiding this comment.
what is the point of renaming img argument to src?
It is unnecessary change
There was a problem hiding this comment.
before PR there was an attribute Mat img in LineIterator. Many warning were generated parameter img hide attribute . i change parameter name. attribute img was unused in class. I delete it after first or second review.
After two changes it is now unnecessary
| @endcode | ||
| */ | ||
| class CV_EXPORTS LineIterator | ||
| class CV_EXPORTS_W LineIterator |
There was a problem hiding this comment.
Why do you need create function. Have you tried to use CV_EXPORTS_W_SIMPLE and add CV_WRAP to the appropriate constructor?
There was a problem hiding this comment.
I tried it does not work without static method create
h = cv.LineIterator.create(pt1, pt2)
pt = h.pos()
error is
[ WARN:0@0.057] global samples.cpp:61 cv::samples::findFile cv::samples::findFile('butterfly.jpg') => 'C:\lib\opencv\samples/data\butterfly.jpg'
Traceback (most recent call last):
File "C:\lib\opencv\samples\python\lineiterator.py", line 8, in <module>
pt = h.pos()
cv2.error: Unknown C++ exception from OpenCV code
I floolowed guide line (https://docs.opencv.org/4.x/da/d49/tutorial_py_bindings_basics.html)
For large classes also, CV_EXPORTS_W is used. To extend class methods, CV_WRAP is used. Similarly, CV_PROP is used for class fields.
Small classes/structs are extended using CV_EXPORTS_W_SIMPLE. These structs are passed by value to C++ functions. Examples are KeyPoint, Match etc. Their methods are extended by CV_WRAP and fields are extended by CV_PROP_RW.
Now code is with CV_EXPORTS_W_SIMPLE and with static method create
| @@ -0,0 +1,32 @@ | |||
| #!/usr/bin/python | |||
There was a problem hiding this comment.
#!/usr/bin/env python is more usable
| #!/usr/bin/python | ||
|
|
||
| ''' | ||
| This example illustrates how to use LineIterator to get point coordinates on a line |
There was a problem hiding this comment.
This example
This line is not needed (at least not accurate)
| import cv2 as cv | ||
| import numpy as np | ||
| import sys | ||
| import math |
There was a problem hiding this comment.
math
Where is it used?
samples/python/lineiterator.py
Outdated
|
|
||
| pt = h.pos() | ||
| while min(pt1[0], pt2[0]) <= pt[0] <= max(pt1[0], pt2[0]) and \ | ||
| min(pt1[1], pt2[1]) <= pt[1] <= max(pt1[1], pt2[1]): |
There was a problem hiding this comment.
Could we improve stop condition?
Could we provide a "native" Python iterator?
for pt in cv.LineIterator(pt1, pt2):
... process pt ...
See how to write Python (3+ only) code here: modules/core/misc/python/package (but for imgproc).
Python allows to replace modules's entity.
Redefine class (create new) or redefine __iter__/__next__ methods:
def LineIterator__iter__(self):
... reset ...
return self
def LineIterator__next__(self):
if self.next():
return self.pos
else:
raise StopIteration
cv2.LineIterator.__iter__ = LineIterator__iter__
cv2.LineIterator.__next__ = LineIterator__next__There was a problem hiding this comment.
There is a problem when import cv2 :
cv2.LineIterator.iter = LineIterator__iter__
TypeError: cannot set 'iter' attribute of immutable type 'cv2.LineIterator'
file init.py content in imgproc/python/package/lineiteraor/
import cv2
def LineIterator__iter__(self):
return self
def LineIterator__next__(self):
if self.next():
return self.pos
else:
raise StopIteration
cv2.LineIterator.__iter__ = LineIterator__iter__
cv2.LineIterator.__next__ = LineIterator__next__
|
|
||
| /** @brief next pixel. Use for python binding. | ||
| */ | ||
| CV_WRAP Point next() { |
There was a problem hiding this comment.
bool next() interface is more appropriate for iterators.
| @@ -0,0 +1,18 @@ | |||
| import cv2 as cv | |||
|
|
|||
| class LineIteratorB(cv.LineIterator): | |||
There was a problem hiding this comment.
👍 for derived class.
Please use LineIteratorWrapper or LineIteratorForPython. `B looks as unclear name.
| super().__init__(pt1, pt2) | ||
|
|
||
| def __iter__(self): | ||
| return self |
There was a problem hiding this comment.
Please check:
line = cv.LineIterator(p1, p2)
print('first pass...')
for pt in line:
print(pt)
print('second pass...')
for pt in line:
print(pt)
Passes should print the same elements.
There was a problem hiding this comment.
There was a problem hiding this comment.
See comments above - reset part should be implemented.
def LineIterator__iter__(self):
... reset ...
return self
BTW, another case from Python iter world:
line = cv.LineIterator(p1, p2)
it1 = iter(line)
it2 = iter(line)
... it1 and it2 should not interfere on each other (must be independent) ...
Perhaps we could not derive. May be we should use some kind of proxy pattern.
|
|
||
| LineIteratorB.__module__ = cv.__name__ | ||
| cv.LineIterator = LineIteratorB | ||
| cv._registerMatType(LineIteratorB) |
There was a problem hiding this comment.
cv._registerMatType(LineIteratorB)
Remove that.
| count = count + 1 | ||
| if count == 10: | ||
| self.assertEqual(p.pos(), (10.0, 10.0)) | ||
| break |
There was a problem hiding this comment.
Lets check for stop condition instead of break:
for ...
...
self.assertLess(count, 102)
self.assertEqual(count, 101)
BTW, 101, 102 could be adjusted.
| */ | ||
| CV_WRAP bool next() { | ||
| this->operator++(); | ||
| return true; |
There was a problem hiding this comment.
I must change c++ class
samples/python/lineiterator.py
Outdated
|
|
||
| pt = h.pos() | ||
| pt_tl, pt_br = boundaries_rect(pt1, pt2) | ||
| while pt_in_rect(pt, pt_tl, pt_br): |
There was a problem hiding this comment.
change in c++ class
|
@opencv-alalek something is weird In python 2 test_lineiterator (test_lineiterator.lineiterator_test) ... ERROR how to disable python2 test in python3 How my test can kill other testt? still waiting an answer @opencv-alalek |
|
@opencv-alalek please take a look. |
I proposed to close this PR |
|
@LaurentBerger Thanks a lot for the contribution. Feel free to close PR, if you treat it as not successful, or does not have a chance to finish the work. |
the work is finished but buildbot is wrong. All my unit tests are good but other tests failed with timeout |
Pull Request Readiness Checklist
See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request
LineIteratorpoorly supported in bindings #21307Patch to opencv_extra has the same branch name.