Я хочу искать в реальном времени экран моего телефона Android с помощью opencv и python. Мой телефон транслирует свой экран через http, и я читаю поток с таким кодом:
host = "192.168.178.168:8080"
hoststr = 'http://' + host + '/stream.mjpeg'
print 'Streaming ' + hoststr
stream=urllib2.urlopen(hoststr)
bytes=''
drop_count = 0
while True:
bytes+=stream.read(1024)
a = bytes.find('\xff\xd8')
b = bytes.find('\xff\xd9')
if a!=-1 and b!=-1:
drop_count+=1
if drop_count > 120:
drop_count = 0
jpg = bytes[a:b+2]
bytes= bytes[b+2:]
i=cv2.imdecode(np.fromstring(jpg,dtype=np.uint8),cv2.IMREAD_COLOR)
cv2.imshow(hoststr,i)
process_img(i)#my image processing
if cv2.waitKey(1) ==27:
exit(0)
Проблема в том, что мой поиск по экрану занимает слишком много времени и создает большую задержку. Поскольку количество кадров в секунду, которое отправляет мой телефон, слишком велико, я хотел бы обрабатывать только одно изображение в секунду или две секунды. Как я могу это сделать? Не могу изменить фпс на телефоне. Я могу изменить размер изображения на экране телефона до 50% перед его отправкой, но если я изменю его размер более чем на 50%, я больше не смогу найти то, что я ищу с помощью opencv. Но даже при изменении размера на 50% это слишком сильно задерживается. Если я сделаю простой счетчик и обработаю только каждое изображение 2/10/30, это не поможет.
Обновлено: я добавил свою простую реализацию счетчика для пропуска кадров, это не помогает. Если я не обрабатываю изображение, я получаю постоянную небольшую задержку с пропуском кадров и без него.
РЕДАКТИРОВАТЬ²: наконец решил это, к сожалению, я не помню, где я это читал, но это очень просто с openCV VideoCapture:
screen_capture = cv2.VideoCapture(stream_url) #init videocapture
drop_count = 0 #init drop counter
while True:
drop_count+=1
ret = screen_capture.grab() #grab frame but dont process it
if drop_count % 5 == 0: #check if not dropping frame
ret, img = self.screen_capture.retrieve() #process frame
Таким образом, кадры, которые вы хотите отбросить, действительно отбрасываются, и задержки не возникает.
да, он отлично работает без обработки изображений с высокой частотой кадров и обычной задержкой ~ 0,5 с. Я отредактировал и добавил свою реализацию счетчика. Если я использую его без обработки изображения, я получаю обычную постоянную задержку 0,5 с и всего около 3 кадров в секунду, но с обработкой изображения я получаю задержку 10 с, и она становится еще больше при потоковой передаче.






Я предполагаю, что задержка получается такой большой, потому что вы отображаете только обработанные кадры. Фактически показывается только 1 кадр из каждых 120. И этот кадр отображается для следующих 120 кадров и времени обработки. Это действительно могло бы показаться запаздывающим.
Вы должны нормально отображать все кадры и вызывать функцию process_img() только каждый 120-й кадр.
Попробуйте, если это улучшит ситуацию:
if a!=-1 and b!=-1:
drop_count+=1
jpg = bytes[a:b+2]
bytes= bytes[b+2:]
i=cv2.imdecode(np.fromstring(jpg,dtype=np.uint8),cv2.IMREAD_COLOR)
cv2.imshow(hoststr,i)
if drop_count > 120: # only process every 120th frame
drop_count = 0
process_img(i)#my image processing
if cv2.waitKey(1) ==27:
exit(0)
Вы уверены, что
process_img()является узким местом? Ваш код работает с высокой частотой кадров безprocess_img()? Если это так, простой счетчик должен быть хорошим решением. Можете ли вы показать код с вашей реализацией счетчика?