Ответ 1
лучший способ думать, что pythonic - забыть другие языки
s = True
while s:
s, i = capture.read()
if s:
do_some_stuff(i)
Я искал что-то вроде этого, но я не мог найти его здесь.
Некоторые фон
Я использую opencv для извлечения кадров из видеофайла. Обычно люди делают это в бесконечном цикле, например:
while (True):
s, img = cv.read()
или
for i in xrange(10000): #just a big number
s, img = cv.read()
теперь я хочу получить все кадры и выйти из цикла, когда больше нет кадров. Однако мои навыки в python недостаточно сильны, чтобы делать то, что я хочу делать.
Что я хочу знать
read
функция (или метод, я не знаю, как они вызывается в python) возвращает кортеж: сначала представляет успех операции, а второй представляет возвращенный фрейм. Я хочу разбить цикл while, когда первый элемент кортежа является ложным. Имея фон C, я подумал, что, возможно, это сработает:
while ((success, img = capture.read())[0]):
#do sth with img
Я думал, что это сломает цикл, когда успех будет ложным. Но это не так. Тогда я подумал, что это сработает:
while ((success, img = capture.read()).success):
#do sth with img
он тоже не работал. Я не хочу делать что-то вроде
while(True):
s, i = capture.read()
if (s == False):
break
Как проверить условие в while
, а не на if
, которое прерывается, если оно успешное?
лучший способ думать, что pythonic - забыть другие языки
s = True
while s:
s, i = capture.read()
if s:
do_some_stuff(i)
Вы можете написать генераторную функцию.
def readframes(cv):
while True:
success, frame = cv.read()
if success:
yield frame
else:
return
Таким образом, вы можете прокручивать кадры с помощью цикла for.
for frame in readframes(cv):
do_something_with_frame(frame)
Python имеет альтернативную iter
подпись, которая берет функцию в качестве первого аргумента и дозорного, определяя условие останова как второе.
Используя его, вы можете найти что-то вроде этого:
for s,img in iter(cv.read, (False, None)):
print img
Тем не менее, я сомневаюсь, что это лучше, чем просто break
в блоке if
.
Кроме того, он принимает только sentinel в качестве общего возвращаемого значения и не может основывать условие остановки на некоторой его части (например, на первом значении кортежа). Это может быть обходным путем, но сделает код еще более запутанным:
>>> for s,img in itertools.takewhile(lambda x: x[0], iter(cv.read, None)):
print img
Он использует itertools.takewhile
, чтобы определить, когда первое значение возвращаемого набора равно False
.
Полная версия для тестирования:
>>> class Capture(object):
def __init__(self):
self.L = iter([1,2,3,4,5])
def read(self):
try:
img = self.L.next()
except StopIteration:
return (False,None)
return True, img
>>> cv = Capture()
>>> for s,img in iter(cv.read, (False, None)):
print img
1
2
3
4
5
>>> cv = Capture()
>>> for s,img in itertools.takewhile(lambda x: x[0], iter(cv.read, None)):
print img
1
2
3
4
5
Это должно работать
while capture.read()[0]:
#do something
Конечно, вы не сможете получить доступ к кадру в этом направлении!
Есть другой способ
s,v = capture.read()
while s:
#Do sth
s,v = capture.read()
Это, конечно, длинный способ сказать
while True:
s,v = capture.read()
if not s:
break
Какой (по какой-то причине) вы не хотите делать
вы не можете делать то, что вы задаете в python (если только не есть хаки, о которых я не знаю).
какая строка:
s, i = capture.read()
делает, это назначение двух отдельных переменных путем распаковки кортежа, просто невозможно сказать python, что вы хотите, чтобы первая назначенная переменная.
В python также запрещено использовать в условном выражении if
, for
или while
.
единственное, что вы могли бы сделать:
if(capture.read()[0]):
Это означает, что вы потеряете данные изображения.
Короче говоря, распаковка кортежей на самом деле довольно сексуальна, нет причин не использовать возможности, которые она предоставляет!
Вот решение, для которого нужно разбить цикл, используя функцию, возвращающую кортеж.
>>> def read(a):
... if a == 0:
... return (False, a+1)
... return (True, a-1)
...
>>> read(5)
(True, 4)
>>> read(0)
(False, 1)
>>> a = True
>>> i = 5
>>> while(a):
... a, i = read(i)
... if a:
... print 'working'
...
...
...
working
working
working
working
working
>>>
Теперь ваш код будет выглядеть так:
s = True
while(s):
s, i = capture.read()