summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNikita Kostovsky <nikita@kostovsky.me>2025-11-30 01:19:33 +0100
committerNikita Kostovsky <nikita@kostovsky.me>2025-11-30 01:19:33 +0100
commitcf87257fc3b7132eccf305f3eca9ee56c151d913 (patch)
tree29ed0aed55050b27a2e589322a488ea29041ba30 /src
parent81fd05d07b51e9cbb25de2d8bdbd4a51ead36994 (diff)
don't waste memory
Diffstat (limited to 'src')
-rw-r--r--src/camera/icamera.h6
-rw-r--r--src/camera/veyeimx287m.cpp163
-rw-r--r--src/camera/veyeimx287m.h20
-rw-r--r--src/image.cpp33
-rw-r--r--src/image.h10
-rw-r--r--src/pixels.h2
-rw-r--r--src/protocols/httpserver.cpp14
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};