Compare commits
36 Commits
Author | SHA1 | Date |
---|---|---|
![]() |
9e0d7a34cd | 12 months ago |
![]() |
773734e6be | 12 months ago |
![]() |
45ef16522d | 1 year ago |
![]() |
3775fcfb1a | 1 year ago |
![]() |
f4beff5fc9 | 1 year ago |
![]() |
476cd5f28a | 1 year ago |
![]() |
aec946622c | 1 year ago |
![]() |
53978fe62c | 1 year ago |
![]() |
609997f878 | 1 year ago |
![]() |
d8a45f7e36 | 1 year ago |
![]() |
25e9e79159 | 1 year ago |
![]() |
d7a438b14c | 1 year ago |
![]() |
1a6f619db6 | 1 year ago |
![]() |
c069025ee6 | 1 year ago |
![]() |
5b9dbbb286 | 1 year ago |
![]() |
9f177afc05 | 1 year ago |
![]() |
10e22bdfaf | 1 year ago |
![]() |
b12e6ef392 | 1 year ago |
![]() |
cea91493db | 1 year ago |
![]() |
fea2b31c15 | 1 year ago |
![]() |
6b1fd2f0e3 | 1 year ago |
![]() |
0baa99402d | 1 year ago |
![]() |
cefc4dc4c5 | 1 year ago |
![]() |
d5703a23fd | 1 year ago |
![]() |
b1852b8259 | 1 year ago |
![]() |
fdfc884cf3 | 1 year ago |
![]() |
58422814e6 | 1 year ago |
![]() |
6abd14cfa7 | 1 year ago |
![]() |
391d304fef | 1 year ago |
![]() |
f889f0dfc2 | 1 year ago |
![]() |
b2f0db9b90 | 1 year ago |
![]() |
6641250cc2 | 1 year ago |
![]() |
116efb461a | 1 year ago |
![]() |
ffeb1beb1d | 1 year ago |
![]() |
fa8a5423ef | 1 year ago |
![]() |
550db09287 | 1 year ago |
@ -0,0 +1,7 @@ |
||||
Copyright © 2021 Alister Sanders (alister@sugol.org) |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
@ -1,3 +0,0 @@ |
||||
#!/bin/bash |
||||
|
||||
convert ../icons/org.sugol.books-16.png ../icons/org.sugol.books-32.png ../icons/org.sugol.books-256.png books.ico |
@ -1,19 +0,0 @@ |
||||
#include <gtkmm.h> |
||||
#include <mainwindow.hpp> |
||||
#include <ui-resources.h> |
||||
|
||||
static void on_startup(Glib::RefPtr<Gtk::Application> app) { |
||||
ui::MainWindow* window = ui::MainWindow::create(); |
||||
app->add_window(*window); |
||||
window->show(); |
||||
} |
||||
|
||||
int main(int argc, char *argv[]) { |
||||
auto resource_bundle = Glib::wrap(ui_res_get_resource()); |
||||
resource_bundle->register_global(); |
||||
|
||||
auto app = Gtk::Application::create("org.sugol.books"); |
||||
app->signal_startup().connect([&]() { on_startup(app); }); |
||||
|
||||
return app->run(argc, argv); |
||||
} |
Before Width: | Height: | Size: 390 B After Width: | Height: | Size: 390 B |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 522 B After Width: | Height: | Size: 522 B |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 7.7 KiB |
@ -0,0 +1,22 @@ |
||||
#!/bin/bash |
||||
|
||||
# Copyright (C) 2021 Alister Sanders |
||||
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
# of this software and associated documentation files (the "Software"), to deal |
||||
# in the Software without restriction, including without limitation the rights |
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
# copies of the Software, and to permit persons to whom the Software is |
||||
# furnished to do so, subject to the following conditions: |
||||
# The above copyright notice and this permission notice shall be included in |
||||
# all copies or substantial portions of the Software. |
||||
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
||||
# THE SOFTWARE. |
||||
|
||||
convert ../icons/org.sugol.books-16.png ../icons/org.sugol.books-32.png ../icons/org.sugol.books-256.png books.ico |
@ -1,35 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include <optional> |
||||
|
||||
#include <featuredetectorparams.hpp> |
||||
#include <fitnessmetrics.hpp> |
||||
#include <imagedata.hpp> |
||||
#include <worker.hpp> |
||||
|
||||
namespace worker { |
||||
class FeatureDetector : public Worker<img::ImageData, img::ImageData> { |
||||
public: |
||||
const double CV_IMAGE_TARGET_DIMENSION = 400.0; |
||||
|
||||
FeatureDetector(std::shared_ptr<InputQueue> input_queue, |
||||
std::shared_ptr<OutputQueue> output_queue, |
||||
const std::vector<ft::FitnessMetric>& fitness_metrics, |
||||
const std::vector<float>& fitness_metric_weights, |
||||
const FeatureDetectorParams& params); |
||||
|
||||
void run(IWorkerPool* wp) override; |
||||
|
||||
private: |
||||
cv::UMat apply_filters(const cv::UMat& mat); |
||||
void find_features(img::ImageData& image_data); |
||||
double resize_mat(const cv::UMat& src, cv::UMat& dest); |
||||
float calculate_fitness(const cv::Mat& mat, const util::Box& box); |
||||
std::optional<img::ImageData::Feature> best_candidate_box(std::vector<img::ImageData::Feature>& features); |
||||
|
||||
private: |
||||
std::vector<ft::FitnessMetric> m_fitness_metrics; |
||||
std::vector<float> m_fitness_weights; |
||||
const FeatureDetectorParams& m_params; |
||||
}; |
||||
} |
@ -1,18 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include <cstdint> |
||||
|
||||
namespace worker { |
||||
struct FeatureDetectorParams { |
||||
FeatureDetectorParams(uint8_t blur = 11, |
||||
uint8_t dilate = 4, |
||||
uint8_t threshold = 50) |
||||
: blur_kernel_size(blur), |
||||
dilate_kernel_size(dilate), |
||||
threshold(threshold) { } |
||||
|
||||
uint8_t blur_kernel_size; |
||||
uint8_t dilate_kernel_size; |
||||
uint8_t threshold; |
||||
}; |
||||
} |
@ -1,80 +0,0 @@ |
||||
#include <featuredetectorpool.hpp> |
||||
|
||||
namespace worker { |
||||
FeatureDetectorPool::FeatureDetectorPool(size_t n_workers, |
||||
std::vector<ft::FitnessMetric> fitness_metrics, |
||||
std::vector<float> fitness_weights, |
||||
FeatureDetectorParams params) |
||||
: m_params(params) { |
||||
m_active_workers = n_workers; |
||||
m_stopped = false; |
||||
m_input_queue = std::make_shared<InputQueue>(); |
||||
m_output_queue = std::make_shared<OutputQueue>(); |
||||
|
||||
for (size_t i = 0; i < n_workers; i++) { |
||||
m_workers.push_back(std::make_unique<FeatureDetector>(m_input_queue, |
||||
m_output_queue, |
||||
fitness_metrics, |
||||
fitness_weights, |
||||
m_params)); |
||||
} |
||||
} |
||||
|
||||
FeatureDetectorPool::~FeatureDetectorPool() { |
||||
join_all(); |
||||
} |
||||
|
||||
std::shared_ptr<FeatureDetectorPool::InputQueue> FeatureDetectorPool::input() { |
||||
return m_input_queue; |
||||
} |
||||
|
||||
std::shared_ptr<FeatureDetectorPool::OutputQueue> FeatureDetectorPool::output() { |
||||
return m_output_queue; |
||||
} |
||||
|
||||
void FeatureDetectorPool::set_input(std::shared_ptr<InputQueue> in) { |
||||
m_input_queue = in; |
||||
|
||||
for (auto& worker : m_workers) { |
||||
worker->set_input_queue(m_input_queue); |
||||
} |
||||
} |
||||
|
||||
void FeatureDetectorPool::set_output(std::shared_ptr<OutputQueue> out) { |
||||
m_output_queue = out; |
||||
} |
||||
|
||||
void FeatureDetectorPool::run_workers() { |
||||
for (auto& worker : m_workers) { |
||||
worker->run(this); |
||||
} |
||||
} |
||||
|
||||
void FeatureDetectorPool::join_all() { |
||||
for (auto& worker : m_workers) { |
||||
worker->join(); |
||||
} |
||||
} |
||||
|
||||
void FeatureDetectorPool::signal_done() { |
||||
std::lock_guard lock(m_mutex); |
||||
m_active_workers--; |
||||
|
||||
if (m_active_workers == 0) { |
||||
m_output_queue->finish(); |
||||
} |
||||
} |
||||
|
||||
void FeatureDetectorPool::stop() { |
||||
m_input_queue->finish(); |
||||
m_input_queue->clear(); |
||||
m_output_queue->finish(); |
||||
m_output_queue->clear(); |
||||
|
||||
m_stopped = true; |
||||
} |
||||
|
||||
bool FeatureDetectorPool::stopped() { |
||||
return m_stopped; |
||||
} |
||||
} |
@ -1,38 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include <featuredetector.hpp> |
||||
#include <featuredetectorparams.hpp> |
||||
#include <workerpool.hpp> |
||||
|
||||
namespace worker { |
||||
class FeatureDetectorPool : public WorkerPool<FeatureDetector> { |
||||
public: |
||||
FeatureDetectorPool() { } |
||||
FeatureDetectorPool(size_t n_workers, |
||||
std::vector<ft::FitnessMetric> fitness_metrics, |
||||
std::vector<float> fitness_weights, |
||||
FeatureDetectorParams params = FeatureDetectorParams()); |
||||
|
||||
~FeatureDetectorPool(); |
||||
|
||||
std::shared_ptr<InputQueue> input() override; |
||||
std::shared_ptr<OutputQueue> output() override; |
||||
void set_input(std::shared_ptr<InputQueue> in) override; |
||||
void set_output(std::shared_ptr<OutputQueue> out) override; |
||||
|
||||
void run_workers() override; |
||||
void join_all() override; |
||||
void signal_done() override; |
||||
void stop() override; |
||||
bool stopped() override; |
||||
|
||||
private: |
||||
std::shared_ptr<InputQueue> m_input_queue; |
||||
std::shared_ptr<OutputQueue> m_output_queue; |
||||
mutable std::mutex m_mutex; |
||||
size_t m_active_workers; |
||||
std::vector<std::unique_ptr<FeatureDetector>> m_workers; |
||||
FeatureDetectorParams m_params; |
||||
bool m_stopped; |
||||
}; |
||||
} |
@ -1,13 +0,0 @@ |
||||
#include "opencv2/imgproc.hpp" |
||||
#include <filter/bgr2grey.hpp> |
||||
|
||||
namespace filter { |
||||
BGR2GreyFilter::~BGR2GreyFilter() {} |
||||
|
||||
cv::Mat BGR2GreyFilter::apply(const cv::Mat &img) { |
||||
cv::Mat img_grey; |
||||
cv::cvtColor(img, img_grey, cv::COLOR_BGR2GRAY); |
||||
|
||||
return img_grey; |
||||
} |
||||
} |
@ -1,11 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include <filter/filter.hpp> |
||||
|
||||
namespace filter { |
||||
class BGR2GreyFilter : public Filter { |
||||
public: |
||||
~BGR2GreyFilter(); |
||||
cv::Mat apply(cv::Mat const& img) override; |
||||
}; |
||||
} |
@ -1,25 +0,0 @@ |
||||
#include "opencv2/imgproc.hpp" |
||||
#include <filter/canny.hpp> |
||||
|
||||
namespace filter { |
||||
CannyFilter::~CannyFilter() { |
||||
} |
||||
|
||||
cv::Mat CannyFilter::apply(const cv::Mat& img) { |
||||
double low_thres, high_thres; |
||||
get_thresholds(img, low_thres, high_thres); |
||||
|
||||
cv::Mat canny; |
||||
cv::Canny(img, canny, low_thres, high_thres); |
||||
|
||||
return canny; |
||||
} |
||||
|
||||
void CannyFilter::get_thresholds(const cv::Mat& img, double& low, double& high) { |
||||
cv::Mat dummy; |
||||
|
||||
// Automagically determine threshold values for the canny filter. Do you know how this works? I sure don't.
|
||||
high = cv::threshold(img, dummy, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU); |
||||
low = 0.5 * high; |
||||
} |
||||
} |
@ -1,13 +0,0 @@ |
||||
#pragma once |
||||
#include <filter/filter.hpp> |
||||
|
||||
namespace filter { |
||||
class CannyFilter : public Filter { |
||||
public: |
||||
~CannyFilter(); |
||||
cv::Mat apply(cv::Mat const& img) override; |
||||
|
||||
private: |
||||
void get_thresholds(cv::Mat const& img, double& low, double& high); |
||||
}; |
||||
} |
@ -1,17 +0,0 @@ |
||||
#include <filter/dilate.hpp> |
||||
|
||||
namespace filter { |
||||
DilateFilter::DilateFilter(int kernel_size) |
||||
: m_kernelSize(kernel_size) { } |
||||
|
||||
DilateFilter::~DilateFilter() {} |
||||
|
||||
cv::Mat DilateFilter::apply(const cv::Mat &img) { |
||||
cv::Mat dilated; |
||||
cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(m_kernelSize, m_kernelSize)); |
||||
|
||||
cv::dilate(img, dilated, kernel); |
||||
|
||||
return dilated; |
||||
} |
||||
} |
@ -1,15 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include <filter/filter.hpp> |
||||
|
||||
namespace filter { |
||||
class DilateFilter : public Filter { |
||||
public: |
||||
DilateFilter(int kernel_size = 8); |
||||
~DilateFilter(); |
||||
cv::Mat apply(cv::Mat const& img) override; |
||||
|
||||
private: |
||||
int m_kernelSize; |
||||
}; |
||||
} |
@ -1,11 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include <opencv2/imgproc.hpp> |
||||
|
||||
namespace filter { |
||||
class Filter { |
||||
public: |
||||
virtual ~Filter() { }; |
||||
virtual cv::Mat apply(cv::Mat const& img) = 0; |
||||
}; |
||||
} |
@ -1,34 +0,0 @@ |
||||
#include "filter/canny.hpp" |
||||
#include "filter/medianblur.hpp" |
||||
#include <filter/filterchain.hpp> |
||||
|
||||
#include <filter/filters_all.hpp> |
||||
|
||||
namespace filter { |
||||
FilterChain::FilterChain() { |
||||
// Construct the default filter chain
|
||||
// TODO: Allow for custom filter chains
|
||||
|
||||
m_filters.emplace_back(new BGR2GreyFilter); |
||||
m_filters.emplace_back(new MedianBlurFilter(11)); |
||||
m_filters.emplace_back(new NormaliseFilter); |
||||
m_filters.emplace_back(new DilateFilter(4)); |
||||
m_filters.emplace_back(new ThresholdFilter); |
||||
m_filters.emplace_back(new CannyFilter); |
||||
} |
||||
|
||||
FilterChain::~FilterChain() { |
||||
for (auto filter : m_filters){ |
||||
delete filter; |
||||
} |
||||
} |
||||
|
||||
cv::Mat FilterChain::apply_filters(const cv::Mat& img) { |
||||
cv::Mat filter_result = img; |
||||
for (auto& filter : m_filters) { |
||||
filter_result = filter->apply(filter_result); |
||||
} |
||||
|
||||
return filter_result; |
||||
} |
||||
} |
@ -1,19 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include <opencv2/imgproc.hpp> |
||||
#include <vector> |
||||
#include <map> |
||||
|
||||
#include <filter/filter.hpp> |
||||
|
||||
namespace filter { |
||||
class FilterChain { |
||||
public: |
||||
FilterChain(); |
||||
~FilterChain(); |
||||
cv::Mat apply_filters(const cv::Mat& img); |
||||
|
||||
private: |
||||
std::vector<Filter*> m_filters; |
||||
}; |
||||
} |
@ -1,8 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include <filter/bgr2grey.hpp> |
||||
#include <filter/medianblur.hpp> |
||||
#include <filter/normalise.hpp> |
||||
#include <filter/dilate.hpp> |
||||
#include <filter/threshold.hpp> |
||||
#include <filter/canny.hpp> |
@ -1,16 +0,0 @@ |
||||
#include "opencv2/imgproc.hpp" |
||||
#include <filter/medianblur.hpp> |
||||
|
||||
namespace filter { |
||||
MedianBlurFilter::MedianBlurFilter(int kernel_size) |
||||
: m_kernel_size(kernel_size) { } |
||||
|
||||
MedianBlurFilter::~MedianBlurFilter() {} |
||||
|
||||
cv::Mat MedianBlurFilter::apply(const cv::Mat& img) { |
||||
cv::Mat blurred; |
||||
cv::medianBlur(img, blurred, m_kernel_size); |
||||
|
||||
return blurred; |
||||
} |
||||
} |
@ -1,15 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include <filter/filter.hpp> |
||||
|
||||
namespace filter { |
||||
class MedianBlurFilter : public Filter { |
||||
public: |
||||
MedianBlurFilter(int kernel_size = 11); |
||||
~MedianBlurFilter(); |
||||
cv::Mat apply(cv::Mat const& img) override; |
||||
|
||||
private: |
||||
int m_kernel_size; |
||||
}; |
||||
} |
@ -1,13 +0,0 @@ |
||||
#include "opencv2/core.hpp" |
||||
#include "opencv2/core/base.hpp" |
||||
#include <filter/normalise.hpp> |
||||
|
||||
namespace filter { |
||||
NormaliseFilter::~NormaliseFilter() {} |
||||
|
||||
cv::Mat NormaliseFilter::apply(const cv::Mat& img) { |
||||
cv::Mat normalised; |
||||
cv::normalize(img, normalised, 255, 0, cv::NORM_MINMAX); |
||||
return normalised; |
||||
} |
||||
} |
@ -1,11 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include <filter/filter.hpp> |
||||
|
||||
namespace filter { |
||||
class NormaliseFilter : public Filter { |
||||
public: |
||||
~NormaliseFilter(); |
||||
cv::Mat apply(cv::Mat const& img) override; |
||||
}; |
||||
} |
@ -1,11 +0,0 @@ |
||||
#include <filter/threshold.hpp> |
||||
|
||||
namespace filter { |
||||
ThresholdFilter::~ThresholdFilter() {} |
||||
|
||||
cv::Mat ThresholdFilter::apply(const cv::Mat &img) { |
||||
cv::Mat threshold_img; |
||||
cv::threshold(img, threshold_img, 60, 255, cv::THRESH_BINARY); |
||||
return threshold_img; |
||||
} |
||||
} |
@ -1,11 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include <filter/filter.hpp> |
||||
|
||||
namespace filter { |
||||
class ThresholdFilter : public Filter { |
||||
public: |
||||
~ThresholdFilter(); |
||||
cv::Mat apply(cv::Mat const& img) override; |
||||
}; |
||||
} |
@ -1,16 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include <functional> |
||||
|
||||
#include <opencv2/imgproc.hpp> |
||||
|
||||
#include <util/box.hpp> |
||||
#include <util/box.hpp> |
||||
|
||||
namespace ft { |
||||
using FitnessMetric = std::function<double(const cv::Mat&, const util::Box&)>; |
||||
|
||||
FitnessMetric aspect_ratio(double aspect); |
||||
FitnessMetric distance_to(util::Point<double> target); |
||||
FitnessMetric relative_area(double ideal_area); |
||||
} |
@ -1,59 +0,0 @@ |
||||
#include <iostream> |
||||
#include <filesystem> |
||||
#include <imageexporterpool.hpp> |
||||
#include <imageexporter.hpp> |
||||
|
||||
namespace fs { using path = std::filesystem::path; } |
||||
|
||||
namespace worker { |
||||
ImageExporter::ImageExporter(std::shared_ptr<InputQueue> input_queue, |
||||
std::shared_ptr<OutputQueue> output_queue) { |
||||
set_input_queue(input_queue); |
||||
set_output_queue(output_queue); |
||||
} |
||||
|
||||
void ImageExporter::run(IWorkerPool* wp) { |
||||
auto work_fn = [=] { |
||||
// TODO: ImageExporterPool
|
||||
auto worker_pool = static_cast<ImageExporterPool*>(wp); |
||||
std::shared_ptr<std::pair<std::shared_ptr<img::ImageData>, ExportParameters>> image = nullptr; |
||||
|
||||
while ((image = m_input_queue->pop()) != nullptr) { |
||||
auto image_data = image->first; |
||||
auto params = image->second; |
||||
util::Box crop = image_data->candidate().second; |
||||
util::Box bounds; |
||||
|
||||
image_data->load(image_data->filename()); |
||||
bounds.top_left() = { 0, 0 }; |
||||
bounds.bottom_right() = { image_data->pixbuf()->get_width(), image_data->pixbuf()->get_height() }; |
||||
|
||||
crop.expand(params.margin, bounds); |
||||
|
||||
cv::Mat output_image; |
||||
if (params.do_crop && crop.area() > 0) { |
||||
try { |
||||
output_image = image_data->mat()(crop); |
||||
} catch (cv::Exception& e) { |
||||
std::cout << crop.top_left().x << " " << crop.top_left().y << " " |
||||
<< crop.bottom_right().x << " " << crop.bottom_right().y << std::endl; |
||||
std::cout << image_data->mat().size().width << " " << image_data->mat().size().height << std::endl; |
||||
} |
||||
} else { |
||||
output_image = image_data->mat(); |
||||
} |
||||
|
||||
fs::path output_path = fs::path(params.export_directory) / fs::path(params.output_file); |
||||
cv::cvtColor(output_image, output_image, cv::COLOR_RGB2BGR); |
||||
cv::imwrite(output_path.string(), output_image); |
||||
image_data->unload(); |
||||
|
||||
m_output_queue->push(nullptr); |
||||
} |
||||
|
||||
worker_pool->signal_done(); |
||||
}; |
||||
|
||||
m_thread = std::thread(work_fn); |
||||
} |
||||
} |
@ -1,21 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include <imagedata.hpp> |
||||
#include <worker.hpp> |
||||
|
||||
namespace worker { |
||||
struct ExportParameters { |
||||
std::string export_directory; |
||||
size_t margin; |
||||
std::string output_file; |
||||
bool do_crop; |
||||
}; |
||||
|
||||
class ImageExporter : public Worker<std::pair<std::shared_ptr<img::ImageData>, ExportParameters>, void*> { |
||||
public: |
||||
ImageExporter(std::shared_ptr<InputQueue> input_queue, |
||||
std::shared_ptr<OutputQueue> output_queue); |
||||
|
||||
void run(IWorkerPool* wp) override; |
||||
}; |
||||
} |
@ -1,68 +0,0 @@ |
||||
#include <imageexporterpool.hpp> |
||||
|
||||
namespace worker { |
||||
ImageExporterPool::ImageExporterPool(size_t n_workers) { |
||||
m_active_workers = n_workers; |
||||
m_stopped = false; |
||||
m_input_queue = std::make_shared<InputQueue>(); |
||||
m_output_queue = std::make_shared<OutputQueue>(); |
||||
|
||||
for (size_t i = 0; i < n_workers; i++) { |
||||
m_workers.push_back(std::make_unique<ImageExporter>(m_input_queue, m_output_queue)); |
||||
} |
||||
} |
||||
|
||||
ImageExporterPool::~ImageExporterPool() { |
||||
join_all(); |
||||
} |
||||
|
||||
std::shared_ptr<ImageExporterPool::InputQueue> ImageExporterPool::input() { |
||||
return m_input_queue; |
||||
} |
||||
|
||||
std::shared_ptr<ImageExporterPool::OutputQueue> ImageExporterPool::output() { |
||||
return m_output_queue; |
||||
} |
||||
|
||||
void ImageExporterPool::set_input(std::shared_ptr<InputQueue> in) { |
||||
m_input_queue = in; |
||||
} |
||||
|
||||
void ImageExporterPool::set_output(std::shared_ptr<OutputQueue> out) { |
||||
m_output_queue = out; |
||||
} |
||||
|
||||
void ImageExporterPool::run_workers() { |
||||
for (auto& worker : m_workers) { |
||||
worker->run(this); |
||||
} |
||||
} |
||||
|
||||
void ImageExporterPool::join_all() { |
||||
for (auto& worker : m_workers) { |
||||
worker->join(); |
||||
} |
||||
} |
||||
|
||||
void ImageExporterPool::signal_done() { |
||||
std::lock_guard lock(m_mutex); |
||||
m_active_workers--; |
||||
|
||||
if (m_active_workers == 0) { |
||||
m_output_queue->finish(); |
||||
} |
||||
} |
||||
|
||||
void ImageExporterPool::stop() { |
||||
m_input_queue->finish(); |
||||
m_input_queue->clear(); |
||||
m_output_queue->finish(); |
||||
m_output_queue->clear(); |
||||
|
||||
m_stopped = true; |
||||
} |
||||
|
||||
bool ImageExporterPool::stopped() { |
||||
return m_stopped; |
||||
} |
||||
} |
@ -1,34 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include <imageexporter.hpp> |
||||
#include <workerpool.hpp> |
||||
|
||||
namespace worker { |
||||
class ImageExporterPool : public WorkerPool<ImageExporter> { |
||||
public: |
||||
ImageExporterPool() { }; |
||||
|
||||
ImageExporterPool(size_t n_workers); |
||||
|
||||
~ImageExporterPool(); |
||||
|
||||
std::shared_ptr<InputQueue> input() override; |
||||
std::shared_ptr<OutputQueue> output() override; |
||||
void set_input(std::shared_ptr<InputQueue> in) override; |
||||
void set_output(std::shared_ptr<OutputQueue> out) override; |
||||
|
||||
void run_workers() override; |
||||
void join_all() override; |
||||
void signal_done() override; |
||||
void stop() override; |
||||
bool stopped() override; |
||||
|
||||
private: |
||||
std::shared_ptr<InputQueue> m_input_queue; |
||||
std::shared_ptr<OutputQueue> m_output_queue; |
||||
mutable std::mutex m_mutex; |
||||
size_t m_active_workers; |
||||
std::vector<std::unique_ptr<ImageExporter>> m_workers; |
||||
bool m_stopped; |
||||
}; |
||||
} |
@ -1,27 +0,0 @@ |
||||
#include <imageloaderpool.hpp> |
||||
#include <imageloader.hpp> |
||||
|
||||
namespace worker { |
||||
ImageLoader::ImageLoader(std::shared_ptr<InputQueue> input_queue, |
||||
std::shared_ptr<OutputQueue> output_queue) { |
||||
set_input_queue(input_queue); |
||||
set_output_queue(output_queue); |
||||
} |
||||
|
||||
void ImageLoader::run(IWorkerPool* wp) { |
||||
auto work_fn = [=] { |
||||
ImageLoaderPool* worker_pool = static_cast<ImageLoaderPool*>(wp); |
||||
|
||||
std::shared_ptr<std::string> filename = nullptr; |
||||
while ((filename = m_input_queue->pop()) != nullptr) { |
||||
std::shared_ptr<img::ImageData> image = std::make_shared<img::ImageData>(*filename); |
||||
m_output_queue->push(std::move(image)); |
||||
} |
||||
|
||||
// This worker is finished
|
||||
worker_pool->signal_done(); |
||||
}; |
||||
|
||||
m_thread = std::thread(work_fn); |
||||
} |
||||
} |
@ -1,14 +0,0 @@ |
||||
#pragma once |
||||
|
||||
#include <imagedata.hpp> |
||||
#include <worker.hpp> |
||||
|
||||
namespace worker { |
||||
class ImageLoader : public Worker<std::string, img::ImageData> { |
||||
public: |
||||
ImageLoader(std::shared_ptr<InputQueue> input_queue, |
||||
std::shared_ptr<OutputQueue> output_queue); |
||||
|
||||
void run(IWorkerPool* wp) override; |
||||
}; |
||||
} |
@ -1,71 +0,0 @@ |
||||
#include <imageloaderpool.hpp> |
||||
|
||||
namespace worker { |
||||
ImageLoaderPool::ImageLoaderPool(size_t n_workers) { |
||||
m_active_workers = n_workers; |
||||
m_stopped = false; |
||||
m_input_queue = std::make_shared<InputQueue>(); |
||||
m_output_queue = std::make_shared<OutputQueue>(); |
||||
|
||||
// Create the workers
|
||||
for (size_t i = 0; i < n_workers; i++) { |
||||
m_workers.push_back(std::make_unique<ImageLoader>(m_input_queue, m_output_queue)); |
||||
} |
||||
} |
||||
|
||||
ImageLoaderPool::~ImageLoaderPool() { |
||||
join_all(); |
||||
} |
||||
|
||||
std::shared_ptr<ImageLoaderPool::InputQueue> ImageLoaderPool::input() { |
||||
return m_input_queue; |
||||
} |
||||
|
||||
std::shared_ptr<ImageLoaderPool::OutputQueue> ImageLoaderPool::output() { |
||||
return m_output_queue; |
||||
} |
||||
|
||||
void ImageLoaderPool::set_input(std::shared_ptr<InputQueue> in) { |
||||
m_input_queue = in; |
||||
} |
||||
|
||||
void ImageLoaderPool::set_output(std::shared_ptr<OutputQueue> out) { |
||||
m_output_queue = out; |
||||
} |
||||
|
||||
void ImageLoaderPool::run_workers() { |
||||
for (auto& worker : m_workers) { |
||||
worker->run(this); |
||||
} |
||||
} |
||||
|
||||
void ImageLoaderPool::join_all() { |
||||
for (auto& worker : m_workers) { |
||||
worker->join(); |
||||
} |
||||
} |
||||
|
||||
void ImageLoaderPool::signal_done() { |
||||
std::lock_guard lock(m_mutex); |
||||
m_active_workers--; |
||||
|
||||
// We're done producing, so signal the consumers to stop consuming once
|
||||
// the output queue runs out
|
||||
if (m_active_workers == 0) { |
||||
m_output_queue->finish(); |
||||
} |
||||
} |
||||
|
||||
void ImageLoaderPool::stop() { |
||||
m_input_queue->finish(); |
||||
m_input_queue->clear(); |
||||
m_output_queue->finish(); |
||||
m_output_queue->clear(); |
||||
|
||||
m_stopped = true; |
||||
} |
||||
|
||||
bool ImageLoaderPool::stopped() { |
||||
return m_stopped; |
||||