summaryrefslogtreecommitdiffstats
path: root/src/image/iface.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/image/iface.cpp')
-rw-r--r--src/image/iface.cpp1489
1 files changed, 1489 insertions, 0 deletions
diff --git a/src/image/iface.cpp b/src/image/iface.cpp
new file mode 100644
index 0000000..8759bf4
--- /dev/null
+++ b/src/image/iface.cpp
@@ -0,0 +1,1489 @@
+/******************************************************************************
+ * Copyright (C) 2018 Alejandro Colomar Andrés *
+ * SPDX-License-Identifier: GPL-2.0-only *
+ ******************************************************************************/
+
+
+/******************************************************************************
+ ******* headers **************************************************************
+ ******************************************************************************/
+#include "vision-artificial/image/iface.hpp"
+
+#include <cerrno>
+#include <cmath>
+#include <cstddef>
+#include <cstdio>
+
+#include <vector>
+
+#include <opencv2/opencv.hpp>
+
+#include "vision-artificial/image/alx.hpp"
+#include "vision-artificial/image/calib3d.hpp"
+#include "vision-artificial/image/cv.hpp"
+#include "vision-artificial/image/ocr.hpp"
+#include "vision-artificial/image/orb.hpp"
+#include "vision-artificial/image/zbar.hpp"
+#include "vision-artificial/save/save.hpp"
+#include "vision-artificial/user/iface.hpp"
+
+
+/******************************************************************************
+ ******* macros ***************************************************************
+ ******************************************************************************/
+#define IMG_MEM_SIZE (20)
+
+#define WIN_NAME_IMG "Image"
+#define WIN_NAME_HIST "Hist"
+#define WIN_TIMEOUT (500)
+
+
+/******************************************************************************
+ ******* enums ****************************************************************
+ ******************************************************************************/
+
+
+/******************************************************************************
+ ******* structs / unions *****************************************************
+ ******************************************************************************/
+
+
+/******************************************************************************
+ ******* variables ************************************************************
+ ******************************************************************************/
+/* Global --------------------------------------------------------------------*/
+ char img_ocr_text [OCR_TEXT_MAX];
+ struct Img_Iface_ZB_Codes zb_codes;
+/* Static --------------------------------------------------------------------*/
+static class cv::Mat image_copy_old;
+static class cv::Mat image_copy_tmp;
+static class cv::Mat image_mem[IMG_MEM_SIZE];
+static class cv::Mat image_ref;
+static class cv::Mat histogram_c0;
+static class cv::Mat histogram_c1;
+static class cv::Mat histogram_c2;
+static class cv::Mat hist_img_c1;
+static class cv::Mat hist_img_c3;
+static class std::vector <class std::vector <cv::Point_ <int>>> contours;
+static double area[CONTOURS_MAX];
+static double perimeter[CONTOURS_MAX];
+static class cv::Mat hierarchy;
+static class cv::Rect_ <int> rectangle;
+static class cv::RotatedRect rectangle_rot;
+static class std::vector <class cv::Vec <float, 3>> circles;
+static class cv::Mat intrinsic_mat;
+static class cv::Mat dist_coefs;
+static class std::vector <class cv::Mat> rvecs;
+static class std::vector <class cv::Mat> tvecs;
+
+
+/******************************************************************************
+ ******* static functions (prototypes) ****************************************
+ ******************************************************************************/
+ /* alx */
+static void img_iface_local_max (void);
+static void img_iface_skeleton (void);
+static void img_iface_lines_horizontal (void);
+static void img_iface_lines_vertical (void);
+static void img_iface_mean_horizontal (void);
+static void img_iface_mean_vertical (void);
+static void img_iface_median_horizontal (void);
+static void img_iface_median_vertical (void);
+ /* cv */
+ /* Core: The core functionality */
+ /* Pixel */
+static void img_iface_pixel_get (const void *data);
+static void img_iface_pixel_set (const void *data);
+ /* ROI */
+static void img_iface_set_ROI (const void *data);
+static void img_iface_set_ROI_2rect (const void *data);
+ /* Operations on Arrays */
+static void img_iface_and_2ref (void);
+static void img_iface_not (void);
+static void img_iface_or_2ref (void);
+static void img_iface_component (const void *data);
+ /* Imgproc: Image processing */
+ /* Image filtering */
+static void img_iface_dilate (const void *data);
+static void img_iface_erode (const void *data);
+static void img_iface_dilate_erode (const void *data);
+static void img_iface_erode_dilate (const void *data);
+static void img_iface_smooth (const void *data);
+static void img_iface_sobel (const void *data);
+static void img_iface_border (const void *data);
+ /* Geometric image transformations */
+static void img_iface_mirror (const void *data);
+static void img_iface_rotate_orto (const void *data);
+static void img_iface_rotate (const void *data);
+static void img_iface_rotate_2rect (const void *data);
+ /* Miscellaneous image transformations */
+static void img_iface_adaptive_thr (const void *data);
+static void img_iface_cvt_color (const void *data);
+static void img_iface_distance_transform (void);
+static void img_iface_threshold (const void *data);
+ /* Histograms */
+static void img_iface_histogram (const void *data);
+static void img_iface_histogram_c3 (const void *data);
+ /* Structural analysis and shape descriptors */
+static void img_iface_contours (const void *data);
+static void img_iface_contours_size (const void *data);
+static void img_iface_bounding_rect (const void *data);
+static void img_iface_fit_ellipse (const void *data);
+static void img_iface_min_area_rect (const void *data);
+ /* Feature detection */
+static void img_iface_hough_circles (const void *data);
+ /* orb */
+static void img_iface_align (void);
+ /* calib3d */
+static void img_iface_calibrate (const void *data);
+static void img_iface_undistort (const void *data);
+ /* zbar */
+static void img_iface_decode (const void *data);
+ /* ocr */
+static void img_iface_read (const void *data);
+ /* iface */
+static void img_iface_apply (void);
+static void img_iface_discard (void);
+static void img_iface_save_mem (const void *data);
+static void img_iface_load_mem (const void *data);
+static void img_iface_save_ref (void);
+ /* save/save */
+static void img_iface_save_file (void);
+static void img_iface_save_update (void);
+
+
+/******************************************************************************
+ ******* global functions *****************************************************
+ ******************************************************************************/
+void img_iface_init (void)
+{
+
+ cv::namedWindow(WIN_NAME_HIST, cv::WINDOW_NORMAL);
+ cv::namedWindow(WIN_NAME_IMG, cv::WINDOW_NORMAL);
+
+ hist_img_c1.release();
+ hist_img_c1 = cv::Mat::zeros(cv::Size(256, 100), CV_8UC3);
+ hist_img_c3.release();
+ hist_img_c3 = cv::Mat::zeros(cv::Size(256 * 3, 100), CV_8UC3);
+}
+
+void img_iface_deinit (void)
+{
+
+ for (ptrdiff_t i = 0; i < IMG_MEM_SIZE; i++)
+ image_mem[i].release();
+ image_ref.release();
+
+ cv::destroyAllWindows();
+}
+
+void img_iface_load (const char *fpath, const char *fname)
+{
+ const char *path;
+ char file_name[FILENAME_MAX];
+
+ if (!fpath)
+ path = saved_path;
+ else
+ path = fpath;
+
+ if (!fname)
+ user_iface_fname(fpath, file_name);
+ else
+ snprintf(file_name, FILENAME_MAX, "%s", fname);
+
+ errno = 0;
+ load_image_file(path, file_name);
+ if (errno)
+ return;
+
+ image.copyTo(image_copy_old);
+ image.copyTo(image_copy_tmp);
+}
+
+void img_iface_cleanup (void)
+{
+
+ image_copy_old.release();
+ image_copy_tmp.release();
+ histogram_c0.release();
+ histogram_c1.release();
+ histogram_c2.release();
+ hist_img_c1.release();
+ hist_img_c3.release();
+}
+
+void img_iface_act (int action, const void *data)
+{
+
+ switch (action) {
+ /* img_alx */
+ case IMG_IFACE_ACT_LOCAL_MAX:
+ img_iface_local_max();
+ break;
+ case IMG_IFACE_ACT_SKELETON:
+ img_iface_skeleton();
+ break;
+ case IMG_IFACE_ACT_LINES_HORIZONTAL:
+ img_iface_lines_horizontal();
+ break;
+ case IMG_IFACE_ACT_LINES_VERTICAL:
+ img_iface_lines_vertical();
+ break;
+ case IMG_IFACE_ACT_MEAN_HORIZONTAL:
+ img_iface_mean_horizontal();
+ break;
+ case IMG_IFACE_ACT_MEAN_VERTICAL:
+ img_iface_mean_vertical();
+ break;
+ case IMG_IFACE_ACT_MEDIAN_HORIZONTAL:
+ img_iface_median_horizontal();
+ break;
+ case IMG_IFACE_ACT_MEDIAN_VERTICAL:
+ img_iface_median_vertical();
+ break;
+ /* img_cv */
+ /* Core: The core functionality */
+ /* Pixel */
+ case IMG_IFACE_ACT_PIXEL_GET:
+ img_iface_pixel_get(data);
+ break;
+ case IMG_IFACE_ACT_PIXEL_SET:
+ img_iface_pixel_set(data);
+ break;
+ /* ROI */
+ case IMG_IFACE_ACT_SET_ROI:
+ img_iface_set_ROI(data);
+ break;
+ case IMG_IFACE_ACT_SET_ROI_2RECT:
+ img_iface_set_ROI_2rect(data);
+ break;
+ /* Operations on Arrays */
+ case IMG_IFACE_ACT_AND_2REF:
+ img_iface_and_2ref();
+ break;
+ case IMG_IFACE_ACT_NOT:
+ img_iface_not();
+ break;
+ case IMG_IFACE_ACT_OR_2REF:
+ img_iface_or_2ref();
+ break;
+ case IMG_IFACE_ACT_COMPONENT:
+ img_iface_component(data);
+ break;
+ /* Imgproc: Image processing */
+ /* Image filtering */
+ case IMG_IFACE_ACT_DILATE:
+ img_iface_dilate(data);
+ break;
+ case IMG_IFACE_ACT_ERODE:
+ img_iface_erode(data);
+ break;
+ case IMG_IFACE_ACT_DILATE_ERODE:
+ img_iface_dilate_erode(data);
+ break;
+ case IMG_IFACE_ACT_ERODE_DILATE:
+ img_iface_erode_dilate(data);
+ break;
+ case IMG_IFACE_ACT_SMOOTH:
+ img_iface_smooth(data);
+ break;
+ case IMG_IFACE_ACT_SOBEL:
+ img_iface_sobel(data);
+ break;
+ case IMG_IFACE_ACT_BORDER:
+ img_iface_border(data);
+ break;
+ /* Geometric image transformations */
+ case IMG_IFACE_ACT_MIRROR:
+ img_iface_mirror(data);
+ break;
+ case IMG_IFACE_ACT_ROTATE_ORTO:
+ img_iface_rotate_orto(data);
+ break;
+ case IMG_IFACE_ACT_ROTATE:
+ img_iface_rotate(data);
+ break;
+ case IMG_IFACE_ACT_ROTATE_2RECT:
+ img_iface_rotate_2rect(data);
+ break;
+ /* Miscellaneous image transformations */
+ case IMG_IFACE_ACT_ADAPTIVE_THRESHOLD:
+ img_iface_adaptive_thr(data);
+ break;
+ case IMG_IFACE_ACT_CVT_COLOR:
+ img_iface_cvt_color(data);
+ break;
+ case IMG_IFACE_ACT_DISTANCE_TRANSFORM:
+ img_iface_distance_transform();
+ break;
+ case IMG_IFACE_ACT_THRESHOLD:
+ img_iface_threshold(data);
+ break;
+ /* Histograms */
+ case IMG_IFACE_ACT_HISTOGRAM:
+ img_iface_histogram(data);
+ break;
+ case IMG_IFACE_ACT_HISTOGRAM_C3:
+ img_iface_histogram_c3(data);
+ break;
+ /* Structural analysis and shape descriptors */
+ case IMG_IFACE_ACT_CONTOURS:
+ img_iface_contours(data);
+ break;
+ case IMG_IFACE_ACT_CONTOURS_SIZE:
+ img_iface_contours_size(data);
+ break;
+ case IMG_IFACE_ACT_BOUNDING_RECT:
+ img_iface_bounding_rect(data);
+ break;
+ case IMG_IFACE_ACT_FIT_ELLIPSE:
+ img_iface_fit_ellipse(data);
+ break;
+ case IMG_IFACE_ACT_MIN_AREA_RECT:
+ img_iface_min_area_rect(data);
+ break;
+ /* Feature detection */
+ case IMG_IFACE_ACT_HOUGH_CIRCLES:
+ img_iface_hough_circles(data);
+ break;
+ /* img_orb */
+ case IMG_IFACE_ACT_ALIGN:
+ img_iface_align();
+ break;
+ /* img_calib3d */
+ case IMG_IFACE_ACT_CALIBRATE:
+ img_iface_calibrate(data);
+ break;
+ case IMG_IFACE_ACT_UNDISTORT:
+ img_iface_undistort(data);
+ break;
+ /* img_zbar */
+ case IMG_IFACE_ACT_DECODE:
+ img_iface_decode(data);
+ break;
+ /* img_ocr */
+ case IMG_IFACE_ACT_READ:
+ img_iface_read(data);
+ break;
+ /* img_iface */
+ case IMG_IFACE_ACT_APPLY:
+ img_iface_apply();
+ break;
+ case IMG_IFACE_ACT_DISCARD:
+ img_iface_discard();
+ break;
+ case IMG_IFACE_ACT_SAVE_MEM:
+ img_iface_save_mem(data);
+ break;
+ case IMG_IFACE_ACT_LOAD_MEM:
+ img_iface_load_mem(data);
+ break;
+ case IMG_IFACE_ACT_SAVE_REF:
+ img_iface_save_ref();
+ break;
+ /* save */
+ case IMG_IFACE_ACT_SAVE_FILE:
+ img_iface_save_file();
+ break;
+ case IMG_IFACE_ACT_SAVE_UPDT:
+ img_iface_save_update();
+ break;
+ default:
+ /* Invalid action */
+ break;
+ }
+}
+
+void img_iface_show_img (void)
+{
+
+ cv::imshow(WIN_NAME_IMG, image_copy_tmp);
+ cv::waitKey(WIN_TIMEOUT);
+}
+
+void img_iface_show_hist_c1 (void)
+{
+
+ cv::imshow(WIN_NAME_HIST, hist_img_c1);
+ cv::waitKey(WIN_TIMEOUT);
+}
+
+void img_iface_show_hist_c3 (void)
+{
+
+ cv::imshow(WIN_NAME_HIST, hist_img_c3);
+ cv::waitKey(WIN_TIMEOUT);
+}
+
+
+/******************************************************************************
+ ******* static functions *****************************************************
+ ******************************************************************************/
+/* alx -----------------------------------------------------------------------*/
+static void img_iface_local_max (void)
+{
+
+ if (image_copy_tmp.channels() != 1)
+ goto err;
+
+ img_alx_act(&image_copy_tmp, IMG_ALX_ACT_LOCAL_MAX, NULL);
+
+ user_iface_log_write(1, "Local maxima");
+ return;
+err:
+ user_iface_log_write(1, "! Invalid input (Must be 1 channel)");
+}
+
+static void img_iface_skeleton (void)
+{
+
+ if (image_copy_tmp.channels() != 1)
+ goto err;
+
+ img_alx_act(&image_copy_tmp, IMG_ALX_ACT_SKELETON, NULL);
+
+ user_iface_log_write(1, "Skeleton");
+ return;
+err:
+ user_iface_log_write(1, "! Invalid input (Must be 1 channel)");
+}
+
+static void img_iface_lines_horizontal (void)
+{
+
+ if (image_copy_tmp.channels() != 1)
+ goto err;
+
+ img_alx_act(&image_copy_tmp, IMG_ALX_ACT_LINES_HORIZONTAL, NULL);
+
+ user_iface_log_write(1, "Horizontal lines");
+ return;
+err:
+ user_iface_log_write(1, "! Invalid input (Must be 1 channel)");
+}
+
+static void img_iface_lines_vertical (void)
+{
+
+ if (image_copy_tmp.channels() != 1)
+ goto err;
+
+ img_alx_act(&image_copy_tmp, IMG_ALX_ACT_LINES_VERTICAL, NULL);
+
+ user_iface_log_write(1, "Vertical lines");
+ return;
+err:
+ user_iface_log_write(1, "! Invalid input (Must be 1 channel)");
+}
+
+static void img_iface_mean_horizontal (void)
+{
+
+ if (image_copy_tmp.channels() != 1)
+ goto err;
+
+ img_alx_act(&image_copy_tmp, IMG_ALX_ACT_MEAN_HORIZONTAL, NULL);
+
+ user_iface_log_write(1, "Horizontal mean");
+ return;
+err:
+ user_iface_log_write(1, "! Invalid input (Must be 1 channel)");
+}
+
+static void img_iface_mean_vertical (void)
+{
+ if (image_copy_tmp.channels() != 1)
+ goto err;
+
+ img_alx_act(&image_copy_tmp, IMG_ALX_ACT_MEAN_VERTICAL, NULL);
+
+ user_iface_log_write(1, "Vertical mean");
+ return;
+err:
+ user_iface_log_write(1, "! Invalid input (Must be 1 channel)");
+}
+
+static void img_iface_median_horizontal (void)
+{
+
+ if (image_copy_tmp.channels() != 1)
+ goto err;
+
+ img_alx_act(&image_copy_tmp, IMG_ALX_ACT_MEDIAN_HORIZONTAL, NULL);
+
+ user_iface_log_write(1, "Horizontal median");
+ return;
+err:
+ user_iface_log_write(1, "! Invalid input (Must be 1 channel)");
+}
+
+static void img_iface_median_vertical (void)
+{
+
+ if (image_copy_tmp.channels() != 1)
+ goto err;
+
+ img_alx_act(&image_copy_tmp, IMG_ALX_ACT_MEDIAN_VERTICAL, NULL);
+
+ user_iface_log_write(1, "Vertical median");
+ return;
+err:
+ user_iface_log_write(1, "! Invalid input (Must be 1 channel)");
+}
+
+/* cv ------------------------------------------------------------------------*/
+/* ----- Core: The core functionality */
+/* ----- ------- Pixel */
+static void img_iface_pixel_get (const void *data)
+{
+ const struct Img_Iface_Data_Pixel_Get *data_cast;
+ struct Img_Iface_Data_Pixel_Get data_tmp;
+ unsigned char val;
+ ptrdiff_t tmp;
+ char txt[LOG_LINE_LEN];
+
+ if (image_copy_tmp.channels() != 1)
+ goto err;
+
+ if (!data) {
+ data_tmp.val = &val;
+ tmp = image_copy_tmp.cols;
+ data_tmp.x = user_iface_getint(0, 0, tmp, "x:", NULL);
+ tmp = image_copy_tmp.rows;
+ data_tmp.y = user_iface_getint(0, 0, tmp, "y:", NULL);
+ data = (const void *)&data_tmp;
+ }
+
+ img_cv_act(&image_copy_tmp, IMG_CV_ACT_PIXEL_GET, data);
+
+ /* Write into user_iface_log_write */
+ data_cast = (const struct Img_Iface_Data_Pixel_Get *)data;
+ snprintf(txt, LOG_LINE_LEN, "Pixel get: (%ti, %ti): %i",
+ data_cast->x, data_cast->y, *data_cast->val);
+ user_iface_log_write(1, txt);
+ return;
+err:
+ user_iface_log_write(1, "! Invalid input (Must be 1 channel)");
+}
+
+static void img_iface_pixel_set (const void *data)
+{
+ const struct Img_Iface_Data_Pixel_Set *data_cast;
+ struct Img_Iface_Data_Pixel_Set data_tmp;
+ ptrdiff_t tmp;
+ char txt[LOG_LINE_LEN];
+
+ if (image_copy_tmp.channels() != 1)
+ goto err;
+
+ if (!data) {
+ tmp = image_copy_tmp.cols;
+ data_tmp.x = user_iface_getint(0, 0, tmp, "x:", NULL);
+ tmp = image_copy_tmp.rows;
+ data_tmp.y = user_iface_getint(0, 0, tmp, "y:", NULL);
+ data_tmp.val = user_iface_getint(0, 0, UINT8_MAX, "val:", NULL);
+ data = (const void *)&data_tmp;
+ }
+
+ img_cv_act(&image_copy_tmp, IMG_CV_ACT_PIXEL_SET, data);
+
+ data_cast = (const struct Img_Iface_Data_Pixel_Set *)data;
+ snprintf(txt, LOG_LINE_LEN, "Pixel get: (%ti, %ti): %i",
+ data_cast->x, data_cast->y, data_cast->val);
+ user_iface_log_write(1, txt);
+ return;
+err:
+ user_iface_log_write(1, "! Invalid input (Must be 1 channel)");
+}
+
+/* ----- ------- ROI */
+static void img_iface_set_ROI (const void *data)
+{
+ const struct Img_Iface_Data_SetROI *data_cast;
+ struct Img_Iface_Data_SetROI data_tmp;
+ ptrdiff_t tmp;
+ char txt[LOG_LINE_LEN];
+
+ if (!data) {
+ tmp = image_copy_tmp.cols;
+ data_tmp.rect.x = user_iface_getint(0, 0, tmp, "Origin: x:",
+ NULL);
+ tmp = image_copy_tmp.rows;
+ data_tmp.rect.y = user_iface_getint(0, 0, tmp, "Origin: y:",
+ NULL);
+ tmp = image_copy_tmp.cols - data_tmp.rect.x;
+ data_tmp.rect.width = user_iface_getint(1, tmp, tmp, "Width:",
+ NULL);
+ tmp = image_copy_tmp.rows - data_tmp.rect.y;
+ data_tmp.rect.height = user_iface_getint(1, tmp, tmp,"Height:",
+ NULL);
+ data = (const void *)&data_tmp;
+ }
+
+ img_cv_act(&image_copy_tmp, IMG_CV_ACT_SET_ROI, data);
+
+ data_cast = (const struct Img_Iface_Data_SetROI *)data;
+ snprintf(txt, LOG_LINE_LEN, "ROI: (%i,%i) w=%i,h=%i",
+ data_cast->rect.x, data_cast->rect.y,
+ data_cast->rect.width, data_cast->rect.height);
+ user_iface_log_write(1, txt);
+}
+
+static void img_iface_set_ROI_2rect (const void *data)
+{
+ const struct Img_Iface_Data_SetROI *data_cast;
+ struct Img_Iface_Data_SetROI data_tmp;
+ char txt[LOG_LINE_LEN];
+
+ if (!data) {
+ data_tmp.rect.x = rectangle.x;
+ data_tmp.rect.y = rectangle.y;
+ data_tmp.rect.width = rectangle.width;
+ data_tmp.rect.height = rectangle.height;
+ data = (const void *)&data_tmp;
+ }
+
+ img_cv_act(&image_copy_tmp, IMG_CV_ACT_SET_ROI, data);
+
+ data_cast = (const struct Img_Iface_Data_SetROI *)data;
+ snprintf(txt, LOG_LINE_LEN, "ROI: (%i,%i) w=%i,h=%i",
+ data_cast->rect.x, data_cast->rect.y,
+ data_cast->rect.width, data_cast->rect.height);
+ user_iface_log_write(1, txt);
+}
+
+/* ----- ------- Operations on arrays */
+static void img_iface_and_2ref (void)
+{
+
+ if (image_copy_tmp.channels() != image_ref.channels())
+ goto err;
+
+ img_cv_act(&image_copy_tmp, IMG_CV_ACT_AND_2REF,
+ (const void *)&image_ref);
+
+ user_iface_log_write(1, "Bitwise AND");
+ return;
+err:
+ user_iface_log_write(1, "! Invalid input (Channels do not match ref)");
+}
+
+static void img_iface_not (void)
+{
+
+ img_cv_act(&image_copy_tmp, IMG_CV_ACT_NOT, NULL);
+
+ user_iface_log_write(1, "Invert color");
+}
+
+static void img_iface_or_2ref (void)
+{
+
+ if (image_copy_tmp.channels() != image_ref.channels())
+ goto err;
+
+ img_cv_act(&image_copy_tmp, IMG_CV_ACT_OR_2REF,
+ (const void *)&image_ref);
+
+ user_iface_log_write(1, "Bitwise OR");
+ return;
+err:
+ user_iface_log_write(1, "! Invalid input (Channels do not match ref)");
+}
+
+static void img_iface_component (const void *data)
+{
+ const struct Img_Iface_Data_Component *data_cast;
+ struct Img_Iface_Data_Component data_tmp;
+ ptrdiff_t tmp;
+ char txt[LOG_LINE_LEN];
+
+ if (image_copy_tmp.channels() < 2)
+ goto err;
+
+ if (!data) {
+ tmp = image_copy_tmp.channels() - 1;
+ data_tmp.cmp = user_iface_getint(0, 0, tmp, "Component:", NULL);
+ data = (const void *)&data_tmp;
+ }
+
+ img_cv_act(&image_copy_tmp, IMG_CV_ACT_COMPONENT, data);
+
+ data_cast = (const struct Img_Iface_Data_Component *)data;
+ snprintf(txt, LOG_LINE_LEN, "Component %ti", data_cast->cmp);
+ user_iface_log_write(1, txt);
+ return;
+err:
+ user_iface_log_write(1, "! Invalid input (Must be >= 2 channels)");
+}
+
+/* ----- Imgproc: Image processing */
+/* ----- ------- Image filtering */
+static void img_iface_dilate (const void *data)
+{
+ const struct Img_Iface_Data_Dilate_Erode *data_cast;
+ struct Img_Iface_Data_Dilate_Erode data_tmp;
+ char txt[LOG_LINE_LEN];
+
+ if (!data) {
+ data_tmp.i = user_iface_getint(1, 1, INFINITY, "Iterations:",
+ NULL);
+ data = (const void *)&data_tmp;
+ }
+
+ img_cv_act(&image_copy_tmp, IMG_CV_ACT_DILATE, data);
+
+ data_cast = (const struct Img_Iface_Data_Dilate_Erode *)data;
+ snprintf(txt, LOG_LINE_LEN, "Dilate i = %i", data_cast->i);
+ user_iface_log_write(1, txt);
+}
+
+static void img_iface_erode (const void *data)
+{
+ const struct Img_Iface_Data_Dilate_Erode *data_cast;
+ struct Img_Iface_Data_Dilate_Erode data_tmp;
+ char txt[LOG_LINE_LEN];
+
+ if (!data) {
+ data_tmp.i = user_iface_getint(1, 1, INFINITY, "Iterations:",
+ NULL);
+ data = (const void *)&data_tmp;
+ }
+
+ img_cv_act(&image_copy_tmp, IMG_CV_ACT_ERODE, data);
+
+ data_cast = (const struct Img_Iface_Data_Dilate_Erode *)data;
+ snprintf(txt, LOG_LINE_LEN, "Erode i = %i", data_cast->i);
+ user_iface_log_write(1, txt);
+}
+
+static void img_iface_dilate_erode (const void *data)
+{
+ const struct Img_Iface_Data_Dilate_Erode *data_cast;
+ struct Img_Iface_Data_Dilate_Erode data_tmp;
+ char txt[LOG_LINE_LEN];
+
+ if (!data) {
+ data_tmp.i = user_iface_getint(1, 1, INFINITY, "Iterations:",
+ NULL);
+ data = (const void *)&data_tmp;
+ }
+
+ img_cv_act(&image_copy_tmp, IMG_CV_ACT_DILATE, data);
+ img_cv_act(&image_copy_tmp, IMG_CV_ACT_ERODE, data);
+
+ data_cast = (const struct Img_Iface_Data_Dilate_Erode *)data;
+ snprintf(txt, LOG_LINE_LEN, "Dilate-erode i = %i", data_cast->i);
+ user_iface_log_write(1, txt);
+}
+
+static void img_iface_erode_dilate (const void *data)
+{
+ const struct Img_Iface_Data_Dilate_Erode *data_cast;
+ struct Img_Iface_Data_Dilate_Erode data_tmp;
+ char txt[LOG_LINE_LEN];
+
+ if (!data) {
+ data_tmp.i = user_iface_getint(1, 1, INFINITY, "Iterations:",
+ NULL);
+ data = (const void *)&data_tmp;
+ }
+
+ img_cv_act(&image_copy_tmp, IMG_CV_ACT_ERODE, data);
+ img_cv_act(&image_copy_tmp, IMG_CV_ACT_DILATE, data);
+
+ data_cast = (const struct Img_Iface_Data_Dilate_Erode *)data;
+ snprintf(txt, LOG_LINE_LEN, "Erode-dilate i = %i", data_cast->i);
+ user_iface_log_write(1, txt);
+}
+
+static void img_iface_smooth (const void *data)
+{
+ const struct Img_Iface_Data_Smooth *data_cast;
+ struct Img_Iface_Data_Smooth data_tmp;
+ char txt[LOG_LINE_LEN];
+
+ if (!data) {
+ data_tmp.method = user_iface_getint(1, 3, 3,
+ "Method: MEAN=1, GAUSS=2, MEDIAN=3", NULL);
+ data_tmp.ksize = user_iface_getint(3, 3, INFINITY,
+ "Kernel size: 3, 5, 7, ...", NULL);
+ data = (const void *)&data_tmp;
+ }
+
+ img_cv_act(&image_copy_tmp, IMG_CV_ACT_SMOOTH, data);
+
+ data_cast = (const struct Img_Iface_Data_Smooth *)data;
+ snprintf(txt, LOG_LINE_LEN, "Smooth mth = %i [%i x %i]",
+ data_cast->method, data_cast->ksize, data_cast->ksize);
+ user_iface_log_write(1, txt);
+}
+
+static void img_iface_sobel (const void *data)
+{
+ const struct Img_Iface_Data_Sobel *data_cast;
+ struct Img_Iface_Data_Sobel data_tmp;
+ char txt[LOG_LINE_LEN];
+
+ if (image_copy_tmp.channels() != 1)
+ goto err;
+
+ if (!data) {
+ data_tmp.dx = user_iface_getint(0, 1, 10,
+ "Order of the derivative x", NULL);
+ data_tmp.dy = user_iface_getint(0, 1, 10,
+ "Order of the derivative y", NULL);
+ data_tmp.ksize = user_iface_getint(-1, 3, 7,
+ "Size of the extended Sobel kernel (Scharr: -1)",
+ NULL);
+ data = (const void *)&data_tmp;
+ }
+
+ img_cv_act(&image_copy_tmp, IMG_CV_ACT_SOBEL, data);
+
+ data_cast = (const struct Img_Iface_Data_Sobel *)data;
+ snprintf(txt, LOG_LINE_LEN, "Sobel dx = %i; dy = %i [ks = %i]",
+ data_cast->dx, data_cast->dy, data_cast->ksize);
+ user_iface_log_write(1, txt);
+ return;
+err:
+ user_iface_log_write(1, "! Invalid input (Must be 1 channel)");
+}
+
+static void img_iface_border (const void *data)
+{
+ const struct Img_Iface_Data_Border *data_cast;
+ struct Img_Iface_Data_Border data_tmp;
+ char txt[LOG_LINE_LEN];
+
+ if (image_copy_tmp.channels() != 1)
+ goto err;
+
+ if (!data) {
+ data_tmp.size = user_iface_getint(1, 1, INT16_MAX, "Size",NULL);
+ data = (const void *)&data_tmp;
+ }
+
+ img_cv_act(&image_copy_tmp, IMG_CV_ACT_BORDER, data);
+
+ data_cast = (const struct Img_Iface_Data_Border *)data;
+ snprintf(txt, LOG_LINE_LEN, "Border size = %ti", data_cast->size);
+ user_iface_log_write(1, txt);
+ return;
+err:
+ user_iface_log_write(1, "! Invalid input (Must be 1 channel)");
+}
+
+/* ----- ------- Geometric image transformations */
+static void img_iface_mirror (const void *data)
+{
+ const struct Img_Iface_Data_Mirror *data_cast;
+ struct Img_Iface_Data_Mirror data_tmp;
+ char txt[LOG_LINE_LEN];
+
+ if (!data) {
+ data_tmp.axis = user_iface_getint(0, 1, 1, "Axis: 0=x; 1=y",
+ NULL);
+ data = (const void *)&data_tmp;
+ }
+
+ img_cv_act(&image_copy_tmp, IMG_CV_ACT_MIRROR, data);
+
+ data_cast = (const struct Img_Iface_Data_Mirror *)data;
+ snprintf(txt, LOG_LINE_LEN, "Mirror axis: %i", data_cast->axis);
+ user_iface_log_write(1, txt);
+}
+
+static void img_iface_rotate_orto (const void *data)
+{
+ const struct Img_Iface_Data_Rotate_Orto *data_cast;
+ struct Img_Iface_Data_Rotate_Orto data_tmp;
+ char txt[LOG_LINE_LEN];
+
+ if (!data) {
+ data_tmp.n = user_iface_getint(1, 1, 3,
+ "Rotate (counterclockwise) n * pi/2 rad; n:",
+ NULL);
+ data = (const void *)&data_tmp;
+ }
+
+ img_cv_act(&image_copy_tmp, IMG_CV_ACT_ROTATE_ORTO, data);
+
+ data_cast = (const struct Img_Iface_Data_Rotate_Orto *)data;
+ snprintf(txt, LOG_LINE_LEN, "Rotate %i * pi/2 rad", data_cast->n);
+ user_iface_log_write(1, txt);
+}
+
+static void img_iface_rotate (const void *data)
+{
+ const struct Img_Iface_Data_Rotate *data_cast;
+ struct Img_Iface_Data_Rotate data_tmp;
+ char txt[LOG_LINE_LEN];
+
+ if (!data) {
+ data_tmp.center.x = user_iface_getdbl(0, 0, INFINITY,
+ "Center: x:", NULL);
+ data_tmp.center.y = user_iface_getdbl(0, 0, INFINITY,
+ "Center: y:", NULL);
+ data_tmp.angle = user_iface_getdbl(-INFINITY, 0, INFINITY,
+ "Angle: (deg)", NULL);
+ data = (const void *)&data_tmp;
+ }
+
+ img_cv_act(&image_copy_tmp, IMG_CV_ACT_ROTATE, data);
+
+ data_cast = (const struct Img_Iface_Data_Rotate *)data;
+ snprintf(txt, LOG_LINE_LEN, "Rotate (%.2f,%.2f) %lfº",
+ data_cast->center.x, data_cast->center.y,
+ data_cast->angle);
+ user_iface_log_write(1, txt);
+}
+
+static void img_iface_rotate_2rect (const void *data)
+{
+ struct Img_Iface_Data_Rotate data_tmp;
+
+ if (!data) {
+ data_tmp.center.x = rectangle_rot.center.x;
+ data_tmp.center.y = rectangle_rot.center.y;
+ data_tmp.angle = rectangle_rot.angle;
+ /* If angle is < -45º,
+ * it is taking into acount the incorrect side */
+ if (data_tmp.angle < -45.0)
+ data_tmp.angle += 90.0;
+ data = (const void *)&data_tmp;
+ }
+
+ img_cv_act(&image_copy_tmp, IMG_CV_ACT_ROTATE, data);
+
+ user_iface_log_write(1, "Rotate to rectangle");
+}
+
+/* ----- ------- Miscellaneous image transformations */
+static void img_iface_adaptive_thr (const void *data)
+{
+ const struct Img_Iface_Data_Adaptive_Thr *data_cast;
+ struct Img_Iface_Data_Adaptive_Thr data_tmp;
+ char txt[LOG_LINE_LEN];
+
+ if (image_copy_tmp.channels() != 1)
+ goto err;
+
+ if (!data) {
+ data_tmp.method = user_iface_getint(0, 1, 1,
+ "Method: MEAN=0, GAUSS=1", NULL);
+ data_tmp.thr_typ = user_iface_getint(0, 0, 1,
+ "Type: BIN=0, BIN_INV=1", NULL);
+ data_tmp.ksize = user_iface_getint(3, 3, INFINITY,
+ "Kernel size: 3, 5, 7, ...", NULL);
+ data = (const void *)&data_tmp;
+ }
+
+ img_cv_act(&image_copy_tmp, IMG_CV_ACT_ADAPTIVE_THRESHOLD, data);
+
+ data_cast = (const struct Img_Iface_Data_Adaptive_Thr *)data;
+ snprintf(txt, LOG_LINE_LEN, "Threshold mth=%i, typ=%i, ks=%i",
+ data_cast->method, data_cast->thr_typ,
+ data_cast->ksize);
+ user_iface_log_write(1, txt);
+ return;
+err:
+ user_iface_log_write(1, "! Invalid input (Must be 1 channel)");
+}
+
+static void img_iface_cvt_color (const void *data)
+{
+ const struct Img_Iface_Data_Cvt_Color *data_cast;
+ struct Img_Iface_Data_Cvt_Color data_tmp;
+ char txt[LOG_LINE_LEN];
+
+ if (image_copy_tmp.channels() != 3)
+ goto err;
+
+ if (!data) {
+ data_tmp.method =user_iface_getint(0, 0, cv::COLOR_COLORCVT_MAX,
+ "Method: BGR2GRAY = 6, BGR2HSV = 40", NULL);
+ data = (const void *)&data_tmp;
+ }
+
+ img_cv_act(&image_copy_tmp, IMG_CV_ACT_CVT_COLOR, data);
+
+ data_cast = (const struct Img_Iface_Data_Cvt_Color *)data;
+ snprintf(txt, LOG_LINE_LEN, "Convert color %i", data_cast->method);
+ user_iface_log_write(1, txt);
+ return;
+err:
+ user_iface_log_write(1, "! Invalid input (Must be 3 channels)");
+}
+
+static void img_iface_distance_transform (void)
+{
+
+ if (image_copy_tmp.channels() != 1)
+ goto err;
+
+ img_cv_act(&image_copy_tmp, IMG_CV_ACT_DISTANCE_TRANSFORM, NULL);
+
+ user_iface_log_write(1, "Distance transform");
+ return;
+err:
+ user_iface_log_write(1, "! Invalid input (Must be 1 channel)");
+}
+
+static void img_iface_threshold (const void *data)
+{
+ const struct Img_Iface_Data_Threshold *data_cast;
+ struct Img_Iface_Data_Threshold data_tmp;
+ char txt[LOG_LINE_LEN];
+
+ if (image_copy_tmp.channels() != 1)
+ goto err;
+
+ if (!data) {
+ data_tmp.thr_typ = user_iface_getint(0, 0, 4,
+ "Type: BIN=0, BIN_INV=1, TRUNC=2, TOZ=3, TOZ_INV=4",
+ NULL);
+ data_tmp.thr_val = user_iface_getint(-1, 0, UINT8_MAX,
+ "Value: 0 to 255 (or -1 for Otsu's algorithm)",
+ NULL);
+ data = (const void *)&data_tmp;
+ }
+
+ img_cv_act(&image_copy_tmp, IMG_CV_ACT_THRESHOLD, data);
+
+ data_cast = (const struct Img_Iface_Data_Threshold *)data;
+ snprintf(txt, LOG_LINE_LEN, "Threshold typ = %i, val = %i",
+ data_cast->thr_typ, data_cast->thr_val);
+ user_iface_log_write(1, txt);
+ return;
+err:
+ user_iface_log_write(1, "! Invalid input (Must be 1 channel)");
+}
+
+/* ----- ------- Histograms */
+static void img_iface_histogram (const void *data)
+{
+ struct Img_Iface_Data_Histogram data_tmp;
+
+ if (image_copy_tmp.channels() != 1)
+ goto err;
+
+ if (!data) {
+ data_tmp.hist_c0 = &histogram_c0;
+ data_tmp.hist_img = &hist_img_c1;
+ data = (const void *)&data_tmp;
+ }
+
+ img_cv_act(&image_copy_tmp, IMG_CV_ACT_HISTOGRAM, data);
+
+ user_iface_log_write(1, "Histogram");
+ return;
+err:
+ user_iface_log_write(1, "! Invalid input (Must be 1 channel)");
+}
+
+static void img_iface_histogram_c3 (const void *data)
+{
+ struct Img_Iface_Data_Histogram data_tmp;
+
+ if (image_copy_tmp.channels() != 3)
+ goto err;
+
+ if (!data) {
+ data_tmp.hist_c0 = &histogram_c0;
+ data_tmp.hist_c1 = &histogram_c1;
+ data_tmp.hist_c2 = &histogram_c2;
+ data_tmp.hist_img = &hist_img_c3;
+ data = (const void *)&data_tmp;
+ }
+
+ img_cv_act(&image_copy_tmp, IMG_CV_ACT_HISTOGRAM_C3, data);
+
+ user_iface_log_write(1, "Histogram (3 channels)");
+ return;
+err:
+ user_iface_log_write(1, "! Invalid input (Must be 3 channels)");
+}
+
+/* ----- ------- Structural analysis and shape descriptors */
+static void img_iface_contours (const void *data)
+{
+ const struct Img_Iface_Data_Contours *data_cast;
+ struct Img_Iface_Data_Contours data_tmp;
+ ptrdiff_t tmp;
+ char txt[LOG_LINE_LEN];
+
+ if (image_copy_tmp.channels() != 1)
+ goto err;
+
+ if (!data) {
+ data_tmp.contours = &contours;
+ data_tmp.hierarchy = &hierarchy;
+ data = (const void *)&data_tmp;
+ }
+
+ img_cv_act(&image_copy_tmp, IMG_CV_ACT_CONTOURS, data);
+
+ data_cast = (const struct Img_Iface_Data_Contours *)data;
+ tmp = data_cast->contours->size();
+ snprintf(txt, LOG_LINE_LEN, "Contours n = %ti", tmp);
+ user_iface_log_write(1, txt);
+ return;
+err:
+ user_iface_log_write(1, "! Invalid input (Must be 1 channel)");
+}
+
+static void img_iface_contours_size (const void *data)
+{
+ const struct Img_Iface_Data_Contours_Size *data_cast;
+ struct Img_Iface_Data_Contours_Size data_tmp;
+ ptrdiff_t tmp;
+ char txt[LOG_LINE_LEN];
+
+ if (!data) {
+ data_tmp.contours = &contours;
+ data_tmp.area = area;
+ data_tmp.perimeter = perimeter;
+ data = (const void *)&data_tmp;
+ }
+
+ img_cv_act(&image_copy_tmp, IMG_CV_ACT_CONTOURS_SIZE, data);
+
+ data_cast = (const struct Img_Iface_Data_Contours_Size *)data;
+ user_iface_log_write(1, "Contours size:");
+ tmp = data_cast->contours->size();
+ for (ptrdiff_t i = 0; i < tmp; i++) {
+ snprintf(txt, LOG_LINE_LEN, "cnt[%ti]: A = %lf; P = %lf;",
+ i, data_cast->area[i], data_cast->perimeter[i]);
+ user_iface_log_write(2, txt);
+ }
+}
+
+static void img_iface_bounding_rect (const void *data)
+{
+ struct Img_Iface_Data_Bounding_Rect data_tmp;
+
+ if (!data) {
+ if(!contours.size())
+ goto err;
+ data_tmp.contour = &(contours[0]);
+ data_tmp.rect = &rectangle;
+ data_tmp.show = true;
+ data = (const void *)&data_tmp;
+ }
+
+ img_cv_act(&image_copy_tmp, IMG_CV_ACT_BOUNDING_RECT, data);
+
+ user_iface_log_write(1, "Bounding rectangle");
+ return;
+err:
+ user_iface_log_write(1, "! Invalid input (No contours saved)");
+}
+
+static void img_iface_fit_ellipse (const void *data)
+{
+ struct Img_Iface_Data_MinARect data_tmp;
+
+ if (!data) {
+ if(!contours.size())
+ goto err;
+ data_tmp.contour = &(contours[0]);
+ data_tmp.rect = &rectangle_rot;
+ data_tmp.show = true;
+ data = (const void *)&data_tmp;
+ }
+
+ img_cv_act(&image_copy_tmp, IMG_CV_ACT_FIT_ELLIPSE, data);
+
+ user_iface_log_write(1, "Fit ellipse");
+ return;
+err:
+ user_iface_log_write(1, "! Invalid input (No contours saved)");
+}
+
+static void img_iface_min_area_rect (const void *data)
+{
+ struct Img_Iface_Data_MinARect data_tmp;
+
+ if (!data) {
+ if(!contours.size())
+ goto err;
+ data_tmp.contour = &(contours[0]);
+ data_tmp.rect = &rectangle_rot;
+ data_tmp.show = true;
+ data = (const void *)&data_tmp;
+ }
+
+ img_cv_act(&image_copy_tmp, IMG_CV_ACT_MIN_AREA_RECT, data);
+
+ user_iface_log_write(1, "Min area rectangle");
+ return;
+err:
+ user_iface_log_write(1, "! Invalid input (No contours saved)");
+}
+
+/* ----- ------- Feature detection */
+static void img_iface_hough_circles (const void *data)
+{
+ const struct Img_Iface_Data_Hough_Circles *data_cast;
+ struct Img_Iface_Data_Hough_Circles data_tmp;
+ ptrdiff_t tmp;
+ char txt[LOG_LINE_LEN];
+
+ if (image_copy_tmp.channels() != 1)
+ goto err;
+
+ if (!data) {
+ data_tmp.circles = &circles;
+ data_tmp.dist_min = user_iface_getdbl(0, 5, INFINITY,
+ "Minimum distance:", NULL);
+ data_tmp.param_1 = user_iface_getdbl(0, 200, INFINITY,
+ "param 1:", NULL);
+ data_tmp.param_2 = user_iface_getdbl(0, 100, INFINITY,
+ "param 2:", NULL);
+ data_tmp.radius_min = user_iface_getint(0, 10, INFINITY,
+ "Minimum radius", NULL);
+ data_tmp.radius_max = user_iface_getint(0, 0, INFINITY,
+ "Maximum radius", NULL);
+ data = (const void *)&data_tmp;
+ }
+
+ img_cv_act(&image_copy_tmp, IMG_CV_ACT_HOUGH_CIRCLES, data);
+
+ data_cast = (const struct Img_Iface_Data_Hough_Circles *)data;
+ tmp = data_cast->circles->size();
+ snprintf(txt, LOG_LINE_LEN, "Circles n = %ti", tmp);
+ user_iface_log_write(1, txt);
+ return;
+err:
+ user_iface_log_write(1, "! Invalid input (Must be 1 channel)");
+}
+
+/* orb -----------------------------------------------------------------------*/
+static void img_iface_align (void)
+{
+
+ if (image_ref.empty())
+ goto err;
+
+ img_orb_act(&image_ref, &image_copy_tmp, IMG_ORB_ACT_ALIGN);
+
+ user_iface_log_write(1, "Align to reference");
+ return;
+err:
+ user_iface_log_write(1, "! Reference is NULL");
+}
+
+/* calib3d -------------------------------------------------------------------*/
+static void img_iface_calibrate (const void *data)
+{
+ struct Img_Iface_Data_Calibrate data_tmp;
+
+ if (image_copy_tmp.channels() != 1)
+ goto err;
+
+ if (!data) {
+ data_tmp.intrinsic_mat = &intrinsic_mat;
+ data_tmp.dist_coefs = &dist_coefs;
+ data_tmp.rvecs = &rvecs;
+ data_tmp.tvecs = &tvecs;
+ data = (const void *)&data_tmp;
+ }
+
+ img_calib3d_act(&image_copy_tmp, IMG_CALIB3D_ACT_CALIBRATE, data);
+
+ user_iface_log_write(1, "Calibrate");
+ return;
+err:
+ user_iface_log_write(1, "! Invalid input (Must be 1 channel)");
+}
+
+static void img_iface_undistort (const void *data)
+{
+ struct Img_Iface_Data_Undistort data_tmp;
+
+ if (!data) {
+ data_tmp.intrinsic_mat = &intrinsic_mat;
+ data_tmp.dist_coefs = &dist_coefs;
+ data = (const void *)&data_tmp;
+ }
+
+ img_calib3d_act(&image_copy_tmp, IMG_CALIB3D_ACT_UNDISTORT, data);
+
+ user_iface_log_write(1, "Undistort");
+}
+
+/* zbar ----------------------------------------------------------------------*/
+static void img_iface_decode (const void *data)
+{
+ struct Img_Iface_Data_Decode data_tmp;
+ const struct Img_Iface_Data_Decode *data_cast;
+ char txt[LOG_LINE_LEN];
+
+ if (image_copy_tmp.channels() != 1)
+ goto err_chan;
+
+ if (!data) {
+ data_tmp.code_type = user_iface_getint(0, 0, INT_MAX,
+ "Type of code: (0 for all)", NULL);
+ data = (const void *)&data_tmp;
+ }
+
+ img_zb_act(&image_copy_tmp, IMG_ZB_ACT_DECODE, data);
+
+ data_cast = (const struct Img_Iface_Data_Decode *)data;
+ snprintf(txt, LOG_LINE_LEN, "Detect codes c = %i",data_cast->code_type);
+ user_iface_log_write(1, txt);
+
+ if (!zb_codes.n)
+ goto err_zb;
+ for (ptrdiff_t i = 0; i < zb_codes.n; i++) {
+ snprintf(txt, LOG_LINE_LEN, "%s -- '%s'",
+ zb_codes.arr[i].sym_name, zb_codes.arr[i].data);
+ user_iface_log_write(2, txt);
+ }
+ return;
+err_zb:
+ user_iface_log_write(2, "! No code detected");
+ return;
+err_chan:
+ user_iface_log_write(1, "! Invalid input (Must be 1 channel)");
+}
+
+/* ocr -----------------------------------------------------------------------*/
+static void img_iface_read (const void *data)
+{
+ struct Img_Iface_Data_Read data_tmp;
+ const struct Img_Iface_Data_Read *data_cast;
+ char txt[LOG_LINE_LEN];
+
+ if (image_copy_tmp.channels() != 1)
+ goto err_chan;
+
+ data_cast = (const struct Img_Iface_Data_Read *)data;
+
+ if (!data) {
+ data_tmp.lang = user_iface_getint(0, 1, 2,
+ "Language: ENG = 0, SPA = 1, CAT = 2", NULL);
+ data_tmp.conf = user_iface_getint(0, 1, 2,
+ "Config: none = 0, Price = 1", NULL);
+ } else {
+ data_tmp.lang = data_cast->lang;
+ data_tmp.conf = data_cast->conf;
+ }
+ /* Adapt image data */
+ data_tmp.img.data = image_copy_tmp.data;
+ data_tmp.img.width = image_copy_tmp.size().width;
+ data_tmp.img.height = image_copy_tmp.size().height;
+ data_tmp.img.B_per_pix = image_copy_tmp.channels();
+ data_tmp.img.B_per_line = image_copy_tmp.step1();
+ data = (const void *)&data_tmp;
+
+ img_ocr_act(IMG_OCR_ACT_READ, data);
+
+ snprintf(txt, LOG_LINE_LEN, "OCR (lang = %i) [c = %i]",
+ data_cast->lang, data_cast->conf);
+ user_iface_log_write(1, txt);
+ if (img_ocr_text[0] == '\0')
+ goto err_ocr;
+ return;
+err_ocr:
+ user_iface_log_write(2, "! No text detected");
+ return;
+err_chan:
+ user_iface_log_write(1, "! Invalid input (Must be 1 channel)");
+}
+
+/* iface ---------------------------------------------------------------------*/
+static void img_iface_apply (void)
+{
+
+ image_copy_old.release();
+ image_copy_tmp.copyTo(image_copy_old);
+
+ user_iface_log_write(1, "Apply changes");
+}
+
+static void img_iface_discard (void)
+{
+
+ image_copy_tmp.release();
+ image_copy_old.copyTo(image_copy_tmp);
+
+ user_iface_log_write(1, "Discard changes");
+}
+
+static void img_iface_save_mem (const void *data)
+{
+ ptrdiff_t m;
+ char txt[LOG_LINE_LEN];
+
+ if (!data)
+ m = user_iface_getint(0, 0, IMG_MEM_SIZE -1,"mem[m]; m:",NULL);
+ else
+ m = *(const ptrdiff_t *)data;
+
+ image_mem[m].release();
+ image_copy_tmp.copyTo(image_mem[m]);
+
+ snprintf(txt, LOG_LINE_LEN, "Save to mem[%ti]", m);
+ user_iface_log_write(1, txt);
+}
+
+static void img_iface_load_mem (const void *data)
+{
+ ptrdiff_t m;
+ char txt[LOG_LINE_LEN];
+
+ if (!data)
+ m = user_iface_getint(0, 0, IMG_MEM_SIZE -1,"mem[m]; m:",NULL);
+ else
+ m = *(const ptrdiff_t *)data;
+
+ if (image_mem[m].empty())
+ goto err;
+
+ image_copy_tmp.release();
+ image_mem[m].copyTo(image_copy_tmp);
+
+ snprintf(txt, LOG_LINE_LEN, "Load from mem[%ti]", m);
+ user_iface_log_write(1, txt);
+ return;
+err:
+ user_iface_log_write(1, "! Empty memory");
+}
+
+static void img_iface_save_ref (void)
+{
+
+ image_ref.release();
+ image_copy_tmp.copyTo(image_ref);
+
+ user_iface_log_write(1, "Save to reference");
+}
+
+/* save/save -----------------------------------------------------------------*/
+static void img_iface_save_file (void)
+{
+
+ user_iface_log_write(1, "Save as...");
+
+ image.release();
+ image_copy_tmp.copyTo(image);
+ save_image_file(NULL, NULL);
+}
+
+static void img_iface_save_update (void)
+{
+
+ image.release();
+ image_copy_tmp.copyTo(image);
+
+ user_iface_log_write(1, "Save: update img");
+}
+
+
+/******************************************************************************
+ ******* end of file **********************************************************
+ ******************************************************************************/