diff options
| author | Nikita Kostovsky <nikita@kostovsky.me> | 2025-11-30 01:19:33 +0100 |
|---|---|---|
| committer | Nikita Kostovsky <nikita@kostovsky.me> | 2025-11-30 01:19:33 +0100 |
| commit | cf87257fc3b7132eccf305f3eca9ee56c151d913 (patch) | |
| tree | 29ed0aed55050b27a2e589322a488ea29041ba30 /src | |
| parent | 81fd05d07b51e9cbb25de2d8bdbd4a51ead36994 (diff) | |
don't waste memory
Diffstat (limited to 'src')
| -rw-r--r-- | src/camera/icamera.h | 6 | ||||
| -rw-r--r-- | src/camera/veyeimx287m.cpp | 163 | ||||
| -rw-r--r-- | src/camera/veyeimx287m.h | 20 | ||||
| -rw-r--r-- | src/image.cpp | 33 | ||||
| -rw-r--r-- | src/image.h | 10 | ||||
| -rw-r--r-- | src/pixels.h | 2 | ||||
| -rw-r--r-- | src/protocols/httpserver.cpp | 14 |
7 files changed, 145 insertions, 103 deletions
diff --git a/src/camera/icamera.h b/src/camera/icamera.h index 545daf9..310e709 100644 --- a/src/camera/icamera.h +++ b/src/camera/icamera.h @@ -49,8 +49,10 @@ public: [[nodiscard]] virtual bool set_gain(const float value) = 0; [[nodiscard]] virtual std::optional<float> get_gain() = 0; - [[nodiscard]] virtual bool getImage(Image *image) = 0; - [[nodiscard]] virtual std::shared_ptr<Image> getImage() = 0; + // [[nodiscard]] virtual bool getImage(Image *image) = 0; + // [[nodiscard]] virtual std::shared_ptr<Image> getImage() = 0; + // [[nodiscard]] virtual std::optional<Image &> getImage() = 0; + [[nodiscard]] virtual Image *getImage() = 0; public: [[nodiscard]] virtual bool startStream() = 0; diff --git a/src/camera/veyeimx287m.cpp b/src/camera/veyeimx287m.cpp index 54bb47e..c36caaa 100644 --- a/src/camera/veyeimx287m.cpp +++ b/src/camera/veyeimx287m.cpp @@ -572,30 +572,26 @@ void VeyeIMX287m::getFramesLoop(std::stop_token stopToken) const uint8_t i = threadIdx % futures.size(); futures[i].waitForFinished(); + m_images[i].reset(); { t.start(); const auto &src = *(Image::radxa_data_t *) m_rawBuffers[bufferIdx].mem; - // const auto image = std::make_shared<Image>(); - // const auto &image = m_rawBuffers[i].image; - auto &dst = m_rawBuffers[i].image->data; + auto &dst = m_images[i].data; Image::copy(dst, src); - // image->rotate(); - // const auto pixels = image->sharedPixels(); - get_elapsed_ns += t.nsecsElapsed(); - // m_sync.rawSemQueue.enqueue(image); } - futures[i] = QtConcurrent::run(&threadPool, - [this, i]() { - const auto image = m_rawBuffers[i].image; - image->rotate(); - const auto pixels = image->sharedPixels(); - return i; - }) /*.then(&threadPool, [this](const uint8_t i) { - const auto image = m_rawBuffers[i].image; - const auto pixels = image->sharedPixels(); + futures[i] = QtConcurrent::run(/*&threadPool, */ [this, i]() { + auto &image = m_images[i]; + image.rotate(); + // const auto pixels = image.sharedPixels(); + const auto &pixels = image.getPixels(); + m_lastImageIdx = i; + return i; + }) /*.then([this](const uint8_t i) { + auto &image = m_images[i]; + const auto pixels = image.sharedPixels(); return i; })*/ ; @@ -712,83 +708,88 @@ bool VeyeIMX287m::dequeueImageBuffer(size_t &imageIndex) return true; } -bool VeyeIMX287m::getImage(Image *image) -{ - return false; - // if (!image) { - // std::cerr << __func__ << ": image is nullptr" << std::endl; +// bool VeyeIMX287m::getImage(Image *image) +// { +// return false; +// if (!image) { +// std::cerr << __func__ << ": image is nullptr" << std::endl; - // return false; - // } +// return false; +// } - // size_t bufferIdx{}; +// size_t bufferIdx{}; - // if (!dequeueImageBuffer(bufferIdx)) { - // return false; - // } +// if (!dequeueImageBuffer(bufferIdx)) { +// return false; +// } - // // TODO: remove this bullshit. return ptr to image or copy image metainfo - // // only, then copy data - // // *image = std::move(m_images[bufferIdx]); - // *image = std::move(*m_rawBuffers[bufferIdx].image); - // { - // QElapsedTimer t; - // t.start(); - // std::lock_guard lock{m_imageMutexes[bufferIdx]}; +// // TODO: remove this bullshit. return ptr to image or copy image metainfo +// // only, then copy data +// // *image = std::move(m_images[bufferIdx]); +// *image = std::move(*m_rawBuffers[bufferIdx].image); +// { +// QElapsedTimer t; +// t.start(); +// std::lock_guard lock{m_imageMutexes[bufferIdx]}; - // auto &src = *(Image::radxa_data_t *) m_rawBuffers[bufferIdx].mem; - // auto &dst = image->data; - // Image::copy(dst, src); - // get_elapsed_ns += t.nsecsElapsed(); - // } +// auto &src = *(Image::radxa_data_t *) m_rawBuffers[bufferIdx].mem; +// auto &dst = image->data; +// Image::copy(dst, src); +// get_elapsed_ns += t.nsecsElapsed(); +// } - // return true; -} +// return true; +// } -std::shared_ptr<Image> VeyeIMX287m::getImage() +Image *VeyeIMX287m::getImage() { - std::shared_ptr<Image> result; - // std::shared_ptr<Image> result = std::make_shared<Image>(); + return m_lastImageIdx.has_value() ? &m_images[*m_lastImageIdx] : nullptr; +} - // if (m_lastProcessedImage != std::numeric_limits<size_t>::max()) { - // if (m_lastProcessedImage) { - // return m_rawBuffers[m_lastProcessedImage].image; - // } +// std::shared_ptr<Image> VeyeIMX287m::getImage() +// { +// std::shared_ptr<Image> result; +// std::shared_ptr<Image> result = std::make_shared<Image>(); - { - std::lock_guard l{m_lastImageMtx}; - // result = m_lastProcessedImage; - // std::swap(result, m_lastProcessedImage); - } - // return {}; - // { - // return m_lastProcessedImage; - // result = m_lastProcessedImage; - // } - return result; +// if (m_lastProcessedImage != std::numeric_limits<size_t>::max()) { +// if (m_lastProcessedImage) { +// return m_rawBuffers[m_lastProcessedImage].image; +// } - // size_t bufferIdx{}; +// { +// std::lock_guard l{m_lastImageMtx}; +// result = m_lastProcessedImage; +// std::swap(result, m_lastProcessedImage); +// } +// return {}; +// { +// return m_lastProcessedImage; +// result = m_lastProcessedImage; +// } +// return result; - // if (!dequeueImageBuffer(bufferIdx)) { - // std::cerr << "cannot dequeue" << std::endl; - // return {}; - // } +// size_t bufferIdx{}; - // // TODO: remove this bullshit. return ptr to image or copy image metainfo - // // only, then copy data - // // *image = std::move(m_images[bufferIdx]); - // // result = m_rawBuffers[bufferIdx].image; - // { - // QElapsedTimer t; - // t.start(); - // std::lock_guard lock{m_imageMutexes[bufferIdx]}; +// if (!dequeueImageBuffer(bufferIdx)) { +// std::cerr << "cannot dequeue" << std::endl; +// return {}; +// } - // auto &src = *(Image::radxa_data_t *) m_rawBuffers[bufferIdx].mem; - // auto &dst = result->data; - // Image::copy(dst, src); - // get_elapsed_ns += t.nsecsElapsed(); - // } - // // std::cerr << "ok" << std::endl; +// // TODO: remove this bullshit. return ptr to image or copy image metainfo +// // only, then copy data +// // *image = std::move(m_images[bufferIdx]); +// // result = m_rawBuffers[bufferIdx].image; +// { +// QElapsedTimer t; +// t.start(); +// std::lock_guard lock{m_imageMutexes[bufferIdx]}; - // return result; -} +// auto &src = *(Image::radxa_data_t *) m_rawBuffers[bufferIdx].mem; +// auto &dst = result->data; +// Image::copy(dst, src); +// get_elapsed_ns += t.nsecsElapsed(); +// } +// // std::cerr << "ok" << std::endl; + +// return result; +// } diff --git a/src/camera/veyeimx287m.h b/src/camera/veyeimx287m.h index d65b00d..3f591f7 100644 --- a/src/camera/veyeimx287m.h +++ b/src/camera/veyeimx287m.h @@ -44,8 +44,9 @@ public: [[nodiscard]] bool dequeueImageBuffer(size_t &image); // bool getImage(Image &image); - [[nodiscard]] bool getImage(Image *image) override; - [[nodiscard]] std::shared_ptr<Image> getImage() override; + // [[nodiscard]] bool getImage(Image *image) override; + [[nodiscard]] Image *getImage() override; + // [[nodiscard]] std::shared_ptr<Image> getImage() override; bool init(); @@ -66,7 +67,7 @@ public: public: /*! * \brief processedCounter - count of images processed in current second. - * Used for performance measurement and bottlenecks analysing + * Used for performance measurement and bottlenecks analysis */ uint32_t processedCounter{0}; @@ -76,6 +77,11 @@ private: [[nodiscard]] bool initI2C(); + /*! + * \brief getFramesLoop - get frames from camera and manage futher processing + * \note to be started in a soparate thread + * \param stopToken - asks to break the loop + */ void getFramesLoop(std::stop_token stopToken); private: @@ -96,21 +102,19 @@ private: */ std::array<std::mutex, BUFFER_COUNT> m_imageMutexes; - // TODO: split this - // there should be no chance of changing image by ioctl during futher processing struct buffer { void *mem{nullptr}; - std::shared_ptr<Image> image{std::make_shared<Image>()}; }; std::vector<buffer> m_rawBuffers; - // std::array<Image, BUFFER_COUNT> m_images; + std::array<Image, BUFFER_COUNT> m_images; + // std::optional<std::remove_const<decltype(BUFFER_COUNT)>> m_lastImageIdx; + std::optional<uint8_t> m_lastImageIdx; std::mutex m_camMtx; std::jthread m_streamThread; std::jthread m_getThreads[1]; - std::mutex m_lastImageMtx; std::shared_ptr<Image> m_lastProcessedImage{}; std::shared_ptr<veye::imx287m::i2c> m_i2c; diff --git a/src/image.cpp b/src/image.cpp index b2cd535..1dffcd9 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -197,17 +197,34 @@ void Image::rotate() rot_elapsed_ns += t.nsecsElapsed(); } -std::shared_ptr<Pixels> Image::sharedPixels() +// std::shared_ptr<Pixels> Image::sharedPixels() +// { +// t.start(); + +// static auto result = std::make_shared<Pixels>(); +// result->counters = counters; + +// std::transform(rotated_cw.cbegin(), rotated_cw.cend(), result->pixels.begin(), process_column); +// pix_elapsed_ns += t.nsecsElapsed(); + +// return result; +// } + +Pixels &Image::getPixels() { + if (pixels) + return *pixels; + t.start(); - static auto result = std::make_shared<Pixels>(); - result->counters = counters; + // overhead of this? + pixels = Pixels{}; + pixels->counters = counters; - std::transform(rotated_cw.cbegin(), rotated_cw.cend(), result->pixels.begin(), process_column); + std::transform(rotated_cw.cbegin(), rotated_cw.cend(), pixels->pixels.begin(), process_column); pix_elapsed_ns += t.nsecsElapsed(); - return result; + return *pixels; } void Image::copyFromData(const void *src, size_t size) @@ -246,6 +263,12 @@ void Image::copyFromData(const void *src, size_t size) } } +void Image::reset() +{ + counters = Counters{}; + pixels = std::nullopt; +} + void Image::copy(data_t &dst, const radxa_data_t &src) { for (size_t i = 0; i < img_height; ++i) { diff --git a/src/image.h b/src/image.h index 33fb4d8..105711b 100644 --- a/src/image.h +++ b/src/image.h @@ -3,6 +3,7 @@ #include <QElapsedTimer> #include "constants.h" +#include "pixels.h" #include "typedefs.h" #define USER_PTR @@ -29,6 +30,7 @@ struct Image alignas(128) data_t data; alignas(128) rotated_data_t rotated_cw; + std::optional<Pixels> pixels{}; uint16_t width{0}; uint16_t height{0}; @@ -40,9 +42,15 @@ struct Image void rotate(); - std::shared_ptr<Pixels> sharedPixels(); + // std::shared_ptr<Pixels> sharedPixels(); + Pixels &getPixels(); void copyFromData(const void* src, size_t size); + /*! + * \brief reset - reset counters and invalidate pixels + */ + void reset(); + static void copy(data_t &dst, const radxa_data_t &src); private: diff --git a/src/pixels.h b/src/pixels.h index 06a8654..3c64b39 100644 --- a/src/pixels.h +++ b/src/pixels.h @@ -12,6 +12,8 @@ struct Pixels { + // TODO: try to avoid setting default values to speedup + // could be even made a ref/ptr to image counters Counters counters{}; std::array<float, img_width> pixels{0.f}; diff --git a/src/protocols/httpserver.cpp b/src/protocols/httpserver.cpp index 3d5a0d5..afc113e 100644 --- a/src/protocols/httpserver.cpp +++ b/src/protocols/httpserver.cpp @@ -94,7 +94,7 @@ QHttpServerResponse HttpServer::GET_image() return QHttpServerResponse::StatusCode::ServiceUnavailable; } - pgm_save(image.get()); + pgm_save(image); std::lock_guard<std::mutex> lg(pgm_image_mtx); return QHttpServerResponse{QByteArray{(const char *) (pgm_image), @@ -115,12 +115,13 @@ QHttpServerResponse HttpServer::GET_pixels() return QHttpServerResponse::StatusCode::ServiceUnavailable; } - std::shared_ptr<Image> image; + // std::shared_ptr<Image> image; { // const elapsed_logger logger{__func__}; - /*const auto */ image = m_camera->getImage(); + // /*const auto */ image = m_camera->getImage(); } + const auto image = m_camera->getImage(); if (!image) { qWarning() << "cannot get image"; return QHttpServerResponse::StatusCode::ServiceUnavailable; @@ -128,9 +129,10 @@ QHttpServerResponse HttpServer::GET_pixels() // FIXME: inc m_camera->processedCounter // FIXME: not thread-safe, don't use this static shared_ptr at all - const auto pixels = image->sharedPixels(); + // const auto pixels = image->sharedPixels(); + const auto &pixels = image->getPixels(); // const auto lines = pixelsToLines(::pixels); - const auto lines = pixelsToLines(*pixels); + const auto lines = pixelsToLines(pixels); // qt json does not allow to limit double precision, so using rapidjson rapidjson::Document jd; @@ -142,7 +144,7 @@ QHttpServerResponse HttpServer::GET_pixels() rapidjson::Value rjPixels{rapidjson::kArrayType}; for (size_t i = 0; i < img_width; ++i) { - rjPixels.PushBack(nan2zero(pixels->pixels[i]), al); + rjPixels.PushBack(nan2zero(pixels.pixels[i]), al); } rapidjson::Value rjLines{rapidjson::kArrayType}; |
