Я использую opencv c ++ в Mac OS X 10.10.2 для обработки видеокадров и их отображения. Производительность imshow с waitKey для отображения видео крайне медленная.
У меня есть следующий код, который корректно отображает кадры в оттенках серого HD (1920×1080), за исключением того, что он работает примерно в 10 раз медленнее (то есть от 2 до 3 кадров в секунду вместо 30 кадров в секунду).
cv::Mat framebuf[TEST_COUNT];
//--- Code here to allocate and fill the frame buffer with about 4 seconds of video. This part works correctly.
//--- This loop runs too slow by factor of approximately 10x
for (int f = 0; f < TEST_COUNT; f++)
{
cv::imshow(windowName, framebuf[f]);
cv::waitKey(33);
}
Кто-нибудь может подсказать, как получить производительность в реальном времени или почти в реальном времени из opencv imshow ()? Я видел много постов, в которых говорится, что они показывают видео в реальном времени или даже быстрее, чем в реальном времени, поэтому я не уверен, что я делаю неправильно. Любая помощь будет принята с благодарностью.
Я могу ошибаться, но для меня проблема не в вашем коде, а в вашей ОС / конфигурации. Я написал небольшой тест:
import cv2
import numpy as np
from random import randrange
img = np.zeros((1920, 1080), dtype = np.uint8)
counter = 0
while counter < 1000:
cv2.line(img, (randrange(0, 1920), randrange(0, 1080)), (randrange(0, 1920), randrange(0, 1080)), (randrange(0, 255)))
cv2.imshow('test', img)
temp = cv2.waitKey(1)
counter += 1
print counter
На моей машине (Core 2 duo 2,6 ГГц x64, 8 ГБ ОЗУ, SSD) для завершения этого теста потребовалось около 30 секунд. Запустите его, и если вы получите значительно больше времени, чем определенно, что-то не так с вашим ноутбуком / конфигурацией opencv / и т.д. Я использовал OpenCV 2.4.x на Mac OS X (думаю, это был 10,9), и он работал нормально. Переустановка OpenCV — самое очевидное решение, которое приходит мне в голову. Когда вы удаляете OpenCV, используйте brew, чтобы установить его снова — brew install opencv --with-tbb --with-python --with-ffpmeg
(или что-то подобное — проверьте с помощью brew options opencv
) все должно быть в порядке. Первая опция указывает brew на сборку opencv с помощью tbb (потоковый строительный блок — библиотека для многопоточности, иногда может значительно повысить скорость), вторая — для установки оболочек Python, а последняя — для установки ffmpeg (обработка кодеков и т. Д.).
Вы должны были бы уменьшить ввод для клавиши ожидания функции. Попробуйте использовать меньшее число в диапазоне 2-5. Это также зависит от других процессов, которые вы выполняете одновременно, попробуйте закрыть другие процессы и посмотреть, улучшится ли это.
Вы можете создать свое собственное окно, чтобы показать изображение. Добавьте файл MyWindow.m MyWindow.h в проект.
MyWindow.h
#ifndef MY_WINDOW_H
#define MY_WINDOW_H
#ifdef __cplusplus
extern "C" {
#endif
void* createNSWindow(int x, int y, int w, int h);
void renderNSWindow(void* inwindow, void* data, int w, int h, int c);
void processNSEvent();
#ifdef __cplusplus
}
#endif
#endif
использование, в main.cpp, не забудьте waitKey
#include "MyWindow.h"
// need create a cv window and do nothing
cv::namedWindow("xxx", 1);
// create window
void* w = createNSWindow(0, 0, 0, 0);
// frame image
cv::Mat frameImage;
// render loop
renderNSWindow(w, frameImage.data, frameImage.cols, frameImage.rows, frameImage.channels());
// need waitKey to display window
processNSEvent();
реализовать в MyWindow.m, удалить импорт «MyWindow.h»
#import <Cocoa/Cocoa.h>
@interface MyWindow : NSWindow
@property(nonatomic, strong) NSImageView *imgv;
@end
@implementation MyWindow
@endstatic NSImage* _createNSImage(void* data, int w, int h, int c);
void* createNSWindow(int x, int y, int w, int h) {
NSRect screenFrame = [[NSScreen mainScreen] frame];
NSRect frame = NSMakeRect(x, y, w, h);
if (w == 0 || h == 0) {
frame = screenFrame;
}
MyWindow* window = [[MyWindow alloc] initWithContentRect:frame
styleMask:NSWindowStyleMaskBorderless
backing:NSBackingStoreBuffered
defer:NO] ;//_initApp(window);
[window makeKeyAndOrderFront:NSApp];
window.titleVisibility = TRUE;
window.styleMask = NSWindowStyleMaskResizable | NSWindowStyleMaskTitled |NSWindowStyleMaskFullSizeContentView;
window.imgv = [[NSImageView alloc] initWithFrame:NSMakeRect(0, 0, frame.size.width, frame.size.height)];
[window.contentView addSubview:window.imgv];return (void*)CFBridgingRetain(window);
}static NSImage* _createNSImage(void* data, int w, int h, int c) {
size_t bufferLength = w * h * c;
CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, data, bufferLength, NULL);
size_t bitsPerComponent = 8;
size_t bitsPerPixel = c * bitsPerComponent;
size_t bytesPerRow = c * w;
CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedLast;
if (c < 4) {
bitmapInfo = kCGBitmapByteOrderDefault | kCGImageAlphaNone;
unsigned char* buf = data;
for(int i = 0; i < w*h; i++) {
unsigned char temp = buf[i*c];
buf[i*c] = buf[i*c+c-1];
buf[i*c+c-1] = temp;
}
}
CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
CGImageRef iref = CGImageCreate(w,
h,
bitsPerComponent,
bitsPerPixel,
bytesPerRow,
colorSpaceRef,
bitmapInfo,
provider, // data provider
NULL, // decode
YES, // should interpolate
renderingIntent);
NSImage* image = [[NSImage alloc] initWithCGImage:iref size:NSMakeSize(w, h)];
return image;
}
void renderNSWindow(void* inwindow, void* data, int w, int h, int c) {
MyWindow* window = (__bridge MyWindow*)inwindow;
window.imgv.image = _createNSImage(data, w, h, c);
}
void processNSEvent() {
for (;;)
{
NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny
untilDate:[NSDate distantPast]
inMode:NSDefaultRunLoopMode
dequeue:YES];
if (event == nil)
break;
[NSApp sendEvent:event];
}
}
кроме того, waitKey теперь занимает около 20 мс, вы можете сделать OpenCV в фоновом потоке и показать окно в основном потоке. Также используйте processNSEvent вместо waitKey, который занимает около 10 мс.
полный исходный код:
#include <iostream>
#include "opencv2/core/core.hpp"#include "opencv2/highgui/highgui.hpp"#include <dispatch/dispatch.h>
#include "MyWindow.h"
using namespace std;
using namespace cv;int opencvfunc(int argc, const char *argv[]);
bool newFrame = false;
cv::Mat back_frame;
int main(int argc, const char * argv[]) {
cv::namedWindow("render", 1);
void* w = createNSWindow(0, 0, 0, 0);
dispatch_queue_t opencvq = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
dispatch_async(opencvq, ^{
opencvfunc(argc, argv);
});while(true) {
usleep(3*1000);
if(newFrame) {
std::chrono::system_clock::time_point starttime = std::chrono::system_clock::now();
renderNSWindow(w, back_frame.data, back_frame.cols, back_frame.rows, back_frame.channels());
newFrame = false;
//auto key = cv::waitKey(1);
//if (key == 'q') {
// break;
//}
processNSEvent();
std::chrono::system_clock::time_point endtime = std::chrono::system_clock::now();
std::cout << "imshow:" << std::chrono::duration_cast<std::chrono::duration<double>>(endtime-starttime).count()*1000 << std::endl;
}
}
return 0;
}
int opencvfunc(int argc, const char *argv[]) {
cv::VideoCapture cap;
cap.open(0);
if (!cap.isOpened()) {
std::cout << "Couldn't open camera 0." << endl;
return EXIT_FAILURE;
}
Mat frame, unmodified_frame;
for (;;) {
cap >> frame; // get a new frame from camera
if (frame.empty()) { // stop if we're at the end of the video
break;
}//unmodified_frame = frame.clone();
// ...
back_frame = frame.clone();
newFrame = true;
}
return EXIT_SUCCESS;
}
OpenCV 4 решил эту проблему, пожалуйста, обновите его до новой версии.
Еще одна вещь, обрабатывать видео и показывать видео в два потока.
#include <stdio.h>
#include <iostream>
#include <opencv2/opencv.hpp>
#include <dispatch/dispatch.h>
using namespace cv;
using namespace std;bool newFrame = false;
Mat back_frame;
int opencvmain(int argc, char** argv ) {
// open camear
cv::VideoCapture cap;
cap.open(0);
if (!cap.isOpened()) {
std::cout << "Couldn't open camera 0." << std::endl;
return EXIT_FAILURE;
}
// define frame images
cv::Mat frame;
// frame loop
for (;;) {
// get video frame
cap >> frame;
if (frame.empty()) {
break;
}
// render
back_frame = frame.clone();
newFrame = true;
}
return 0;
}
int main(int argc, char** argv ) {namedWindow("video", WINDOW_AUTOSIZE );
dispatch_queue_t opencvq = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_async(opencvq, ^{
opencvmain(argc, argv);
});while(true) {
usleep(3*1000);
if(newFrame) {
imshow("video", back_frame);
auto key = cv::waitKey(1);
if (key == ' ') {
break;
}
newFrame = false;
}
}
return 0;
}