Working on a personal machine learning project, I would like to train a model which can recognize my son.
The first step is to extract my son’s faces from about 20K pictures. OpenCV can help a lot. It’s very handy and there already has the face cascade. Now the point is how to make the image processing faster. As a Java programmer, processing it in multiple threads is the first solution to try. After some searching, a lot of comments led me to boost::asio.
I was a C++ developer before C++11. I have to say, in the last several years, C++ got greatly improved. With boost::asio in C++, it becomes much easier to implement a simple thread pool, similar to Java concurrency.
thread_pool.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
#ifndef __THREAD_POOL_H__ #define __THREAD_POOL_H__ #include <boost/asio.hpp> #include <vector> #include <memory> #include <boost/thread.hpp> class ThreadPool; class Worker { public: Worker(ThreadPool&); void operator()(); private: ThreadPool& m_pool; }; class ThreadPool { public: explicit ThreadPool(size_t); ~ThreadPool(); template<typename F> void enqueue(F f); private: std::vector<std::unique_ptr<boost::thread>> m_workThreads; boost::asio::io_service m_ioService; boost::asio::io_service::work m_work; friend class Worker; }; template<typename F> void ThreadPool::enqueue(F f) { m_ioService.post(f); } #endif |
thread_pool.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
#include "thread_pool.h" using namespace boost; using namespace std; Worker::Worker(ThreadPool& aPool) : m_pool(aPool) { } void Worker::operator()() { m_pool.m_ioService.run(); } ThreadPool::ThreadPool(size_t sizeOfWorkerThreads) : m_work(m_ioService) { for (auto i = 0; i < sizeOfWorkerThreads; ++i) { m_workThreads.push_back( unique_ptr<boost::thread>(new boost::thread(Worker(*this)))); } } ThreadPool::~ThreadPool() { m_ioService.stop(); for (auto& workThread : m_workThreads) { workThread->join(); } } |
Image processing code to make pictures smaller.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
int doMain5(int, char**) { ThreadPool threadPool(10); fs::path imgFolderPath("H:\\export_files"); fs::directory_entry facesDirEntry(imgFolderPath); auto index = 1; for(auto& p : fs::directory_iterator(imgFolderPath)) { if (p.path().string().find("smaller") != string::npos) { cout << index << ": Skip the path of " << p.path() << endl; index++; continue; } threadPool.enqueue([p, imgFolderPath, index] { Mat img = imread(p.path().string()); Mat imgSmallerOne; resize(img, imgSmallerOne, Size(), 0.4, 0.4); stringstream ss; ss << p.path().stem() << "_smaller.jpg"; cout << index << ": Write resized img into file of " << ss.str() << endl; fs::path newPath = fs::path(imgFolderPath) / fs::path(ss.str()).c_str(); imwrite(newPath.string(), imgSmallerOne); fs::remove(p); }); index++; } return 0; } |