First of all, thank you for the clarity of the question.

Q: Is it okay to use (multi)threading on application level with OpenCV?

A: Yes it is totally ok to use multithreading on application level with OpenCV unless and until you are using functions which can take advantage of multithreading such as blurring, colour space changing, here you can split the image into multiple parts and apply global functions throughout the divided part and then recombine it to give the final output.

In some functions such as Hough, pca_analysis which cannot give correct results when they are applied to divided image sections and then recombined, applying multithreading on application level to such functions may not give correct results and thus should not be done.

As πάντα ῥεῖ mentioned, your implementation of multithreading will not give you an advantage because you are joining the thread in the for loop itself. I would suggest you use promise and future objects(If you want an example of how to, let me know down in the comments, I will share the snippet.

Below answer took a lot of research, thanks for asking the question, it really helps me add info to my multithreading knowledge :)

Q: If yes, why are the time spans printed by my program above GROWING over time?

A: After a lot of research I found out that creating and destroying threads takes a lot of CPU as well as memory resources. When we initialize a thread(in your code by this line: thread t(blurSlowdown, nullptr); ) an identifier is written to the memory location to which this variable points and this identifier enables us to refer to the thread. Now in your program you are creating and destroying thread at a very high rate, now this is what happens, there is a thread pool allocated to a program through which our program can run and destroy threads, I will keep it short and let's look at the explanation below:

  1. When you create a thread, this creates an identifier which points this thread.
  2. When you destroy the thread, this memory is freed

BUT

  1. When you again create a thread after no time the first thread is destroyed, the identifier of this new thread points to a new location(location other than the previous thread) in the thread pool.

  2. After repeatedly creating and destroying a thread, the thread pool is exhausted and so CPU is forced to slow down our program cycles a bit so that the thread pool is again freed for making space for a new thread.

Intel TBB and OpenMP are very good at thread pool management so this problem may not occur while using them.

Q: Is TBB in 2019 now widely supported?

A: Yes, you can take advantages of TBB in your OpenCV program while also turning on TBB support on building OpenCV.

Here is a program for TBB implementation in 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;
}

On my machine, TBB implementation takes around 10ms and w/o TBB it takes around 40ms.

Q: If yes, what offers better performance, multithreading on the application level(if allowed) or TBB / OpenMP?

A: I would suggest using TBB/OpenMP over POSIX multithreading(pthread/thread) because TBB offers you better control over thread + better structure for writing parallel code and internally it manages pthreads. In case if you use pthreads you will have to take care of sync and safety etc in your code. But using these framework abstracts the need for handling thread which may get very complex.

Edit: I checked the comments regarding the incompatibility of image dimensions with the number of thread in which you want to divide the processing. So here is a potential workaround(haven't tested but should work), scale the image resolution to the compatible dimensions like:

If your image res is 485 x 647, scale it to 488 x 648 then pass it to Parallel_process then scale back the output to the original size of 458 x 647.

For comparison of TBB and OpenMP check this answer

Answer from FutureJJ on Stack Overflow
Top answer
1 of 1
23

First of all, thank you for the clarity of the question.

Q: Is it okay to use (multi)threading on application level with OpenCV?

A: Yes it is totally ok to use multithreading on application level with OpenCV unless and until you are using functions which can take advantage of multithreading such as blurring, colour space changing, here you can split the image into multiple parts and apply global functions throughout the divided part and then recombine it to give the final output.

In some functions such as Hough, pca_analysis which cannot give correct results when they are applied to divided image sections and then recombined, applying multithreading on application level to such functions may not give correct results and thus should not be done.

As πάντα ῥεῖ mentioned, your implementation of multithreading will not give you an advantage because you are joining the thread in the for loop itself. I would suggest you use promise and future objects(If you want an example of how to, let me know down in the comments, I will share the snippet.

Below answer took a lot of research, thanks for asking the question, it really helps me add info to my multithreading knowledge :)

Q: If yes, why are the time spans printed by my program above GROWING over time?

A: After a lot of research I found out that creating and destroying threads takes a lot of CPU as well as memory resources. When we initialize a thread(in your code by this line: thread t(blurSlowdown, nullptr); ) an identifier is written to the memory location to which this variable points and this identifier enables us to refer to the thread. Now in your program you are creating and destroying thread at a very high rate, now this is what happens, there is a thread pool allocated to a program through which our program can run and destroy threads, I will keep it short and let's look at the explanation below:

  1. When you create a thread, this creates an identifier which points this thread.
  2. When you destroy the thread, this memory is freed

BUT

  1. When you again create a thread after no time the first thread is destroyed, the identifier of this new thread points to a new location(location other than the previous thread) in the thread pool.

  2. After repeatedly creating and destroying a thread, the thread pool is exhausted and so CPU is forced to slow down our program cycles a bit so that the thread pool is again freed for making space for a new thread.

Intel TBB and OpenMP are very good at thread pool management so this problem may not occur while using them.

Q: Is TBB in 2019 now widely supported?

A: Yes, you can take advantages of TBB in your OpenCV program while also turning on TBB support on building OpenCV.

Here is a program for TBB implementation in 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;
}

