Прежде всего, спасибо за ясность вопроса.
Q: Можно ли использовать (multi) многопоточность на уровне приложений с OpenCV?
A: Да, вполне нормально использовать многопоточность на уровне приложений с OpenCV, если только вы не используете функции, которые могут использовать преимущества многопоточности, такие как размытие, изменение цветового пространства, здесь вы можете разделить изображение нанесколько частей и применяют глобальные функции по всей разделенной части, а затем рекомбинируют его для получения окончательного результата.
В некоторых функциях, таких как Hough, pca_analysis, которые не могут дать правильные результаты, когда они применяются к разделенным разделам изображения и затем рекомбинируютсяприменение многопоточности на уровне приложения к таким функциям может не дать правильных результатов и поэтому не должно выполняться.
Как уже упоминалось, ваша реализация многопоточности не даст вам преимущества, поскольку вы присоединяетесь к потоку вдля самой петли.Я бы посоветовал вам использовать обещание и будущие объекты. (Если вам нужен пример того, как это сделать, дайте мне знать в комментариях, я поделюсь фрагментом кода.
Ниже ответа потребовалось много исследований,спасибо, что задали вопрос, это действительно помогает мне добавить информацию к моим многопоточным знаниям:)
Q: Если да, почему промежутки времени напечатаны моей программой вышевремя?
A: После многих исследований я обнаружил, что создание и уничтожение потоков требует много ресурсов ЦП и памяти.Когда мы инициализируем поток (в вашем коде этой строкой: thread t(blurSlowdown, nullptr);
), идентификатор записывается в область памяти, на которую указывает эта переменная, и этот идентификатор позволяет нам ссылаться на поток.Теперь в вашей программе вы создаете и уничтожаете потоки с очень высокой скоростью, теперь это то, что происходит, для программы выделен пул потоков, с помощью которого наша программа может запускать и уничтожать потоки, я буду кратким, и давайте посмотрим наобъяснение ниже:
- Когда вы создаете поток, это создает идентификатор, который указывает на этот поток.
- Когда вы уничтожаете поток, эта память освобождается
НО
При повторном создании потока, после того как первый поток не был уничтожен, идентификатор этого нового потока указывает на новое местоположение (местоположение, отличное от предыдущего потока) в пуле потоков.
После многократного создания и уничтожения потока, пул потоков исчерпан , и поэтому ЦП вынужден немного замедлять циклы нашей программы, так чтопул потоков снова освобождается для освобождения места для нового потока.
Intel TBB и OpenMP очень хорошо справляются с управлением пулами потоков, поэтому эта проблема может не возникать при их использовании.
Q: Широко ли поддерживается TBB в 2019 году?
A: Да, вы можете воспользоваться преимуществами TBB в своей программе OpenCV, хотя такжеВключение поддержки TBB при сборке OpenCV.
Вот программа для реализации TBB в medianBlur:
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include <chrono>
using namespace cv;
using namespace std;
using namespace std::chrono;
class Parallel_process : public cv::ParallelLoopBody
{
private:
cv::Mat img;
cv::Mat& retVal;
int size;
int diff;
public:
Parallel_process(cv::Mat inputImgage, cv::Mat& outImage,
int sizeVal, int diffVal)
: img(inputImgage), retVal(outImage),
size(sizeVal), diff(diffVal)
{
}
virtual void operator()(const cv::Range& range) const
{
for(int i = range.start; i < range.end; i++)
{
/* divide image in 'diff' number
of parts and process simultaneously */
cv::Mat in(img, cv::Rect(0, (img.rows/diff)*i,
img.cols, img.rows/diff));
cv::Mat out(retVal, cv::Rect(0, (retVal.rows/diff)*i,
retVal.cols, retVal.rows/diff));
cv::medianBlur(in, out, size);
}
}
};
int main()
{
VideoCapture cap(0);
cv::Mat img, out;
while(1)
{
cap.read(img);
out = cv::Mat::zeros(img.size(), CV_8UC3);
// create 8 threads and use TBB
auto start1 = high_resolution_clock::now();
cv::parallel_for_(cv::Range(0, 8), Parallel_process(img, out, 9, 8));
//cv::medianBlur(img, out, 9); //Uncomment to compare time w/o TBB
auto stop1 = high_resolution_clock::now();
auto duration1 = duration_cast<microseconds>(stop1 - start1);
auto time_taken1 = duration1.count()/1000;
cout << "TBB Time: " << time_taken1 << "ms" << endl;
cv::imshow("image", img);
cv::imshow("blur", out);
cv::waitKey(1);
}
return 0;
}
На моей машине реализация TBB занимает около 10 мс, а без TBB - около40 мс.
Q: Если да, что обеспечивает лучшую производительность, многопоточность на уровне приложения (если разрешено) или TBB / OpenMP?
A: Я бы предложил использовать многопоточность TBB / OpenMP поверх POSIX (pthread / thread), потому что TBB предлагает вам лучший контроль над потоком + лучшую структуру для написания параллельного кода и внутренне он управляет pthreads.В случае, если вы используете pthreads, вам придется позаботиться о синхронизации, безопасности и т. Д. В вашем коде.Но использование этих рамок абстрагирует необходимость обработки потока, который может стать очень сложным.
Для сравнения TBB и проверки OpenMP этот ответ