#include "fie.h"
#include "oal_aloc.h"
INT fnSMP_image_diff_execute(VOID *handle, FHANDLE h_target_img, FHANDLE h_dst);
VOID *fnSMP_image_diff_morphology_setup(FHANDLE h_master_img, INT filter_num, INT *errcode);
VOID *fnSMP_image_diff_stat_setup(FHANDLE *master_imgs, INT master_num, DOUBLE min_thresh, DOUBLE stddev_factor, INT *errcode);
VOID fnSMP_image_diff_teardown(VOID* handle);
typedef struct
{
FHANDLE h_min_img;
FHANDLE h_max_img;
} SMP_IMAGE_DIFF_DESC;
INT fnSMP_image_diff_execute(VOID *handle, FHANDLE h_target_img, FHANDLE h_dst)
{
INT tgt_width, tgt_height, tgt_channels, tgt_type;
INT dst_width, dst_height, dst_channels, dst_type;
INT max_width, max_height, max_channels, max_type;
INT min_width, min_height, min_channels, min_type;
SMP_IMAGE_DIFF_DESC *desc = (SMP_IMAGE_DIFF_DESC*)handle;
FHANDLE h_work_brighter = NULL, h_work_darker = NULL;
INT err = F_ERR_UNKNOWN;
err = F_ERR_INVALID_PARAM;
if (desc == NULL) {
goto exit;
}
err = fnFIE_img_get_params(h_target_img, &tgt_channels, &tgt_type, NULL, &tgt_width, &tgt_height);
if (err != F_ERR_NONE) {
goto exit;
}
err = fnFIE_img_get_params(h_dst, &dst_channels, &dst_type, NULL, &dst_width, &dst_height);
if (err != F_ERR_NONE) {
goto exit;
}
err = fnFIE_img_get_params(desc->h_max_img, &max_channels, &max_type, NULL, &max_width, &max_height);
if (err != F_ERR_NONE) {
goto exit;
}
err = fnFIE_img_get_params(desc->h_min_img, &min_channels, &min_type, NULL, &min_width, &min_height);
if (err != F_ERR_NONE) {
goto exit;
}
err = F_ERR_INVALID_IMAGE;
if (tgt_width != dst_width || tgt_width != max_width || tgt_width != min_width) {
goto exit;
}
if (tgt_height != dst_height || tgt_height != max_height || tgt_height != min_height) {
goto exit;
}
if (tgt_channels != dst_channels || tgt_channels != max_channels || tgt_channels != min_channels || tgt_channels != 1) {
goto exit;
}
if (tgt_type != dst_type || tgt_type != max_type || tgt_type != min_type || tgt_type != F_IMG_UC8) {
goto exit;
}
h_work_brighter = fnFIE_img_root_alloc(tgt_type, tgt_channels, tgt_width, tgt_height);
h_work_darker = fnFIE_img_root_alloc(tgt_type, tgt_channels, tgt_width, tgt_height);
if (h_work_brighter == NULL || h_work_darker == NULL) {
err = F_ERR_NOMEMORY;
goto exit;
}
err = fnFIE_img_sub(h_target_img, desc->h_max_img, h_work_brighter);
if (err != F_ERR_NONE) {
goto exit;
}
err = fnFIE_img_sub(desc->h_min_img, h_target_img, h_work_darker);
if (err != F_ERR_NONE) {
goto exit;
}
err = fnFIE_img_add(h_work_brighter, h_work_darker, h_dst);
if (err != F_ERR_NONE) {
goto exit;
}
err = F_ERR_NONE;
exit:
fnFIE_free_object(h_work_brighter);
fnFIE_free_object(h_work_darker);
return err;
}
VOID *fnSMP_image_diff_morphology_setup(FHANDLE h_master_img, INT filter_num, INT *errcode)
{
INT width, height, channels, type;
SMP_IMAGE_DIFF_DESC *desc = NULL;
INT err = F_ERR_UNKNOWN;
err = fnFIE_img_get_params(h_master_img, &channels, &type, NULL, &width, &height);
if (err != F_ERR_NONE) {
goto exit;
}
err = F_ERR_INVALID_PARAM;
if (filter_num < 1) {
goto exit;
}
err = F_ERR_INVALID_IMAGE;
if (channels != 1) {
goto exit;
}
if (type != F_IMG_UC8) {
goto exit;
}
desc = (SMP_IMAGE_DIFF_DESC*)fnOAL_malloc(sizeof(SMP_IMAGE_DIFF_DESC));
if (desc == NULL) {
err = F_ERR_NOMEMORY;
goto exit;
}
desc->h_max_img = fnFIE_img_root_alloc(type, channels, width, height);
desc->h_min_img = fnFIE_img_root_alloc(type, channels, width, height);
if (desc->h_max_img == NULL || desc->h_min_img == NULL) {
err = F_ERR_NOMEMORY;
goto exit;
}
err = fnFIE_dilation(h_master_img, desc->h_max_img, filter_num, 0);
if (err != F_ERR_NONE) {
goto exit;
}
err = fnFIE_erosion(h_master_img, desc->h_min_img, filter_num, 0);
if (err != F_ERR_NONE) {
goto exit;
}
err = F_ERR_NONE;
exit:
if (errcode) *errcode = err;
if (err == F_ERR_NONE) return desc;
fnSMP_image_diff_teardown(desc);
return NULL;
}
VOID *fnSMP_image_diff_stat_setup(FHANDLE *master_imgs, INT master_num, DOUBLE min_thresh, DOUBLE stddev_factor, INT *errcode)
{
INT width, height, channels, type;
SMP_IMAGE_DIFF_DESC *desc = NULL;
FHANDLE h_average_img = NULL;
FHANDLE h_stddev_img = NULL;
FHANDLE h_work = NULL;
INT err = F_ERR_UNKNOWN;
err = F_ERR_INVALID_PARAM;
if (master_imgs == NULL) {
goto exit;
}
if (master_num < 2) {
goto exit;
}
if (min_thresh < 0) {
goto exit;
}
if (stddev_factor <= 0) {
goto exit;
}
err = fnFIE_img_get_params(master_imgs[0], &channels, &type, NULL, &width, &height);
if (err != F_ERR_NONE) {
goto exit;
}
err = F_ERR_INVALID_IMAGE;
if (channels != 1) {
goto exit;
}
if (type != F_IMG_UC8) {
goto exit;
}
desc = (SMP_IMAGE_DIFF_DESC*)fnOAL_malloc(sizeof(SMP_IMAGE_DIFF_DESC));
if (desc == NULL) {
err = F_ERR_NOMEMORY;
goto exit;
}
desc->h_max_img = fnFIE_img_root_alloc(type, channels, width, height);
desc->h_min_img = fnFIE_img_root_alloc(type, channels, width, height);
h_work = fnFIE_img_root_alloc(type, channels, width, height);
if (desc->h_max_img == NULL || desc->h_min_img == NULL || h_work == NULL) {
err = F_ERR_NOMEMORY;
goto exit;
}
err = fnFIE_stats_img_average(master_imgs, master_num, &h_average_img, F_IMG_UC8);
if (err != F_ERR_NONE) {
goto exit;
}
err = fnFIE_stats_img_stddev(master_imgs, master_num, &h_stddev_img, F_IMG_UC8);
if (err != F_ERR_NONE) {
goto exit;
}
err = fnFIE_img_mul_const(h_stddev_img, stddev_factor, h_work);
if (err != F_ERR_NONE) {
goto exit;
}
err = fnFIE_img_max_const(h_work, min_thresh, h_work);
if (err != F_ERR_NONE) {
goto exit;
}
err = fnFIE_img_add(h_average_img, h_work, desc->h_max_img);
if (err != F_ERR_NONE) {
goto exit;
}
err = fnFIE_img_sub(h_average_img, h_work, desc->h_min_img);
if (err != F_ERR_NONE) {
goto exit;
}
err = F_ERR_NONE;
exit:
if (errcode) *errcode = err;
fnFIE_free_object(h_average_img);
fnFIE_free_object(h_stddev_img);
fnFIE_free_object(h_work);
if (err == F_ERR_NONE) return desc;
fnSMP_image_diff_teardown(desc);
return NULL;
}
VOID fnSMP_image_diff_teardown(VOID *handle)
{
SMP_IMAGE_DIFF_DESC *desc = (SMP_IMAGE_DIFF_DESC*)handle;
if (desc) {
fnFIE_free_object(desc->h_max_img);
fnFIE_free_object(desc->h_min_img);
fnOAL_free(desc);
}
}
static INT run_image_diff_morphology()
{
FHANDLE himg_master = NULL;
FHANDLE himg_target = NULL;
FHANDLE himg_dst = NULL;
VOID* handle = NULL;
INT err;
err = fnFIE_load_img_file("master.png", &himg_master, F_COLOR_IMG_TYPE_UC8);
if (err != F_ERR_NONE) goto exit;
err = fnFIE_load_img_file("target.png", &himg_target, F_COLOR_IMG_TYPE_UC8);
if (err != F_ERR_NONE) goto exit;
himg_dst = fnFIE_img_root_alloc(F_IMG_UC8, 1, fnFIE_img_get_width(himg_master), fnFIE_img_get_height(himg_master));
if (himg_dst == NULL) {
err = F_ERR_NOMEMORY;
goto exit;
}
handle = fnSMP_image_diff_morphology_setup(himg_master, 2, &err);
if (err != F_ERR_NONE) goto exit;
err = fnSMP_image_diff_execute(handle, himg_target, himg_dst);
if (err != F_ERR_NONE) goto exit;
err = fnFIE_save_png("dest_morphology.png", himg_dst, -1);
if (err != F_ERR_NONE) goto exit;
err = F_ERR_NONE;
exit:
fnFIE_free_object(himg_master);
fnFIE_free_object(himg_target);
fnFIE_free_object(himg_dst);
fnSMP_image_diff_teardown(handle);
return err;
}
static INT run_image_diff_stat()
{
FHANDLE himgs_master[] = {
NULL,
NULL,
NULL,
NULL,
NULL,
};
CHAR* master_paths[] = {
"master01.png",
"master02.png",
"master03.png",
"master04.png",
"master05.png",
};
INT num_masters = sizeof(master_paths) / sizeof(master_paths[0]);
FHANDLE himg_target = NULL;
FHANDLE himg_dst = NULL;
VOID* handle = NULL;
INT err, i;
for (i = 0; i < num_masters; i++)
{
err = fnFIE_load_img_file(master_paths[i], &himgs_master[i], F_COLOR_IMG_TYPE_UC8);
if (err != F_ERR_NONE) goto exit;
}
err = fnFIE_load_img_file("target.png", &himg_target, F_COLOR_IMG_TYPE_UC8);
if (err != F_ERR_NONE) goto exit;
himg_dst = fnFIE_img_root_alloc(F_IMG_UC8, 1, fnFIE_img_get_width(himg_target), fnFIE_img_get_height(himg_target));
if (himg_dst == NULL) {
err = F_ERR_NOMEMORY;
goto exit;
}
handle = fnSMP_image_diff_stat_setup(himgs_master, num_masters, 10, 3, &err);
if (err != F_ERR_NONE) goto exit;
err = fnSMP_image_diff_execute(handle, himg_target, himg_dst);
if (err != F_ERR_NONE) goto exit;
err = fnFIE_save_png("dest_stat.png", himg_dst, -1);
if (err != F_ERR_NONE) goto exit;
err = F_ERR_NONE;
exit:
for (i = 0; i < num_masters; i++)
{
fnFIE_free_object(himgs_master[i]);
}
fnFIE_free_object(himg_target);
fnFIE_free_object(himg_dst);
fnSMP_image_diff_teardown(handle);
return err;
}
INT main()
{
INT err;
fnFIE_setup();
err = run_image_diff_morphology();
if (err == F_ERR_NONE) {
err = run_image_diff_stat();
}
fnFIE_teardown();
return err;
}