/*
 * *****************************************************************
 * *                                                               *
 * *       Copyright (c) Fast Corporation, 2001                    *
 * *                                                               *
 * *   All Rights Reserved.  Unpublished rights  reserved  under   *
 * *   the copyright laws of the Japan.                            *
 * *                                                               *
 * *   The software contained on this media  is  proprietary  to   *
 * *   and  embodies  the  confidential  technology  of  Fast      *
 * *   Corporation.  Possession, use,  duplication  or             *
 * *   dissemination of the software and media is authorized only  *
 * *   pursuant to a valid written license from Fast Corporation.  *
 * *                                                               *
 * *****************************************************************
 */

/* CSC90X ダイナミックレンジ拡大                     RANGE.C */
/*[作成者]H.Yagi */
/*
目的:
関数:
履歴:  Ver 1.0     01/01/16    初版
        Ver 1.1     01/04/23    エンハンス(スロープ形状)で抽出した最大濃度以降の入力レベル
                                については濃度255固定に変換するよう変更。

注記:m_menu.hをインクルードして下さい。
      m_menu.c及びm_note.cをリンクして下さい。
*/

/*
 * Include compiler runtime library
 */
#include <string.h>
#include <math.h>


/*
 * Include CSC90X library
 */
#include "f_stdlib.h"
#include "f_time.h"
#include "f_gui.h"
#include "f_stdio.h"
#include "f_graph.h"
#include "f_image.h"
#include "f_pinf.h"
#include "f_video.h"
#include "f_system.h"
#include "f_bgray.h"
#include "f_gray.h"
#include "f_file.h"
#include "f_filter.h"

/*
 * Include CSC90X common local
 */
#include "m_menu.h"


/*
 * プロトタイプ宣言
 */
void  main( void );
void  main_menu_disp( void );
void  menu_disp4he( char *, char *, char *, char * );
void  disp_help( void );
void set_para( void );
void pdm_enhance_ab( int, int, int, PARADIGM * );
void pdm_disp_enhance( int, int, PARADIGM * );
void pdm_ascope( int, int, PARADIGM * );
void pdm_histogram_bfo( int, int, PARADIGM * );
void pdm_histogram_aft( int, int, PARADIGM * );
void range_cnv( void );
void exec( void );
int  xxx_freeze( int );
void cut_space( char *, char * );
void pdm_set_file_name( int, int, PARADIGM * );
void upper_modify( int, int, int );

extern int  message_note( void );

/*
 * メニュー項目
 */
#define LANG_N       2
#define MAIN_MENU_N  4
static const char *str_main_menu[MAIN_MENU_N][LANG_N] = {
    { "   SET    ", " 設 定 " },
    { "   EXEC   ", "  実 行  " },
    { "  PROC3   ", "  処理3  " },
    { "  PROC4   ", "  処理4  " }
};

#define  INIT_CUR_POS_X     255
#define  INIT_CUR_POS_Y     239

#define FILENAME_SAIZE  12
char grayfile[FILENAME_SAIZE+1];

static struct Gray_conv gconv;
struct _deviinfo devi;

int pad_level;
static PVAL value[15];
int gray_mem_no;
int pre_cnt;
int filter_sw;
int yuko_hist;
int enhance_a;
int enhance_b;
int auto_enh_sw;
int fs0_image_sw;           /*FS0画像入力スイッチ*/
int ave_num;


/*
 * メイン
 */
