#include "fie.h"
#include "oal_aloc.h"
#include <math.h>
#include <stdio.h>
enum smp_scan_direction
{
R_DIRECT,
L_DIRECT,
D_DIRECT,
U_DIRECT
};
INT fnSMP_box_edge(
FHANDLE hsrc,
DPNT_T start,
DOUBLE width,
DOUBLE height,
DOUBLE rad,
enum smp_scan_direction scan_dir,
F_EDGE1D_DIFF_FILTER diff_filter,
INT arnd,
enum f_edge1d_edge_direction direct_mode,
enum f_diff_type diff_type,
DOUBLE diff_thr,
enum f_edge1d_sort_mode detection_mode,
INT prj_width,
F_DEDGE** edges,
INT* edge_num
);
static INT fnSMP_scan_edges(FHANDLE hsrc, INT prj_width, F_EDGE1D_DIFF_FILTER diff_filter, INT arnd, enum f_edge1d_edge_direction direct_mode,
enum f_diff_type diff_type, DOUBLE diff_thr, enum f_edge1d_sort_mode detection_mode, F_DEDGE **edges, INT *edge_num, FMATRIX *inverse_af);
static INT fnSMP_mat_affine(DPNT_T start, DOUBLE width, DOUBLE height, DOUBLE rad, INT prj_width, FMATRIX **mat_aff, enum smp_scan_direction scan_dir);
static INT fnSMP_edges_outside(FHANDLE hsrc, DPNT_T *box, DOUBLE box_height, INT prj_width, F_EDGE1D_DIFF_FILTER diff_filter, INT arnd,
enum f_edge1d_edge_direction direct_mode, enum f_diff_type diff_type, DOUBLE diff_thr, enum f_edge1d_sort_mode detection_mode, F_DEDGE **edges, INT *edge_num);
INT fnSMP_box_edge(
FHANDLE hsrc,
DPNT_T start,
DOUBLE width,
DOUBLE height,
DOUBLE rad,
enum smp_scan_direction scan_dir,
F_EDGE1D_DIFF_FILTER diff_filter,
INT arnd,
enum f_edge1d_edge_direction direct_mode,
enum f_diff_type diff_type,
DOUBLE diff_thr,
enum f_edge1d_sort_mode detection_mode,
INT prj_width,
F_DEDGE** edges,
INT* edge_num
)
{
INT ret = F_ERR_UNKNOWN;
FHANDLE affine_img = NULL;
FHANDLE average_img = NULL;
FMATRIX *mat_aff = NULL;
FMATRIX *inverse_aff = NULL;
INT hsrc_width, hsrc_height, hsrc_type;
INT i;
BOOL is_inside;
DOUBLE box_w, box_h;
DPNT_T box_rearranged[4];
DPNT_T box_original[4];
ret = F_ERR_INVALID_PARAM;
if (prj_width < 0)goto EXIT;
if (width < 1 || height < 1)goto EXIT;
switch (scan_dir)
{
case R_DIRECT:
case L_DIRECT:
case D_DIRECT:
case U_DIRECT:
break;
default:
goto EXIT;
}
if (edges == NULL || *edges != NULL)goto EXIT;
ret = fnFIE_img_get_params(hsrc, NULL, &hsrc_type, NULL, &hsrc_width, &hsrc_height);
if (ret != F_ERR_NONE)goto EXIT;
ret = F_ERR_INVALID_IMAGE;
switch (hsrc_type)
{
case F_IMG_UC8:
case F_IMG_US16:
case F_IMG_DOUBLE:
break;
default:
goto EXIT;
}
ret = F_ERR_NOMEMORY;
mat_aff = fnFIE_mat_aalloc(3, 3);
if (mat_aff == NULL)goto EXIT;
inverse_aff = fnFIE_mat_aalloc(3, 3);
if (inverse_aff == NULL)goto EXIT;
ret = fnSMP_mat_affine(start, width, height, rad, prj_width, &mat_aff, scan_dir);
if (ret != F_ERR_NONE)goto EXIT;
ret = fnFIE_mat_inverse3(mat_aff, inverse_aff, NULL);
if (ret != F_ERR_NONE)goto EXIT;
if (scan_dir == R_DIRECT || scan_dir == L_DIRECT)
{
box_w = width;
box_h = height + prj_width * 2;
}
else
{
box_w = height;
box_h = width + prj_width * 2;
}
box_rearranged[0].x = 0;
box_rearranged[0].y = 0;
box_rearranged[1].x = box_w - 1;
box_rearranged[1].y = 0;
box_rearranged[2].x = 0;
box_rearranged[2].y = box_h - 1;
box_rearranged[3].x = box_w - 1;
box_rearranged[3].y = box_h - 1;
ret= fnFIE_geotrans_affine_npoints(box_rearranged, box_original, 4, inverse_aff);
if (ret != F_ERR_NONE)goto EXIT;
is_inside = TRUE;
for (i = 0; i < 4; i++)
{
if (box_original[i].x < 0 || box_original[i].x >= hsrc_width || box_original[i].y < 0 || box_original[i].y >= hsrc_height)
{
is_inside = FALSE;
break;
}
}
if (is_inside)
{
INT size_m, size_n;
affine_img = fnFIE_img_root_alloc(hsrc_type, 1, (INT)box_w, (INT)box_h);
if (affine_img == NULL)
{
ret = F_ERR_NOMEMORY;
goto EXIT;
}
ret = fnFIE_geotrans_affine(hsrc, affine_img, NULL, mat_aff, FALSE, F_SAMPLING_BILINEAR);
if (ret != F_ERR_NONE)goto EXIT;
average_img = fnFIE_img_root_alloc(F_IMG_DOUBLE, 1, (INT)box_w, (INT)box_h);
if (average_img == NULL)
{
ret = F_ERR_NOMEMORY;
goto EXIT;
}
size_m = 1;
size_n = prj_width * 2 + 1;
ret = fnFIE_averageMxN(affine_img, average_img, size_m, size_n, F_BORDER_NONE, 0);
if (ret != F_ERR_NONE)goto EXIT;
ret = fnSMP_scan_edges(average_img, prj_width, diff_filter, arnd, direct_mode, diff_type, diff_thr, detection_mode, edges, edge_num, inverse_aff);
if (ret != F_ERR_NONE)goto EXIT;
}
else
{
ret = fnSMP_edges_outside(hsrc, box_original, box_h,prj_width, diff_filter, arnd, direct_mode, diff_type, diff_thr, detection_mode, edges, edge_num);
if (ret != F_ERR_NONE)goto EXIT;
}
EXIT:
fnFIE_mat_afree(mat_aff);
fnFIE_free_object(affine_img);
fnFIE_free_object(average_img);
return ret;
}
static INT fnSMP_scan_edges(FHANDLE hsrc, INT prj_width, F_EDGE1D_DIFF_FILTER diff_filter, INT arnd,enum f_edge1d_edge_direction direct_mode,
enum f_diff_type diff_type,DOUBLE diff_thr, enum f_edge1d_sort_mode detection_mode, F_DEDGE **edges, INT *edge_num, FMATRIX *inverse_aff)
{
INT ret = F_ERR_UNKNOWN;
INT_PTR prj_step;
DOUBLE* prj;
INT y;
INT edge_cnt;
F_DEDGE* edge_buff_wk = NULL;
F_DEDGE* edges_on_line = NULL;
FHANDLE hvarray = NULL;
DPNT_T *src = NULL;
DPNT_T *dst = NULL;
INT i;
INT height, width;
ret = fnFIE_img_get_params(hsrc, NULL, NULL, NULL, &width, &height);
if (ret != F_ERR_NONE)goto EXIT;
prj_step = fnFIE_img_get_step(hsrc);
prj = (DOUBLE*)fnFIE_img_get_adrs(hsrc);
ret = F_ERR_NOMEMORY;
edges_on_line = (F_DEDGE*)fnOAL_malloc(width * sizeof(F_DEDGE));
if (edges_on_line == NULL)goto EXIT;
hvarray = fnFIE_vectarray_alloc((enum f_objtag)0, sizeof(F_DEDGE), 0);
if (hvarray == NULL)goto EXIT;
edge_cnt = 0;
for (y = prj_width; y < height - prj_width; y++)
{
INT line_edge_num;
const DOUBLE* wk_p = prj + (prj_step * y);
ret = fnFIE_edge1d_detect_edges_diff(wk_p, width, diff_filter, arnd, 0,
direct_mode, diff_type, diff_thr, detection_mode,
edges_on_line, width, &line_edge_num, NULL, width);
if (ret != F_ERR_NONE)goto EXIT;
if (line_edge_num > 0)
{
edges_on_line->y = y;
ret = fnFIE_vectarray_push_back(hvarray, edges_on_line);
if (F_ERR_NONE != ret)goto EXIT;
edge_cnt++;
}
}
if (edge_cnt == 0) {
*edges = NULL;
*edge_num = 0;
ret = F_ERR_NONE;
goto EXIT;
}
ret = F_ERR_NOMEMORY;
src = (DPNT_T*)fnOAL_malloc(edge_cnt * sizeof(DPNT_T));
if (src == NULL)goto EXIT;
dst = (DPNT_T*)fnOAL_malloc(edge_cnt * sizeof(DPNT_T));
if (dst == NULL)goto EXIT;
for (i = 0; i < edge_cnt; i++)
{
src[i].x = (*(F_DEDGE*)fnFIE_vectarray_getat(hvarray, i)).x;
src[i].y = (*(F_DEDGE*)fnFIE_vectarray_getat(hvarray, i)).y;
}
ret = fnFIE_geotrans_affine_npoints(src, dst, edge_cnt, inverse_aff);
if (ret != F_ERR_NONE)goto EXIT;
edge_buff_wk = (F_DEDGE*)fnOAL_malloc(edge_cnt * sizeof(F_DEDGE));
if (edge_buff_wk == NULL)
{
ret = F_ERR_NOMEMORY;
goto EXIT;
}
for (i = 0; i < edge_cnt; i++)
{
edge_buff_wk[i] = *(F_DEDGE*)fnFIE_vectarray_getat(hvarray, i);
edge_buff_wk[i].x = dst[i].x;
edge_buff_wk[i].y = dst[i].y;
}
*edges = edge_buff_wk;
*edge_num = edge_cnt;
ret = F_ERR_NONE;
EXIT:
fnOAL_free(edges_on_line);
fnFIE_vectarray_free(hvarray);
fnOAL_free(src);
fnOAL_free(dst);
if (ret != F_ERR_NONE) {
fnOAL_free(edge_buff_wk);
}
return ret;
}
static INT fnSMP_mat_affine(DPNT_T start, DOUBLE width, DOUBLE height, DOUBLE rad, INT prj_width, FMATRIX **mat_aff, enum smp_scan_direction scan_dir)
{
INT ret = F_ERR_UNKNOWN;
FMATRIX *mat_rotate = NULL;
FMATRIX *mat_shift = NULL;
FMATRIX *mat_line_rotate = NULL;
FMATRIX *mat_mul = NULL;
DOUBLE line_angle;
DOUBLE shift_x, shift_y;
ret = F_ERR_NOMEMORY;
mat_rotate = fnFIE_mat_aalloc(3, 3);
if (mat_rotate == NULL) goto EXIT;
mat_shift = fnFIE_mat_aalloc(3, 3);
if (mat_shift == NULL)goto EXIT;
mat_line_rotate = fnFIE_mat_aalloc(3, 3);
if (mat_line_rotate == NULL)goto EXIT;
mat_mul = fnFIE_mat_aalloc(3, 3);
if (mat_mul == NULL)goto EXIT;
ret = fnFIE_geotrans_calc_rotate_matrix(mat_rotate, -rad, start.x, start.y);
if (ret != F_ERR_NONE) goto EXIT;
switch (scan_dir)
{
case R_DIRECT:
{
line_angle = 0;
shift_x = -start.x;
shift_y = -start.y + prj_width;
}
break;
case L_DIRECT:
{
line_angle = PI;
shift_x = -start.x + width - 1;
shift_y = -start.y + height + prj_width - 1;
}
break;
case D_DIRECT:
{
line_angle = 1.5*PI;
shift_x = -start.x;
shift_y = -start.y + width + prj_width - 1;
}
break;
case U_DIRECT:
{
line_angle = 0.5*PI;
shift_x = -start.x + height - 1;
shift_y = -start.y + prj_width;
}
break;
default:
break;
}
ret = fnFIE_geotrans_calc_rotate_matrix(mat_line_rotate, line_angle, start.x, start.y);
if (ret != F_ERR_NONE) goto EXIT;
ret = fnFIE_geotrans_calc_shift_matrix(mat_shift, shift_x, shift_y);
if (ret != F_ERR_NONE)goto EXIT;
ret = fnFIE_mat_mul_aa(mat_shift, mat_line_rotate, mat_mul);
if (ret != F_ERR_NONE)goto EXIT;
ret = fnFIE_mat_mul_aa(mat_mul, mat_rotate, *mat_aff);
if (ret != F_ERR_NONE)goto EXIT;
EXIT:
fnFIE_mat_afree(mat_rotate);
fnFIE_mat_afree(mat_shift);
fnFIE_mat_afree(mat_line_rotate);
fnFIE_mat_afree(mat_mul);
return ret;
}
static INT fnSMP_edges_outside(FHANDLE hsrc, DPNT_T *box,DOUBLE box_height,INT prj_width, F_EDGE1D_DIFF_FILTER diff_filter, INT arnd,
enum f_edge1d_edge_direction direct_mode, enum f_diff_type diff_type, DOUBLE diff_thr, enum f_edge1d_sort_mode detection_mode, F_DEDGE **edges, INT *edge_num)
{
INT ret = F_ERR_UNKNOWN;
DPNT_T srt[2], end[2];
DOUBLE unit_x, unit_y;
DOUBLE norm;
DSGMT_T line;
INT i;
INT edge_cnt = 0;
F_DEDGE* edge_buff_wk = NULL;
F_DEDGE* edges_on_line = NULL;
FHANDLE hvarray = NULL;
srt[0] = box[0];
end[0] = box[1];
srt[1] = box[2];
end[1] = box[3];
unit_x = srt[1].x - srt[0].x;
unit_y = srt[1].y - srt[0].y;
norm = sqrt(unit_x*unit_x + unit_y*unit_y);
unit_x /= norm;
unit_y /= norm;
hvarray = fnFIE_vectarray_alloc((enum f_objtag)0, sizeof(F_DEDGE), 0);
if (hvarray == NULL)
{
ret = F_ERR_NOMEMORY;
goto EXIT;
}
for (i = prj_width; i < box_height - prj_width; i++)
{
INT line_edge_num = 0;
line.st.x = i*unit_x + srt[0].x;
line.st.y = i*unit_y + srt[0].y;
line.ed.x = i*unit_x + end[0].x;
line.ed.y = i*unit_y + end[0].y;
ret = fnFIE_edge1d_line2(hsrc, line, prj_width, diff_filter, arnd, 0, direct_mode,
diff_type, diff_thr, detection_mode, &edges_on_line, &line_edge_num, NULL, NULL);
if (line_edge_num > 0)
{
ret = fnFIE_vectarray_push_back(hvarray, edges_on_line);
if (F_ERR_NONE != ret)goto EXIT;
edge_cnt++;
}
fnOAL_free(edges_on_line); edges_on_line = NULL;
}
if (edge_cnt == 0) {
*edges = NULL;
*edge_num = 0;
ret = F_ERR_NONE;
goto EXIT;
}
edge_buff_wk = (F_DEDGE*)fnOAL_malloc(edge_cnt * sizeof(F_DEDGE));
if (edge_buff_wk == NULL)
{
ret = F_ERR_NOMEMORY;
goto EXIT;
}
for (i = 0; i < edge_cnt; i++)
{
edge_buff_wk[i] = *(F_DEDGE*)fnFIE_vectarray_getat(hvarray, i);
}
*edges = edge_buff_wk;
*edge_num = edge_cnt;
ret = F_ERR_NONE;
EXIT:
fnOAL_free(edges_on_line);
fnFIE_vectarray_free(hvarray);
if (ret != F_ERR_NONE) {
fnOAL_free(edge_buff_wk);
}
return ret;
}
static INT execute()
{
INT ret = F_ERR_UNKNOWN;
FHANDLE hsrc = NULL;
DPNT_T start;
DOUBLE width;
DOUBLE height;
DOUBLE rad;
enum smp_scan_direction scan_dir;
F_EDGE1D_DIFF_FILTER diff_filter;
INT arnd;
enum f_edge1d_edge_direction direct_mode;
enum f_diff_type diff_type;
DOUBLE diff_thr;
enum f_edge1d_sort_mode detection_mode;
INT prj_width;
F_DEDGE* edges = NULL;
INT edge_num;
ret = fnFIE_load_img_file("edges.bmp", &hsrc, F_COLOR_IMG_TYPE_UC8);
if (F_ERR_NONE != ret) goto EXIT;
start.x = 250;
start.y = 200;
width = 200;
height = 150;
rad = 0 * PI;
scan_dir = R_DIRECT;
diff_filter.minus_foot = 3;
diff_filter.minus_len = 1;
diff_filter.plus_foot = 3;
diff_filter.plus_len = 1;
arnd = 5;
direct_mode = F_DRK_TO_BRI;
diff_type = F_RELATIVE_THR;
diff_thr = 75;
detection_mode = F_POS_SORT;
prj_width = 5;
ret = fnSMP_box_edge(
hsrc,
start,
width,
height,
rad,
scan_dir,
diff_filter,
arnd,
direct_mode,
diff_type,
diff_thr,
detection_mode,
prj_width,
&edges,
&edge_num
);
if (F_ERR_NONE != ret) goto EXIT;
{
INT i;
for (i = 0; i < edge_num; i++)
{
printf("%03d: x=%0.5f, y=%0.5f, q=%0.1f, mag=%0.5f\n",
i, edges[i].x, edges[i].y, edges[i].q ,edges[i].mag);
}
}
EXIT:
fnFIE_free_object(hsrc);
fnOAL_free(edges);
return ret;
}
INT main()
{
INT ret = F_ERR_UNKNOWN;
fnFIE_setup();
ret = execute();
fnFIE_teardown();
return ret;
}