On my machine, TBB implementation takes around 10ms and w/o TBB it takes around 40ms.

Q: If yes, what offers better performance, multithreading on the application level(if allowed) or TBB / OpenMP?

A: I would suggest using TBB/OpenMP over POSIX multithreading(pthread/thread) because TBB offers you better control over thread + better structure for writing parallel code and internally it manages pthreads. In case if you use pthreads you will have to take care of sync and safety etc in your code. But using these framework abstracts the need for handling thread which may get very complex.

Edit: I checked the comments regarding the incompatibility of image dimensions with the number of thread in which you want to divide the processing. So here is a potential workaround(haven't tested but should work), scale the image resolution to the compatible dimensions like:

If your image res is 485 x 647, scale it to 488 x 648 then pass it to Parallel_process then scale back the output to the original size of 458 x 647.

For comparison of TBB and OpenMP check this answer

🌐
Nrsyed
nrsyed.com › 2018 › 07 › 05 › multithreading-with-opencv-python-to-improve-video-processing-performance
Multithreading with OpenCV-Python to improve video processing performance • Najam R. Syed
July 6, 2018 - We import the threading module, which will allow us to spawn new threads. In the class __init__() method, we initialize an OpenCV VideoCapture object and read the first frame.
Discussions

multithreading - Multi-threading in image processing - video python opencv - Stack Overflow
Im working on object detection from a live stream video using opencv python. The program I have is running on a single thread because of that the resulting video shown on the screen doesnt even loo... More on stackoverflow.com
🌐 stackoverflow.com
[Question] OpenCV with multithreading in C++
You could run separate blur functions on different images using normal multithreading or open mp, but if you want to speed up a single image you'd have to use the TBB thing. But for optimum speed use a GPU. A blur of an enormous image could be done in microseconds there. I see that CUDA has some sort of library for opencv optimization More on reddit.com
🌐 r/opencv
9
14
February 13, 2020
OpenCV C++ Multithreading - Stack Overflow
The slick way to achieve this is not to do the thread housekeeping yourself but use a library that provides micro-parallelization. OpenCV itself uses Intel Thread Building Blocks (TBB) for exactly this task -- running loops in parallel. More on stackoverflow.com
🌐 stackoverflow.com
July 26, 2016
[Question] Is OpenCV thread-safe?
Yikes. You don't say what "jqueue" is, but I see zero attempts at protecting the structure between the two threads. So if the calls to front() and erase() happen while the other thread is calling push_back(), then you corrupt the structure, leading to segfaults. This has nothing to do with using OpenCV. Instead, this is very basic thread synchronization. You need to read up on how to protect containers and structures from being modified from multiple threads. OpenCV's cv::Mat objects can be used from multiple threads without issues...as long as you protect them. Like everything else in C++, reading something from multiple threads is fine. But once you modify or delete things, then you need to protect yourself and manage access. More on reddit.com
🌐 r/opencv
6
6
March 2, 2022
🌐
Medium
medium.com › @rachittayal7 › a-note-on-opencv-threads-performance-in-prod-d10180716fba
A Note on OpenCV Threads & Performance in Prod. | by Rachit Tayal | Medium
January 3, 2020 - Locally: Total Threads spawned = 13 13 = 8 (created by OpenCV, since 8 cores) + 5 (other module of app)In Prod: Total Threads spawned = 29 29 = 24 (created by OpenCV, since 24 cores) + 5 (other module of app) General rule of thumb is, your app should be spawning that many threads as the cores it has available for processing.
🌐
OpenCV Q&A Forum
answers.opencv.org › question › 97382 › opencv-c-multithreading
OpenCV C++ Multithreading - OpenCV Q&A Forum
June 27, 2016 - But then, fundamentally, multithreading sequential processes is a bad approach. ... You can use the TBB parallel pipeline with OpenCV to do just that.
Top answer
1 of 2
5

Working on the assumption that the detection algorithm is CPU-intensive, you need to be using multiprocessing instead of multithreading since multiple threads will not run Python bytecode in parallel due to contention for the Global Interpreter Lock. You should also get rid of all the calls to sleep. It is also not clear when you run multiple threads or processes the way you are doing it what guarantees that the frames will be output in the correct order, that is, the processing of the second frame could complete before the processing of the first frame and get written to the detection_buffer first.

The following uses a processing pool of 6 processes (there is no need now for an implicit input queue).

from multiprocessing import Pool, Queue
import time
import cv2

# intialize global variables for the pool processes:
def init_pool(d_b):
    global detection_buffer
    detection_buffer = d_b


def detect_object(frame):
    time.sleep(1)
    detection_buffer.put(frame)


def show():
    while True:
        print("show")
        frame = detection_buffer.get()
        if frame is not None:
            cv2.imshow("Video", frame)
        else:
            break
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    return


# required for Windows:
if __name__ == "__main__":

    detection_buffer = Queue()
    # 6 workers: 1 for the show task and 5 to process frames:
    pool = Pool(6, initializer=init_pool, initargs=(detection_buffer,))
    # run the "show" task:
    show_future = pool.apply_async(show)

    cap = cv2.VideoCapture(0)

    futures = []
    while True:
        ret, frame = cap.read()
        if ret:
            f = pool.apply_async(detect_object, args=(frame,))
            futures.append(f)
            time.sleep(0.025)
        else:
            break
    # wait for all the frame-putting tasks to complete:
    for f in futures:
        f.get()
    # signal the "show" task to end by placing None in the queue
    detection_buffer.put(None)
    show_future.get()
    print("program ended")
2 of 2
2

for me what I've done is building 2 threads for 2 funtions and use one queue:

  1. to get the frame and process it
  2. to dispaly

the cap variable was inside my process function.

def process:
     cap = cv2.VideoCapture(filename)
     ret, frame = cap.read()

      while ret:
          ret, frame = cap.read()
#detection part in my case I use tensorflow then 
     # end of detection part 
          q.put(result_of_detection)

def Display():
  while True:
    if q.empty() != True:
        frame = q.get()
        cv2.imshow("frame1", frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

if __name__ == '__main__':
#  start threads
p1 = threading.Thread(target=process)
p2 = threading.Thread(target=Display)
p1.start()
p2.start()

it works just fine for me

hope I helped :D

Also, I think this page could may help: https://pyimagesearch.com/2015/12/21/increasing-webcam-fps-with-python-and-opencv/

Starred by 102 users
Forked by 45 users
Languages: C++ 92.3% | C 4.0% | CMake 3.7% | C++ 92.3% | C 4.0% | CMake 3.7%
Top answer
1 of 2
6

The slick way to achieve this is not to do the thread housekeeping yourself but use a library that provides micro-parallelization.

OpenCV itself uses Intel Thread Building Blocks (TBB) for exactly this task -- running loops in parallel.

In your case, your loop has just four iterations. With C++11, you can write it down very easily using a lambda expression. In your example:

std::vector<cv::Mat> input = { m1, m2, m3, m4; }
tbb::parallel_for(size_t(0), input.size(), size_t(1), = {
    processBinary(input[i]); 
});

For this example I took code from here.

2 of 2
0

In case, you're using python language, then you can use my powerful open-source built-in multi-threaded vidgear OpenCV's wrapper python library available on GitHub and PyPI for achieving higher FPS.

Project Insight:

VidGear is a lightweight python wrapper around OpenCV Video I/O module that contains powerful multi-thread modules(gears) to enable high-speed video frames capture functionality across various devices and platforms.

Features:

Key features which differentiate it from the other existing multi-threaded open source solutions are:

  • Multi-Threaded high-speed OpenCV video-frame capturing(resulting in High FPS)

  • Flexible Direct control over the video stream with easy manipulation ability

  • Lightweight

  • Built-in Robust Error and frame synchronization Handling

  • Multi-Platform compatibility(Compatible with Raspberry Pi Camera also.)

  • Full Support for Network Video Streams(Including Gstreamer Raw Video Capture Pipeline)

Find elsewhere
🌐
OpenCV Q&A Forum
answers.opencv.org › question › 163564 › does-opencv-have-any-multi-threading-under-the-hood
Does OpenCV have any multi threading under the hood? - OpenCV Q&A Forum
July 3, 2017 - I will assume that since I did not see predict() in that search that the answer to the first question is No while the answer to the second question is Yes. ... By the way, why doesn't opencv use multithreading by default? Is it being planned to introduce such a functionality?
🌐
OpenCV Q&A Forum
answers.opencv.org › question › 216815 › opencv-python-and-multi-threading
opencv-python and multi-threading - OpenCV Q&A Forum
Python has GIL that makes multi-threading is less efficient. Opencv-python will release GIL when calling C/C++ function. Therefore, I think that I can use many threads to run tasks with opencv without lost parallel efficiency. For example, I can run a capture thread, a pre-processing thread ...
🌐
Reddit
reddit.com › r/opencv › [question] is opencv thread-safe?
r/opencv on Reddit: [Question] Is OpenCV thread-safe?
March 2, 2022 -

Hey folks.

I have a program that is multi-threading. Main thread gets the image from the camera and process it, then in another thread I write the finished images using imwrite. After I've implemented this method, and I've done it because we've increased the image size and that increased write times dramatically, the program started crashing randomly. I'm guessing it's because the thread.

The structure is as follows (simplified):

void process_input()

{

thread th_im(write_frames);

video_cap.open(video_path);

video_cap >> frame;

// Image is processed

jqueue.push_back({frame_path, frame.clone());

}

void write_frames()
{
while(true)
    {   
if (jqueue.size() > 0) {
jqueue.front().write(); // imwrite(filepath, frame, params);  
jqueue.erase(jqueue.begin());
}
else {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
    }
}

Do you think this program is thread-safe? Or what is the problem if it's not?

🌐
Pysource
pysource.com › home › blog › increase opencv speed by 2x with python and multithreading | tutorial
Increase OpenCV speed by 2x with Python and Multithreading | Tutorial - Pysource
October 15, 2024 - To speed up OpenCV, we need to introduce multi-threading. OpenCV Multithreading in a linear approach, while the program is busy displaying the current frame, it is not capturing the next frame.
🌐
OpenCV Q&A Forum
answers.opencv.org › question › 36065 › turn-onoff-multithreading
Turn on/off multithreading? - OpenCV Q&A Forum
July 1, 2014 - The motivation to turn off multithreading is to do performance testing, to see how my code runs faster or slower, serially, based on different code changes. Is there a compile flag or function call I need to do? ... it's all done in the cmake stage, when building the libs. if you don't enable anything (like openmp or similar) there, it will run single-threaded anyway. ... If your OpenCV version was compiled with TBB, then the answer is no way, I suppose.
🌐
How to use OpenCV
opencvhelp.org › tutorials › best-practices › multi-threading-gpu-acceleration
Best Practices for Multi-Threading and GPU Acceleration in OpenCV
OpenCV provides several functions for multi-threading and GPU acceleration, such as cv::parallel_for_(), cv::gpu::GpuMat, and cv::cuda::GpuMat. In this tutorial, we’ll explore the best practices for using these functions in OpenCV.
🌐
Medium
sihabsahariar.medium.com › a-multi-threading-approach-for-faster-opencv-video-streaming-in-python-7324f11dbd2f
A Multi-Threading Approach for Faster OpenCV Video Streaming in Python | by Sihab Sahariar | Medium
September 20, 2022 - Python OpenCV streaming from camera — multithreading, timestamps · Video Streaming from IP Camera in Python Using OpenCV cv2.VideoCapture · How to capture multiple camera streams with OpenCV? OpenCV real time streaming video capture is slow.
🌐
PyImageSearch
pyimagesearch.com › home › blog › multiprocessing with opencv and python
Multiprocessing with OpenCV and Python - PyImageSearch
December 29, 2022 - The image hashing post she is referring to is singled threaded, meaning that only one core of the processor is being utilized — if we switch to using multiple threads/processes we can dramatically speed up the hashing process.
Top answer
1 of 2
1

I think multiprocessing will work when you are running the function for multiple images at the same time.

Right now you are using a for loop and passing one image at a time to a single process.

Try the following approach and compare the time this takes with your original approach.

if __name__ == '__main__':
    p1 = Process(target=Upscale,args(file_list[0:len(file_list)//2]))
    p1.start()
    p2 = Process(target=Upscale,args(file_list[len(file_list)//2:len(file_list)]))
    p2.start()
    p1.join()
    p2.join()

Inside the Upscale function, make a for loop and loop through the images, and perform the same tasks as before.

Also, note that the function's argument is mentioned separately in "args" of the function "multiprocessing.Process".

P.S This is my first time answering, let me know if something is not clear.

For the output, you can try the following approach, I picked it up online through this https://superfastpython.com/multiprocessing-return-value-from-process/

# example of returning a variable from a process using a value
from random import random
from time import sleep
from multiprocessing import Value
from multiprocessing import Process

# function to execute in a child process
def task(variable):
    # generate some data
    data = random()
    # block, to simulate computational effort
    print(f'Generated {data}', flush=True)
    sleep(data)
    # return data via value
    variable.value = data

# protect the entry point
if __name__ == '__main__':
    # create shared variable
    variable = Value('f', 0.0)
    # create a child process process
    process = Process(target=task, args=(variable,))
    # start the process
    process.start()
    # wait for the process to finish
    process.join()
    # report return value
    print(f'Returned: {variable.value}')
2 of 2
1

Multithreading / multiprocessing can be inefficient or even counterproductive when used to optimise the execution of neural networks on CPUs since a network execution may already be multithreaded.

Before any optimisation work you should first profile your code in order to identify what is slow and what can be improved. Here is some relevant questions you can ask yourself during this optimisation process:

  • Does executing a single network already max out all the CPU's?
  • Is it possible to execute the network on a faster accelerator such as the GPU?
  • In the first place, is your network optimised (FP16, vectorisation, etc.)?
  • Is OpenCV up to date and compiled to take advantage of all the available compute power?
  • What is the memory footprint of a single network and how many could you execute at the same time on the CPU without out of memory errors?
  • Is there any unnecessary redundant allocation (such as the one I pointed out in another of your question)?
  • Are there obvious operations that would greatly benefit from being run concurrently (such as imwrite and imread being memory-bound while upscale is compute-bound)?

This list is not exhaustive, try to search for methods to profile, benchmark and optimise neural networks executions.