void  main( void )
{
    int  sts;
    int  xpos;
    int  ypos;
    int  s_xpos;
    int  s_ypos;

    /* 初期メッセージ表示 */
    if( NORMAL_RETURN != message_note() )
        return;

    /* パラメタ初期化 */
    xpos = INIT_CUR_POS_X;
    ypos = INIT_CUR_POS_Y;
    s_xpos = INIT_CUR_POS_X;
    s_ypos = INIT_CUR_POS_Y;
    gconv.Shape  = SLOPE_TYPE;
    gconv.Aparam = 0;
    gconv.Bparam = 50;
    auto_enh_sw  = ON;
    yuko_hist    = 100;
    enhance_a    = 0;
    enhance_b    = 50;
    fs0_image_sw = OFF;
    strcpy( grayfile, "GRAYMEM1.IMG" );   /*FS0入力画像ファイル名*/
    ave_num      = 0;


    /* 入力ビデオ制御 */
    Lib_input_video_control( GRAY_PLANE );

    /* ビデオ出力表示項目制御 */
    Lib_display_control( GRAY_PLANE | LINE_PLANE | CHAR_PLANE );

    /* ビデオ表示項目クリア */
    Lib_memory_clear( LINE_PLANE | CHAR_PLANE );

    /* カーソル初期化 */
    Lib_init_cursor();

    /* メインメニューの表示 */
    main_menu_disp();

    /* マウスカーソルの表示 */
    Lib_draw_cursor( INIT_CUR_POS_X, INIT_CUR_POS_Y );

    /* グレイメモリのアロケーション */
    gray_mem_no = Lib_alloc_gray_memory();
    if ( -1 == gray_mem_no )
    {
       Lib_display_message( 70, 200, "グレイメモリ アロケーションエラー", "処理打ち切り" );
       return;
    }
    else
       Lib_gray_memory_cls( gray_mem_no );


    /* メニュー制御 */
    for (;;)
    {
        sts = 0;

        /* マウス位置読みとり */
        sts = Lib_see_current_position( &xpos, &ypos );
        if ( s_xpos != xpos || s_ypos != ypos )
        {
            /* マウス表示位置移動 */
            Lib_move_cursor( xpos, ypos );
            s_xpos = xpos;
            s_ypos = ypos;
        }

        /* 処理振り分け */
        if( CURSOR_EXECUTE == sts )
        {
            if ( xpos > MENU_1_XS && xpos < MENU_1_XE && ypos > MENU_1_YS && ypos < MENU_1_YE )
            {
                Lib_memory_clear( LINE_PLANE | CHAR_PLANE );
                set_para();                                         /*設定*/
                main_menu_disp();
            }
            else if ( xpos > MENU_2_XS && xpos < MENU_2_XE && ypos > MENU_2_YS && ypos < MENU_2_YE )
            {
                Lib_memory_clear( LINE_PLANE | CHAR_PLANE );
                exec( );                                            /* 実行 */
                main_menu_disp();
            }
            else if ( xpos > MENU_H_XS && xpos < MENU_H_XE && ypos > MENU_H_YS && ypos < MENU_H_YE )
            {
                Lib_memory_clear( LINE_PLANE | CHAR_PLANE );
                disp_help();                                        /* ヘルプ */
                main_menu_disp();
            }
            else if ( xpos > MENU_E_XS && xpos < MENU_E_XE && ypos > MENU_E_YS && ypos < MENU_E_YE )
            {
                break;                                              /* 終了 */
            }
        }
    }

    Lib_free_gray_memory( gray_mem_no );
}


/*
 * メインメニュー表示
 */
static void  main_menu_disp( void )
{
    int iLanguage;

    /* 日本語/英語表示文字列切替情報取得 */
    iLanguage = Lib_get_disp_language();

    /* 整列キー表示 -> ( m_menu.c ) */
    SUB_menu_disp4he( (char *)str_main_menu[0][iLanguage],
                      (char *)str_main_menu[1][iLanguage],
                      (char *)NULL,
                      (char *)NULL
                    );
}


/*
 * ヘルプ表示
 */
static void  disp_help( void )
{
    Lib_chrdisp( 10,  8, "【機能\概要】                        RANGE" );
    Lib_chrdisp( 11, 10, "ダイナミックレンジ拡大" );
    Lib_chrdisp( 11, 12, "○エンハンスパラメータA,Bは自動または手動で" );
    Lib_chrdisp( 11, 13, " 選択可。自動の場合、最小濃度~最大濃度を抽出" );
    Lib_chrdisp( 11, 14, " し256階調へレンジ変換します。" );
    Lib_chrdisp( 11, 16, "○エンハンスは「スロープ形状」固定です。" );
    Lib_chrdisp( 11, 18, "○自動でMIN/MAXを算出する際、有効ヒストグラム" );
    Lib_chrdisp( 11, 19, " 以上の濃度のみを対象とします。" );
    Lib_chrdisp( 11, 21, "○エンハンス後に画像平均をかけることでヒストグ" );
    Lib_chrdisp( 11, 22, " ラムをなめらかにできます。" );
    Lib_chrdisp( 11, 24, "○任意にFS0画像入力も可能\です。" );
    Lib_chrdisp( 11, 26, "○エンハンス(スロープ形状)で抽出した最大濃度以降" );
    Lib_chrdisp( 11, 27, "  の入力レベルについては濃度255固定に変換する" );
    Lib_chrdisp( 11, 28, "  よう変更。" );
}


