Skip to content

Commit 51ba2b7

Browse files
authored
Merge pull request #32 from Digitelektro/develop
Develop
2 parents aecc228 + d791155 commit 51ba2b7

7 files changed

Lines changed: 270 additions & 42 deletions

File tree

CMakeLists.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ project(Meteordemod LANGUAGES CXX)
66

77
set(CMAKE_CXX_STANDARD 14)
88
set(CMAKE_CXX_STANDARD_REQUIRED ON)
9+
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
910

1011
if (NOT CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "")
1112
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "" FORCE)
@@ -81,6 +82,8 @@ add_executable(meteordemod
8182
tools/databuffer.h
8283
tools/iniparser.cpp
8384
tools/iniparser.h
85+
tools/threadpool.cpp
86+
tools/threadpool.h
8487
GIS/shapereader.cpp
8588
GIS/shapereader.h
8689
GIS/shaperenderer.cpp
@@ -139,7 +142,7 @@ if(UNIX AND NOT APPLE)
139142
if (DEBIAN_FOUND)
140143
SET(CPACK_GENERATOR "DEB")
141144
SET(CPACK_PACKAGE_VERSION_MAJOR "2")
142-
SET(CPACK_PACKAGE_VERSION_MINOR "1")
145+
SET(CPACK_PACKAGE_VERSION_MINOR "2")
143146
SET(CPACK_PACKAGE_VERSION_PATCH "0")
144147
SET(CPACK_DEBIAN_PACKAGE_MAINTAINER "Digitelektro")
145148
SET(CPACK_DEBIAN_PACKAGE_HOMEPAGE "https://github.com/Digitelektro/MeteorDemod")

MeteorDemod.pro

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ SOURCES += \
3131
tools/databuffer.cpp \
3232
tools/iniparser.cpp \
3333
tools/pixelgeolocationcalculator.cpp \
34+
tools/threadpool.cpp \
3435
tools/tlereader.cpp \
3536
tools/matrix.cpp \
3637
tools/vector.cpp \
@@ -67,6 +68,7 @@ HEADERS += \
6768
tools/iniparser.h \
6869
tools/pixelgeolocationcalculator.h \
6970
tools/matrix.h \
71+
tools/threadpool.h \
7072
tools/tlereader.h \
7173
tools/vector.h \
7274
tools/databuffer.h \

common/version.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#define VERSION_H
33

44
#define VERSION_MAJOR 2
5-
#define VERSION_MINOR 1
5+
#define VERSION_MINOR 2
66
#define VERSION_FIX 0
77

88
#endif // VERSION_H

main.cpp

Lines changed: 53 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#include "tlereader.h"
1919
#include "settings.h"
2020

21+
#include "threadpool.h"
22+
2123
struct ImageForSpread {
2224
ImageForSpread(cv::Mat img, std::string fileNamebase)
2325
: image(img)
@@ -34,6 +36,7 @@ int mean(int cur, int prev);
3436
void differentialDecode(int8_t *data, int64_t len);
3537
int8_t clamp(float x);
3638

39+
static std::mutex saveImageMutex;
3740

3841
static uint16_t intSqrtTable[32768];
3942

@@ -72,6 +75,7 @@ static Viterbi mViterbi;
7275
static PacketParser mPacketParser;
7376
static ReedSolomon mReedSolomon;
7477
static Settings &mSettings = Settings::getInstance();
78+
static ThreadPool mThreadPool(std::thread::hardware_concurrency());
7579

7680
int main(int argc, char *argv[])
7781
{
@@ -84,6 +88,7 @@ int main(int argc, char *argv[])
8488
mSettings.parseArgs(argc, argv);
8589
mSettings.parseIni(mSettings.getResourcesPath() + "settings.ini");
8690

91+
mThreadPool.start();
8792
TleReader reader(mSettings.getTlePath());
8893
TleReader::TLE tle;
8994
reader.processFile();
@@ -291,11 +296,15 @@ int main(int argc, char *argv[])
291296
}
292297

293298
} else if(mPacketParser.isChannel64Available() && mPacketParser.isChannel65Available() && mPacketParser.isChannel66Available()) {
294-
cv::Mat threatedImage = mPacketParser.getRGBImage(PacketParser::APID_66, PacketParser::APID_65, PacketParser::APID_64, mSettings.fillBackLines());
299+
cv::Mat threatedImage1 = mPacketParser.getRGBImage(PacketParser::APID_66, PacketParser::APID_65, PacketParser::APID_64, mSettings.fillBackLines());
300+
cv::Mat threatedImage2 = mPacketParser.getRGBImage(PacketParser::APID_65, PacketParser::APID_65, PacketParser::APID_64, mSettings.fillBackLines());
295301

296-
if(!ThreatImage::isNightPass(threatedImage, mSettings.getNightPassTreshold())) {
297-
imagesToSpread.push_back(ImageForSpread(threatedImage, "123_"));
298-
saveImage(mSettings.getOutputPath() + fileNameDate + "_123.bmp", threatedImage);
302+
if(!ThreatImage::isNightPass(threatedImage1, mSettings.getNightPassTreshold())) {
303+
imagesToSpread.push_back(ImageForSpread(threatedImage1, "321_"));
304+
saveImage(mSettings.getOutputPath() + fileNameDate + "_321.bmp", threatedImage1);
305+
306+
imagesToSpread.push_back(ImageForSpread(threatedImage2, "221_"));
307+
saveImage(mSettings.getOutputPath() + fileNameDate + "_221.bmp", threatedImage2);
299308
} else {
300309
std::cout << "Night pass, RGB image skipped, threshold set to: " << mSettings.getNightPassTreshold() << std::endl;
301310
}
@@ -306,7 +315,7 @@ int main(int argc, char *argv[])
306315

307316
cv::Mat ch64 = mPacketParser.getChannelImage(PacketParser::APID_64, mSettings.fillBackLines());
308317
cv::Mat ch65 = mPacketParser.getChannelImage(PacketParser::APID_65, mSettings.fillBackLines());
309-
cv::Mat ch66 = mPacketParser.getChannelImage(PacketParser::APID_68, mSettings.fillBackLines());
318+
cv::Mat ch66 = mPacketParser.getChannelImage(PacketParser::APID_66, mSettings.fillBackLines());
310319

311320
saveImage(mSettings.getOutputPath() + fileNameDate + "_64.bmp", ch64);
312321
saveImage(mSettings.getOutputPath() + fileNameDate + "_65.bmp", ch65);
@@ -346,61 +355,68 @@ int main(int argc, char *argv[])
346355
return 0;
347356
}
348357

349-
SpreadImage spreadImage;
350358
std::ostringstream oss;
351359
oss << std::setfill('0') << std::setw(2) << passStart.Day() << "/" << std::setw(2) << passStart.Month() << "/" << passStart.Year() << " " << std::setw(2) << passStart.Hour() << ":" << std::setw(2) << passStart.Minute() << ":" << std::setw(2) << passStart.Second() << " UTC";
352360
std::string dateStr = oss.str();
353361

354362
std::list<ImageForSpread>::const_iterator it;
355-
356-
int c = 1;
357-
for(it = imagesToSpread.begin(); it != imagesToSpread.end(); ++it, c++) {
363+
for(it = imagesToSpread.begin(); it != imagesToSpread.end(); ++it) {
358364
std::string fileName = (*it).fileNameBase + fileNameDate + "." + mSettings.getOutputFormat();
359365

360366
if(mSettings.spreadImage()) {
361-
cv::Mat strechedImg = spreadImage.stretch((*it).image);
362-
363-
if(!strechedImg.empty()) {
364-
ThreatImage::drawWatermark(strechedImg, dateStr);
365-
saveImage(mSettings.getOutputPath() + std::string("spread_") + fileName, strechedImg);
366-
} else {
367-
std::cout << "Failed to strech image" << std::endl;
368-
}
367+
mThreadPool.addJob([=]() {
368+
SpreadImage spreadImage;
369+
cv::Mat strechedImg = spreadImage.stretch((*it).image);
370+
371+
if(!strechedImg.empty()) {
372+
ThreatImage::drawWatermark(strechedImg, dateStr);
373+
saveImage(mSettings.getOutputPath() + std::string("spread_") + fileName, strechedImg);
374+
} else {
375+
std::cout << "Failed to strech image" << std::endl;
376+
}
377+
});
369378
}
370379

371380
if(mSettings.mercatorProjection()) {
372-
cv::Mat mercator = spreadImage.mercatorProjection((*it).image, calc, [c, &imagesToSpread](float percent) {
373-
std::cout << "Spreading mercator " << c << " of " << imagesToSpread.size() << " " << static_cast<int>(percent) << "%\t\t\r" << std::flush;
381+
mThreadPool.addJob([=]() {
382+
SpreadImage spreadImage;
383+
cv::Mat mercator = spreadImage.mercatorProjection((*it).image, calc);
384+
385+
if(!mercator.empty()) {
386+
ThreatImage::drawWatermark(mercator, dateStr);
387+
saveImage(mSettings.getOutputPath() + std::string("mercator_") + fileName, mercator);
388+
} else {
389+
std::cout << "Failed to create mercator projection" << std::endl;
390+
}
374391
});
375-
std::cout << std::endl;
376-
377-
if(!mercator.empty()) {
378-
ThreatImage::drawWatermark(mercator, dateStr);
379-
saveImage(mSettings.getOutputPath() + std::string("mercator_") + fileName, mercator);
380-
} else {
381-
std::cout << "Failed to create mercator projection" << std::endl;
382-
}
383392
}
384393

385394
if(mSettings.equadistantProjection()) {
386-
cv::Mat equidistant = spreadImage.equidistantProjection((*it).image, calc, [c, &imagesToSpread](float percent) {
387-
std::cout << "Spreading equidistant " << c << " of " << imagesToSpread.size() << " " << static_cast<int>(percent) << "%\t\t\r" << std::flush;
395+
mThreadPool.addJob([=]() {
396+
SpreadImage spreadImage;
397+
cv::Mat equidistant = spreadImage.equidistantProjection((*it).image, calc);
398+
399+
if(!equidistant.empty()) {
400+
ThreatImage::drawWatermark(equidistant, dateStr);
401+
saveImage(mSettings.getOutputPath() + std::string("equidistant_") + fileName, equidistant);
402+
} else {
403+
std::cout << "Failed to create equidistant projection" << std::endl;
404+
}
388405
});
389-
std::cout << std::endl;
390-
391-
if(!equidistant.empty()) {
392-
ThreatImage::drawWatermark(equidistant, dateStr);
393-
saveImage(mSettings.getOutputPath() + std::string("equidistant_") + fileName, equidistant);
394-
} else {
395-
std::cout << "Failed to create equidistant projection" << std::endl;
396-
}
397406
}
398407
}
408+
409+
std::cout << "Generate images" << std::endl;
410+
mThreadPool.stop();
411+
std::cout << "Generate images done" << std::endl;
412+
399413
return 0;
400414
}
401415

402416
void saveImage(const std::string fileName, const cv::Mat &image)
403417
{
418+
std::unique_lock<decltype(saveImageMutex)>lock(saveImageMutex);
419+
404420
std::vector<int> compression_params;
405421
compression_params.push_back(cv::IMWRITE_JPEG_QUALITY);
406422
compression_params.push_back(mSettings.getJpegQuality());

readme.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,8 @@ Other settings can be found in the settings.ini file.
7777
Master branch is for the latest stable version, beta branch for beta versions, development is ongoing on other branches.
7878

7979
## Future developments
80-
- More precise image overlays
81-
- Rain overlay
8280
- Composite output from multiple passes
8381
- Support dead Meteor M2 2 satellite (it may be required for future satellites)
84-
- Multithreading, faster image processing
8582

8683

8784
## Example Outputs

tools/threadpool.cpp

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#include "threadpool.h"
2+
3+
ThreadPool::ThreadPool(int numOfThreads)
4+
: mNumberOfThreads(numOfThreads)
5+
, mIsRuning(false)
6+
{
7+
8+
}
9+
10+
ThreadPool::~ThreadPool()
11+
{
12+
if(mIsRuning) {
13+
stop();
14+
}
15+
}
16+
17+
void ThreadPool::start()
18+
{
19+
mIsRuning = true;
20+
21+
for (int i = 0; i < mNumberOfThreads; i++)
22+
{
23+
mThreads.push_back(std::thread(&ThreadPool::threadLoop, this));
24+
}
25+
}
26+
27+
void ThreadPool::stop()
28+
{
29+
waitForAllJobsDone();
30+
31+
{
32+
std::unique_lock<std::mutex> lock(mQueueMutex);
33+
mIsRuning = false;
34+
}
35+
36+
mConditionVariable.notify_all(); // wake up all threads.
37+
38+
for (std::thread &th : mThreads)
39+
{
40+
if(th.joinable())
41+
{
42+
th.join();
43+
}
44+
}
45+
46+
mThreads.clear();
47+
}
48+
49+
void ThreadPool::addJob(JobFunction_t task)
50+
{
51+
{
52+
std::unique_lock<std::mutex> lock(mQueueMutex);
53+
mJobCounter++;
54+
mJobsQueue.push(task);
55+
}
56+
57+
mConditionVariable.notify_one();
58+
}
59+
60+
void ThreadPool::threadLoop()
61+
{
62+
JobFunction_t job;
63+
64+
while (true)
65+
{
66+
{
67+
std::unique_lock<std::mutex> lock(mQueueMutex);
68+
69+
mConditionVariable.wait(lock, [this](){
70+
return !mJobsQueue.empty() || !mIsRuning;
71+
});
72+
73+
if(!mIsRuning) {
74+
break;
75+
}
76+
77+
job = mJobsQueue.front();
78+
mJobsQueue.pop();
79+
}
80+
job();
81+
82+
mJobCounter--;
83+
}
84+
}

0 commit comments

Comments
 (0)