summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--plugins/dexela/CMakeLists.txt4
-rw-r--r--plugins/dexela/changelog.txt6
-rw-r--r--plugins/dexela/software-roi.c12
-rw-r--r--plugins/dexela/software-roi.h18
-rw-r--r--plugins/dexela/uca-dexela-camera.c99
-rw-r--r--test/CMakeLists.txt4
-rw-r--r--test/test-software-roi.c85
8 files changed, 205 insertions, 24 deletions
diff --git a/.gitignore b/.gitignore
index 59f657e..33c959e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,7 +11,6 @@ Makefile
src/config.h
src/libuca.so*
tags
-test/
tools/benchmark
tools/gen-doc
tools/grab
diff --git a/plugins/dexela/CMakeLists.txt b/plugins/dexela/CMakeLists.txt
index a93ddc6..c9edd54 100644
--- a/plugins/dexela/CMakeLists.txt
+++ b/plugins/dexela/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 2.6)
project(ucadexela C)
-set(VERSION "1.2.0")
+set(VERSION "1.3.2")
find_package(DEXELA)
@@ -20,7 +20,7 @@ if (DEXELA_FOUND)
include_directories(${DEXELA_INCLUDE_DIRS}
${UCA_CONFIGDIR})
- add_library(ucadexela SHARED uca-dexela-camera.c)
+ add_library(ucadexela SHARED uca-dexela-camera.c software-roi.c)
target_link_libraries(ucadexela ${UCA_DEPS} ${DEXELA_LIBRARIES})
diff --git a/plugins/dexela/changelog.txt b/plugins/dexela/changelog.txt
index 4bcd2d6..5b44262 100644
--- a/plugins/dexela/changelog.txt
+++ b/plugins/dexela/changelog.txt
@@ -1,3 +1,9 @@
+* Tue Sep 16 2014 Mihael Koep <mihael.koep@softwareschneiderei.de> 1.3.2-1
+- implement sensor pixel width and height properties
+* Tue Sep 16 2014 Mihael Koep <mihael.koep@softwareschneiderei.de> 1.3.1-1
+- fix software roi for multi-byte images
+* Tue Sep 9 2014 Mihael Koep <mihael.koep@softwareschneiderei.de> 1.3.0-1
+- add software roi feature
* Tue Jul 29 2014 Mihael Koep <mihael.koep@softwareschneiderei.de> 1.2.0-1
- bump plugin version for package management systems
* Wed Mar 19 2014 Mihael Koep <mihael.koep@softwareschneiderei.de> 1.0.3-1
diff --git a/plugins/dexela/software-roi.c b/plugins/dexela/software-roi.c
new file mode 100644
index 0000000..6056dec
--- /dev/null
+++ b/plugins/dexela/software-roi.c
@@ -0,0 +1,12 @@
+#include "software-roi.h"
+#include <string.h>
+
+void apply_software_roi(const guchar* src, guint srcWidth, guint bytesPerPixel, guchar* dest, guint x, guint y, guint roiWidth, guint roiHeight)
+{
+ for (guint row = 0; row < roiHeight; row++) {
+ guint roiWidthInBytes = roiWidth * bytesPerPixel;
+ guint rowOffset = srcWidth * bytesPerPixel * (y + row);
+ guint offset = rowOffset + x * bytesPerPixel;
+ memcpy(dest + row * roiWidthInBytes, src + offset, roiWidthInBytes);
+ }
+}
diff --git a/plugins/dexela/software-roi.h b/plugins/dexela/software-roi.h
new file mode 100644
index 0000000..3fb3b69
--- /dev/null
+++ b/plugins/dexela/software-roi.h
@@ -0,0 +1,18 @@
+#ifndef SOFTWAREROI_H
+#define SOFTWAREROI_H
+#include <glib.h>
+
+/**
+ * @brief apply_software_roi Extracts the pixels defined by x, y, roiWidth, roiHeight from
+ * the src array and writes them into the dest buffer
+ * @param src
+ * @param srcWidth
+ * @param dest
+ * @param x
+ * @param y
+ * @param roiWidth
+ * @param roiHeight
+ */
+void apply_software_roi(const guchar* src, guint srcWidth, guint bytesPerPixel, guchar* dest, guint x, guint y, guint roiWidth, guint roiHeight);
+
+#endif // SOFTWAREROI_H
diff --git a/plugins/dexela/uca-dexela-camera.c b/plugins/dexela/uca-dexela-camera.c
index 4c30ad7..49f4635 100644
--- a/plugins/dexela/uca-dexela-camera.c
+++ b/plugins/dexela/uca-dexela-camera.c
@@ -18,8 +18,10 @@
#include <string.h>
#include <gio/gio.h>
#include <gmodule.h>
+#include <math.h>
#include "uca-dexela-camera.h"
#include "dexela/dexela_api.h"
+#include "software-roi.h"
#define UCA_DEXELA_CAMERA_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UCA_TYPE_DEXELA_CAMERA, UcaDexelaCameraPrivate))
@@ -47,6 +49,8 @@ static gint base_overrideables[] = {
PROP_NAME,
PROP_SENSOR_WIDTH,
PROP_SENSOR_HEIGHT,
+ PROP_SENSOR_PIXEL_WIDTH,
+ PROP_SENSOR_PIXEL_HEIGHT,
PROP_SENSOR_BITDEPTH,
PROP_SENSOR_HORIZONTAL_BINNING,
PROP_SENSOR_HORIZONTAL_BINNINGS,
@@ -68,13 +72,20 @@ static gint base_overrideables[] = {
static GParamSpec *dexela_properties[N_PROPERTIES] = { NULL, };
static const gdouble MICROS_TO_SECONDS_FACTOR = 1e6d;
+static const gdouble MINIMUM_EXPOSURE_TIME_IN_SECONDS = 0.017d; // 17ms as per documentation
+static const gdouble PIXEL_SIZE = 74.8e-6; // 74.8µm as per data sheet
struct _UcaDexelaCameraPrivate {
GValueArray *binnings;
guint width;
guint height;
+ guint roi_x;
+ guint roi_y;
+ guint roi_width;
+ guint roi_height;
guint bits;
gsize num_bytes;
+ UcaCameraTrigger uca_trigger_mode;
};
/**
@@ -94,26 +105,26 @@ static void fill_binnings(UcaDexelaCameraPrivate *priv)
g_value_array_append(priv->binnings, &val);
}
-static void map_dexela_trigger_mode_to_uca(GValue* value, TriggerMode mode)
+static void map_dexela_trigger_mode_to_uca(UcaDexelaCameraPrivate *priv, GValue* value, TriggerMode mode)
{
if (mode == SOFTWARE) {
- g_value_set_enum(value, UCA_CAMERA_TRIGGER_SOFTWARE);
+ g_value_set_enum(value, priv->uca_trigger_mode);
return;
}
if (mode == EDGE) {
g_value_set_enum(value, UCA_CAMERA_TRIGGER_EXTERNAL);
return;
}
- // XXX: this mapping is only a hack/guess
- if (mode == DURATION) {
- g_value_set_enum(value, UCA_CAMERA_TRIGGER_AUTO);
- return;
- }
g_warning("Unsupported dexela trigger mode: %d", mode);
}
-static void set_trigger_mode(UcaCameraTrigger mode)
+static void set_trigger_mode(UcaDexelaCameraPrivate *priv, UcaCameraTrigger mode)
{
+ priv->uca_trigger_mode = mode;
+ if (mode == UCA_CAMERA_TRIGGER_AUTO) {
+ dexela_set_trigger_mode(SOFTWARE);
+ return;
+ }
if (mode == UCA_CAMERA_TRIGGER_SOFTWARE) {
dexela_set_trigger_mode(SOFTWARE);
return;
@@ -122,10 +133,6 @@ static void set_trigger_mode(UcaCameraTrigger mode)
dexela_set_trigger_mode(EDGE);
return;
}
- if (mode == UCA_CAMERA_TRIGGER_AUTO) {
- dexela_set_trigger_mode(DURATION);
- return;
- }
g_warning("Unsupported uca trigger mode: %d", mode);
}
@@ -182,14 +189,34 @@ static void uca_dexela_camera_get_property(GObject *object, guint property_id, G
g_value_set_uint(value, priv->height);
break;
}
+ case PROP_SENSOR_PIXEL_WIDTH:
+ {
+ g_value_set_double(value, PIXEL_SIZE);
+ break;
+ }
+ case PROP_SENSOR_PIXEL_HEIGHT:
+ {
+ g_value_set_double(value, PIXEL_SIZE);
+ break;
+ }
+ case PROP_ROI_X:
+ {
+ g_value_set_uint(value, priv->roi_x);
+ break;
+ }
+ case PROP_ROI_Y:
+ {
+ g_value_set_uint(value, priv->roi_y);
+ break;
+ }
case PROP_ROI_WIDTH:
{
- g_value_set_uint(value, dexela_get_width());
+ g_value_set_uint(value, priv->roi_width);
break;
}
case PROP_ROI_HEIGHT:
{
- g_value_set_uint(value, dexela_get_height());
+ g_value_set_uint(value, priv->roi_height);
break;
}
case PROP_SENSOR_HORIZONTAL_BINNING:
@@ -224,7 +251,7 @@ static void uca_dexela_camera_get_property(GObject *object, guint property_id, G
}
case PROP_TRIGGER_MODE:
{
- map_dexela_trigger_mode_to_uca(value, dexela_get_trigger_mode());
+ map_dexela_trigger_mode_to_uca(priv, value, dexela_get_trigger_mode());
break;
}
default:
@@ -242,10 +269,30 @@ static void uca_dexela_camera_set_property(GObject *object, guint property_id, c
switch (property_id) {
case PROP_EXPOSURE_TIME:
{
- const gdouble exposureTimeInSeconds = g_value_get_double(value);
+ const gdouble exposureTimeInSeconds = fmax(MINIMUM_EXPOSURE_TIME_IN_SECONDS, g_value_get_double(value));
dexela_set_exposure_time_micros((gint) (exposureTimeInSeconds * MICROS_TO_SECONDS_FACTOR));
break;
}
+ case PROP_ROI_X:
+ {
+ priv->roi_x = g_value_get_uint(value);
+ break;
+ }
+ case PROP_ROI_Y:
+ {
+ priv->roi_y = g_value_get_uint(value);
+ break;
+ }
+ case PROP_ROI_WIDTH:
+ {
+ priv->roi_width = g_value_get_uint(value);
+ break;
+ }
+ case PROP_ROI_HEIGHT:
+ {
+ priv->roi_height = g_value_get_uint(value);
+ break;
+ }
case PROP_SENSOR_HORIZONTAL_BINNING:
{
const guint horizontalBinning = g_value_get_uint(value);
@@ -291,7 +338,7 @@ static void uca_dexela_camera_set_property(GObject *object, guint property_id, c
}
case PROP_TRIGGER_MODE:
{
- set_trigger_mode(g_value_get_enum(value));
+ set_trigger_mode(priv, g_value_get_enum(value));
break;
}
default:
@@ -315,9 +362,14 @@ static void uca_dexela_camera_stop_recording(UcaCamera *camera, GError **error)
static gboolean uca_dexela_camera_grab(UcaCamera *camera, gpointer data, GError **error)
{
g_debug("grab called");
- g_return_if_fail(UCA_IS_DEXELA_CAMERA(camera));
+ g_return_val_if_fail(UCA_IS_DEXELA_CAMERA(camera), FALSE);
UcaDexelaCameraPrivate *priv = UCA_DEXELA_CAMERA_GET_PRIVATE(camera);
- memcpy((gchar *) data, dexela_grab(), priv->width * priv->height * priv->num_bytes);
+
+ if (priv->uca_trigger_mode == UCA_CAMERA_TRIGGER_SOFTWARE) {
+ // TODO: wait for a signal from uca_camera_trigger()
+ }
+ guchar* fullFrame = dexela_grab();
+ apply_software_roi(fullFrame, priv->width, priv->num_bytes, data, priv->roi_x, priv->roi_y, priv->roi_width, priv->roi_height);
return TRUE;
}
@@ -361,12 +413,12 @@ static void uca_dexela_camera_class_init(UcaDexelaCameraClass *klass)
for (guint i = 0; base_overrideables[i] != 0; i++) {
g_object_class_override_property(gobject_class, base_overrideables[i], uca_camera_props[base_overrideables[i]]);
}
- dexela_properties[PROP_GAIN_MODE] =
+ dexela_properties[PROP_GAIN_MODE] =
g_param_spec_uint("gain-mode",
"High or Low Full Well",
"High (1) or Low (0) Full Well",
0, 1, 0, G_PARAM_READWRITE);
- dexela_properties[PROP_TEST_MODE] =
+ dexela_properties[PROP_TEST_MODE] =
g_param_spec_boolean("test-mode",
"Enable or disable test mode",
"Enable (true) or disable (false) test mode",
@@ -388,7 +440,12 @@ static void uca_dexela_camera_init(UcaDexelaCamera *self)
priv->bits = dexela_get_bit_depth();
priv->width = dexela_get_width();
priv->height = dexela_get_height();
+ priv->roi_x = 0;
+ priv->roi_y = 0;
+ priv->roi_width = priv->width;
+ priv->roi_height = priv->height;
priv->num_bytes = 2;
+ priv->uca_trigger_mode = UCA_CAMERA_TRIGGER_AUTO;
}
G_MODULE_EXPORT GType
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 0e8cfad..afe79ec 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -1,10 +1,14 @@
cmake_minimum_required(VERSION 2.6)
+include_directories(${ucadexela_SOURCE_DIR})
+
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/gtester.xsl
${CMAKE_CURRENT_BINARY_DIR}/gtester.xsl)
add_executable(test-mock test-mock.c)
add_executable(test-ring-buffer test-ring-buffer.c)
+add_executable(test-software-roi test-software-roi.c ${ucadexela_SOURCE_DIR}/software-roi.c)
target_link_libraries(test-mock uca ${UCA_DEPS})
target_link_libraries(test-ring-buffer uca ${UCA_DEPS})
+target_link_libraries(test-software-roi ${UCA_DEPS})
diff --git a/test/test-software-roi.c b/test/test-software-roi.c
new file mode 100644
index 0000000..08ab742
--- /dev/null
+++ b/test/test-software-roi.c
@@ -0,0 +1,85 @@
+#include <glib.h>
+#include "software-roi.h"
+
+static const guchar test_frame[] = {
+ 0, 10, 20, 30, 40, 50, 60, 70, 80,
+ 0, 11, 21, 31, 41, 51, 61, 71, 81,
+ 0, 12, 22, 32, 42, 52, 62, 72, 82,
+ 0, 13, 23, 33, 43, 53, 63, 73, 83,
+ 0, 14, 24, 34, 44, 54, 64, 74, 84,
+};
+static const guint test_frame_width = 9;
+static guchar test_roi_2x1_5x3[] = {
+ 21, 31, 41, 51, 61,
+ 22, 32, 42, 52, 62,
+ 23, 33, 43, 53, 63,
+};
+
+static const guchar test_frame16bit[] = {
+ 0, 0, 10, 10, 20, 20, 30, 30, 40, 40, 50, 50, 60, 60, 70, 70,
+ 1, 1, 11, 11, 21, 21, 31, 31, 41, 41, 51, 51, 61, 61, 71, 71,
+ 2, 2, 12, 12, 22, 22, 32, 32, 42, 42, 52, 52, 62, 62, 72, 72,
+ 3, 3, 13, 13, 23, 23, 33, 33, 43, 43, 53, 53, 63, 63, 73, 73,
+ 4, 4, 14, 14, 24, 24, 34, 34, 44, 44, 54, 54, 64, 64, 74, 74,
+ 5, 5, 15, 15, 25, 25, 35, 35, 45, 45, 55, 55, 65, 65, 75, 75,
+ 6, 6, 16, 16, 26, 26, 36, 36, 46, 46, 56, 56, 66, 66, 76, 76,
+};
+static const guint test_frame16bit_width = 8;
+static guchar test_roi16bit_3x3_5x3[] = {
+ 33, 33, 43, 43, 53, 53, 63, 63, 73, 73,
+ 34, 34, 44, 44, 54, 54, 64, 64, 74, 74,
+ 35, 35, 45, 45, 55, 55, 65, 65, 75, 75,
+ 36, 36, 46, 46, 56, 56, 66, 66, 76, 76,
+};
+
+void typical_roi_test(void)
+{
+ guint roiX = 2;
+ guint roiY = 1;
+ guint roiWidth = 5;
+ guint roiHeight = 3;
+ guint roiSize = roiWidth * roiHeight;
+ guchar roiFrame[roiSize];
+ apply_software_roi(test_frame, test_frame_width, 1, roiFrame, roiX, roiY, roiWidth, roiHeight);
+ for (guint i = 0; i < roiSize; i++) {
+ g_assert_cmpint(test_roi_2x1_5x3[i], ==, roiFrame[i]);
+ }
+}
+
+void nrows_only_roi_test(void)
+{
+ guint roiX = 0;
+ guint roiY = 0;
+ guint roiWidth = test_frame_width;
+ guint roiHeight = 3;
+ guint roiSize = roiWidth * roiHeight;
+ guchar roiFrame[roiSize];
+ apply_software_roi(test_frame, test_frame_width, 1, roiFrame, roiX, roiY, roiWidth, roiHeight);
+ for (guint i = 0; i < roiSize; i++) {
+ g_assert_cmpint(test_frame[i], ==, roiFrame[i]);
+ }
+}
+
+void multibyte_image_test(void)
+{
+ guint roiX = 3;
+ guint roiY = 3;
+ guint roiWidth = 5;
+ guint roiHeight = 3;
+ guint bytesPerPixel = 2;
+ guint roiSize = roiWidth * bytesPerPixel * roiHeight;
+ guchar roiFrame[roiSize];
+ apply_software_roi(test_frame16bit, test_frame16bit_width, bytesPerPixel, roiFrame, roiX, roiY, roiWidth, roiHeight);
+ for (guint i = 0; i < roiSize; i++) {
+ g_assert_cmpint(test_roi16bit_3x3_5x3[i], ==, roiFrame[i]);
+ }
+}
+
+int main(int argc, char** argv)
+{
+ g_test_init(&argc, &argv, NULL);
+ g_test_add_func("/software-roi/apply-typical-roi", typical_roi_test);
+ g_test_add_func("/software-roi/apply-roi-nrows-only", nrows_only_roi_test);
+ g_test_add_func("/software-roi/apply-roi-multibyte-image", multibyte_image_test);
+ return g_test_run();
+}