/************************************************************************/
/*  設定                                                             */
/************************************************************************/
void set_para()
{
int no;
int i;

    Lib_set_pad_maxstring( 18 );        /*パッド表示文字数変更*/
    pad_level = Lib_view_open();
    Lib_view_set_title( pad_level, "設定" );

    value[0].on_off_type    = auto_enh_sw;
    value[2].value_type     = (long)yuko_hist;
    value[4].value_type     = (long)enhance_a;
    value[5].value_type     = (long)enhance_b;
    value[6].value_type     = (long)ave_num;
    value[11].on_off_type   =  fs0_image_sw;

    i = 0;
    Lib_view_set_uniq_alter  ( pad_level,  5,  5,   "自動エンハンス", value[i].on_off_type,  i );                    i++;
    Lib_view_set_comment     ( pad_level,  5, 35,   "自動時パラメータ", i );                                        i++;
    Lib_view_set_uniq_numeral( pad_level, 10, 65,   "有効ヒストグラム(pix)", value[i].value_type, 1, 10000, i );     i++;
    Lib_view_set_comment     ( pad_level,  5, 100,  "手動時パラメータ", i );                                        i++;
    Lib_view_set_uniq_numeral( pad_level, 10, 130,  "エンハンス A", value[i].value_type, 0, 255, i );                i++;
    Lib_view_set_uniq_numeral( pad_level, 10, 160,  "エンハンス B", value[i].value_type, 0, 255, i );                i++;
    Lib_view_set_uniq_numeral( pad_level,  5, 195,  "平均回数", value[i].value_type, 0, 3, i );                 i++;
    Lib_view_set_null        ( pad_level,  5, 230,  "結果画像", i );                                            i++;
    Lib_view_set_null        ( pad_level,  5, 260,  "Aスコープ", i );                                          i++;
    Lib_view_set_null        ( pad_level,  5, 290,  "ヒストグラム(前)", i );                                  i++;
    Lib_view_set_null        ( pad_level,  5, 320,  "ヒストグラム(後)", i );                                  i++;
    Lib_view_set_uniq_alter  ( pad_level,  5, 350,  "FS0画像入力", value[i].on_off_type,  i );                  i++;

    Lib_set_xparadigm( pad_level,  4, WHOLE_TIMING, pdm_enhance_ab    );
    Lib_set_xparadigm( pad_level,  5, WHOLE_TIMING, pdm_enhance_ab    );
    Lib_set_paradigm ( pad_level,  7, START_TIMING, pdm_disp_enhance  );
    Lib_set_paradigm ( pad_level,  8, START_TIMING, pdm_ascope        );
    Lib_set_paradigm ( pad_level,  9, START_TIMING, pdm_histogram_bfo );
    Lib_set_paradigm ( pad_level, 10, START_TIMING, pdm_histogram_aft );
    Lib_set_paradigm ( pad_level, 11, END_TIMING  , pdm_set_file_name );

    Lib_view_set_size( pad_level, 0, 0, 5, 5 );
    Lib_draw_menu( pad_level );

    if( ERROR_RETURN != ( no = Lib_process_menu( pad_level, value ) ) )
    {
        auto_enh_sw  = value[0].on_off_type;
        yuko_hist    = (int)value[2].value_type;
        enhance_a    = (int)value[4].value_type;
        enhance_b    = (int)value[5].value_type;
        ave_num      = (int)value[6].value_type;
        fs0_image_sw = value[11].on_off_type;
    }
    else
    {
        Lib_chrdisp( 1, 28, "pad_level err" );
    }
    Lib_erase_menu( pad_level );
    Lib_view_close( pad_level );
    Lib_set_pad_maxstring( 10 );        /*パッド表示文字数初期化*/
}


/************************************************************************/
/*  エンハンスパラメータ設定                                            */
/************************************************************************/
void pdm_enhance_ab( menu_no, timing, numb, val )
int menu_no;
int timing;
int numb;
PARADIGM val[];
{
    if ( timing == START_TIMING )
    {
        Lib_erase_menu( pad_level );

        if ( OFF == value[11].on_off_type )
            Lib_freeze( NOT_TRANSMIT );
        else
            xxx_freeze( NOT_TRANSMIT );
    }

    if ( timing == END_TIMING )
    {
        Lib_freerun();
        Lib_memory_clear( LINE_PLANE | CHAR_PLANE );
        Lib_draw_menu( pad_level );
    }

    if ( 0 == menu_no )
        gconv.Aparam = (int)val[0].long_type;
    else
        gconv.Bparam = (int)val[0].long_type;

    Lib_make_grayconv_table( &gconv, OFF );
    Lib_gray_convert( 0, gray_mem_no );     /*エンハンス*/
    upper_modify( 0, gray_mem_no, gconv.Aparam + gconv.Bparam );
    Lib_xvideo_transmit( gray_mem_no, GRAY_PLANE );

}


/************************************************************************/
/*  エンハンス画像の表示                                               */
/************************************************************************/
void pdm_disp_enhance( timing, numb, val )
int timing;
int numb;
PARADIGM val[];
{
    Lib_erase_menu( pad_level );

    range_cnv( );                           /*レンジ変換*/

    Lib_display_keyinput( 430, 0, "  確認  " );

    Lib_freerun();
    Lib_draw_menu( pad_level );
}


/************************************************************************/
/*  Aスコープの表示                                                   */
/************************************************************************/
void pdm_ascope( timing, numb, val )
int timing;
int numb;
PARADIGM val[];
{
    Lib_erase_menu( pad_level );

    range_cnv( );                           /*レンジ変換*/

    Lib_ascope( 0 );                        /*Aスコープ表示*/

    Lib_freerun();
    Lib_draw_menu( pad_level );
}


/************************************************************************/
/*  レンジ変換(設定時)                                                */
/************************************************************************/
void range_cnv( )
{
int i;
static struct HISTDATA histp;

    if ( OFF == value[11].on_off_type )
        Lib_freeze( NOT_TRANSMIT );
    else
        xxx_freeze( NOT_TRANSMIT );


    if ( ON == value[0].on_off_type )       /*自動エンハンス?(最小濃度~最大濃度を抽出し256階調へ)*/
    {
        Lib_stddevi( CURRENT_MEMORY, &devi );       /*平均、標準偏差、最大、最小の取得*/
        Lib_histogram( CURRENT_MEMORY, &histp );

        /*有効ヒストグラムのチェック( MIN側 )*/
        for (;;)
        {
            if ( histp.hist_tbl[ devi.min ] < value[2].value_type )
                devi.min++;
            else
                break;
        }

        /*有効ヒストグラムのチェック( MAX側 )*/
        for (;;)
        {
            if ( histp.hist_tbl[ devi.max ] < value[2].value_type )
                devi.max--;
            else
                break;
        }

        gconv.Aparam = devi.min;
        gconv.Bparam = devi.max - devi.min;
    }
    else
    {
        gconv.Aparam = value[4].value_type;
        gconv.Bparam = value[5].value_type;
    }
    Lib_make_grayconv_table( &gconv, OFF );
    Lib_gray_convert( 0, gray_mem_no );     /*エンハンス*/
    upper_modify( 0, gray_mem_no, gconv.Aparam + gconv.Bparam );
    Lib_gray_memory_move( gray_mem_no, 0, 0xff );

    /*画像平均*/
    if ( 0 != value[6].value_type )
    {
        for ( i=0; i<value[6].value_type; i++ )
        {
            Lib_averaging( gray_mem_no, 0 );
            Lib_gray_memory_move( 0, gray_mem_no, 0xff );
        }
    }

    Lib_xvideo_transmit( 0, GRAY_PLANE );
}


/************************************************************************/
/*  ヒストグラム(前)の表示                                            */
/************************************************************************/
void pdm_histogram_bfo( timing, numb, val )
int timing;
int numb;
PARADIGM val[];
{
    Lib_erase_menu( pad_level );

    if ( OFF == value[11].on_off_type )
        Lib_freeze( NOT_TRANSMIT );
    else
        xxx_freeze( TRANSMIT );

    Lib_display_histogram( 0 );

    Lib_freerun();
    Lib_draw_menu( pad_level );
}


/************************************************************************/
/*  ヒストグラム(後)の表示                                           */
/************************************************************************/
void pdm_histogram_aft( timing, numb, val )
int timing;
int numb;
PARADIGM val[];
{
    Lib_erase_menu( pad_level );

    range_cnv( );                           /*レンジ変換*/

    Lib_display_histogram( 0 );

    Lib_freerun();
    Lib_draw_menu( pad_level );
}


/************************************************************************/
/*  実行                                                                */
/************************************************************************/
void exec()
{
int i;
static struct HISTDATA histp;

    if ( OFF == fs0_image_sw )
        Lib_freeze( NOT_TRANSMIT );
    else
        xxx_freeze( NOT_TRANSMIT );


    if ( ON == auto_enh_sw )        /*自動エンハンス?(最小濃度~最大濃度を抽出し256階調へ)*/
    {
        Lib_stddevi( CURRENT_MEMORY, &devi );       /*平均、標準偏差、最大、最小の取得*/
        Lib_histogram( CURRENT_MEMORY, &histp );

        /*有効ヒストグラムのチェック( MIN側 )*/
        for (;;)                     
        {
            if ( histp.hist_tbl[ devi.min ] < yuko_hist )
                devi.min++;
            else
                break;
        }

        /*有効ヒストグラムのチェック( MAX側 )*/
        for (;;)
        {
            if ( histp.hist_tbl[ devi.max ] < yuko_hist )
                devi.max--;
            else
                break;
        }

        gconv.Aparam = devi.min;
        gconv.Bparam = devi.max - devi.min;
    }
    else
    {
        gconv.Aparam = enhance_a;
        gconv.Bparam = enhance_b;
    }
    Lib_make_grayconv_table( &gconv, OFF );
    Lib_gray_convert( 0, gray_mem_no );     /*エンハンス*/
    upper_modify( 0, gray_mem_no, gconv.Aparam + gconv.Bparam );
    Lib_gray_memory_move( gray_mem_no, 0, 0xff );

    /*画像平均*/
    if ( 0 != ave_num )
    {
        for ( i=0; i<ave_num; i++ )
        {
            Lib_averaging( gray_mem_no, 0 );
            Lib_gray_memory_move( 0, gray_mem_no, 0xff );
        }
    }

    Lib_xvideo_transmit( 0, GRAY_PLANE );

    Lib_ascope( 0 );            /*Aスコープ表示*/

    Lib_freerun();
}


/************************************************************************/
/*  フリーズ                                                            */
/************************************************************************/
int xxx_freeze( flag )
int flag;       /* バッファ転送フラグ */
{
char wwstr[13];
char infile[20];
int status;

    status = ERROR_RETURN;
    Lib_freeze( NOT_TRANSMIT );
    Lib_chrdisp( 1, 30, "画像ロード中..." );

    cut_space( grayfile, wwstr );
    Lib_sprintf( infile, "\\FS0\\%s", wwstr );
    if ( 0 == Lib_fload( infile, Lib_adrs_gray_memory(0), Lib_get_fx_size()*Lib_get_fy_size() ) )
    {
        Lib_chrdisp( 1, 30, "         " );
        Lib_display_message( 70, 200, "fload_err", infile );
    }
    else
    {
        Lib_chrdisp( 1, 30, "         " );
        if ( ON == flag )
            Lib_xvideo_transmit( 0, GRAY_PLANE );     /* モニタ表示 */

        status = NORMAL_RETURN;
    }

    return( status );
}


/*********************************************************************/
/*  スペース除去                              */
/*********************************************************************/
void cut_space( instr, otstr )
char *instr;
char *otstr;
{
    for(;;)
    {
        if ( ' ' != *instr )
            *otstr++ = *instr;

        if ( 0x00 == *instr )
            break;

        instr++;
    }
}


/*********************************************************************/
/*   ファイル名設定                           */
/*********************************************************************/
void pdm_set_file_name( Timing, Numb, val )
int  Timing;
int  Numb;
PARADIGM val[];
{
    if ( ON == value[11].on_off_type )
        Lib_get_string_by_keyboad( 50, 200, 12, grayfile );
}


/*********************************************************************/
/* エンハンス(スロープ)オフセット以降の画素を最大レベル(255)とする  */
/*********************************************************************/
void upper_modify( src_mem, dst_mem, sta_level )
int src_mem, dst_mem;
int sta_level;
{
register int i,a;
int fx, fy;
unsigned char *sbase, *dbase;
unsigned char *sp, *dp;

    fx = Lib_get_fx_size();
    fy = Lib_get_fy_size();

    sbase  = (void *)Lib_adrs_gray_memory( src_mem );
    dbase  = (void *)Lib_adrs_gray_memory( dst_mem );

    dp = dbase;
    for ( i=0; i<fy; i++ )
    {
        sp = sbase + (fx*i);
        for ( a=0; a<fx; a++ )
        {
            if ( sta_level <= ( *sp & 0xff ))
            *dp = 0xff;
            sp++;
            dp++;
        }
    }
}