//Source file: D:\\Projects\\src\\yi\\iu\\region\\LabeledRgnFtsWithPxlValue.java

package yi.iu.region;

import yi.ds.*;
import yi.util.label.*;
import java.util.*;
import yi.util.config.*;
import yi.util.io.input.*;
import yi.util.io.output.*;
import yi.util.io.*;
import yi.iu.processor.resample.*;
import java.awt.*;
import yi.util.label.Label;
import yi.iu.imgdb.learn.*;


/**
 * Besides providing the region label of each pixel, it also remember the value of
 * each pixel.  Certainly, the values of each feature is stored too.
 *
 * This pixels value information is useful, say, when intersecting two results
 * from color segmentation and texture segmentation.  In that case, the mean of
 * each intersected region should be recalculated using the pixel values.
 */
public class LabeledRgnFtsWithPxlValue extends LabeledRegionFeatures
{
  public int REUSE = DIU.INPUT_NONE;
  public int OUTPUT = DOU.OUTPUT_SER;

  static final long serialVersionUID = -1665308988338301661L;

  /**
   * The values of each pixel.  For example, (HSI) of each pixel for color
   * segmentation.
   */
  protected double[][] m_pixelValues;

  public LabeledRgnFtsWithPxlValue() {
  }

  public LabeledRgnFtsWithPxlValue(double[][] pixel_values, int[] labels, int w, int h, int old_w, int old_h, boolean zeroAsBg, int ft_vect_dim)
  {
    super(pixel_values, labels, w, h, old_w, old_h, zeroAsBg, ft_vect_dim);
    m_pixelValues = pixel_values;
  }

  public LabeledRgnFtsWithPxlValue(int[] labels, int w, int h, int old_w, int old_h, boolean zeroAsBg, int ft_vect_dim)
  {
    super(labels, w, h, old_w, old_h, zeroAsBg, ft_vect_dim);
    m_pixelValues = null;
  }

  /**
   * Scale the results.  This method is useful to save space when outputing
   * the results
   * @param scaled_width
   * @param scaled_height
   */
  public void scale(int scaled_width, int scaled_height) {
    if (scaled_width == width && scaled_height == height) return;

    // scaled result width and height
    double x_ratio = (double)scaled_width / (double)width;
    double y_ratio = (double)scaled_height / (double)height;

    // new label
    double[][] scaled_values = new double[scaled_width * scaled_height][];
    int index = 0;
    for (int y=0; y<scaled_height; y++) {
      for (int x=0; x<scaled_width; x++, index++) {
        // corresponding coordinators in the results
        int corres_x = (int)Math.round(x / x_ratio);
        if (x<0) x = 0;
        if (x>=width) x=width -1;
        int corres_y = (int)Math.round(y / y_ratio);
        if (y<0) y = 0;
        if (y>=height) y=height -1;
        scaled_values[index] = m_pixelValues[corres_y * width + corres_x];
      }
    }
    m_pixelValues = scaled_values;
    super.scale(scaled_width, scaled_height);
  }

  public static LabeledRgnFtsWithPxlValue combineTwoRegionFeature(
      LabeledRgnFtsWithPxlValue ft_list1, LabeledRgnFtsWithPxlValue ft_list2,
      int size_threshold) {
    int[] label1 = ft_list1.m_labels;
    int[] label2 = ft_list2.m_labels;

    HashMapHashMap overlap_table = new HashMapHashMap();
    int index = 1; // avoid 0
    int[] new_label = new int[label1.length];
    for (int i = 0; i < label1.length; i++) {
      if (label1[i] == 0 || label2[i] == 0) {
        new_label[i] = 0;
        continue;
      }
      // first check whether there is a new label for such a combination
      Object obj = overlap_table.get(new Integer(label1[i]),
                                     new Integer(label2[i]));
      if (obj == null) { // if not give it a new one
        obj = new Integer(index);
        overlap_table.put(new Integer(label1[i]), new Integer(label2[i]), obj);
        index++;
      }
      new_label[i] = ( (Integer) obj).intValue();
    }

    // sort the labels
    Label.filterSmallRegions(new_label, size_threshold); // filtering small component
    Label.sequential(new_label, null, true);

    // combine the feature vectors
    double[][] pv1 = ft_list1.m_pixelValues;
    double[][] pv2 = ft_list2.m_pixelValues;
    int dim = ft_list1.m_ftVectDim + ft_list2.m_ftVectDim;
    double[][] data = new double[pv1.length][dim];

    for (int i = 0; i < data.length; i++) {
      int new_j = 0;
      if (pv1[i] != null) {
        for (int j = 0; j < pv1[i].length; j++, new_j++) {
          data[i][new_j] = pv1[i][j];
        }
      }
      new_j = ft_list1.m_ftVectDim;
      if (pv2[i] != null) {
        for (int j = 0; j < pv2[i].length; j++, new_j++) {
          data[i][new_j] = pv2[i][j];
        }
      }
    }

    return new LabeledRgnFtsWithPxlValue(data, new_label,
                                         ft_list1.width, ft_list1.height,
                                         ft_list1.originalWidth,
                                         ft_list1.originalHeight, true, dim);
  }

  public LabeledRegionFeatures createFromFile(String processor_name, int scale, int rst_scale, String img) throws Exception {
    String scaled_img_name = img;
    if (scale != 0)
      scaled_img_name = img +
          yi.iu.processor.resample.Resampler.RESIZED_FILE_SUFFIX + scale;
    if (rst_scale != 0)
      scaled_img_name = scaled_img_name +
          ".r"  + rst_scale;

    Configuration.setParameter("SOURCE_NAME", scaled_img_name);
    LabeledRgnFtsWithPxlValue ds = (LabeledRgnFtsWithPxlValue) reuseLabeledRgnFtsWithPxlValue(processor_name, DIU.
        INPUT_SER);

    return ds;
  }

//  public FeatureRepresentable createFeatureFromFile(String processor_name, int scale,
//      String img) throws Exception {
//    return createFromFile(processor_name, scale, 0, img);
//  }
//
//  public FeatureRepresentable createFeatureFromFile(String processor_name, int scale, int rst_scale,
//      String img) throws Exception {
//    return createFromFile(processor_name, scale, rst_scale, img);
//  }

  public Object reuseLabeledRgnFtsWithPxlValue(String processor_name, int reuse_level)
  {
    if (reuse_level != DIU.INPUT_NONE) {
      try {
        LabeledRgnFtsWithPxlValue rst = (LabeledRgnFtsWithPxlValue) DIU.in(
            reuse_level,
            processor_name,
            "LabeledRgnFtsWithPxlValue",
            Class.forName("yi.iu.region.LabeledRgnFtsWithPxlValue"));
        return rst;
      }
      catch (Exception e) {
        e.printStackTrace();
      }
    }
    return null;
  }

  void outputLabeledRgnFtsWithPxlValue(int output_level, String processor_name, LabeledRgnFtsWithPxlValue ds)
  {
   if (output_level != DOU.OUTPUT_NONE) {
     try {
       DOU.out(
           output_level,
           processor_name,
           "LabeledRgnFtsWithPxlValue",
           ds);
     } catch (DataOutputException e) {
       e.printStackTrace();
     }
   }
  }

  public LabeledRgnFtsWithPxlValue getReusableLabeledRgnFtsWithPxlValue(String img, String feautres_str, int scale, int rst_scale, String comb_ft_name, int size_threshold)
  throws Exception
  {

     LabeledRgnFtsWithPxlValue rst = (LabeledRgnFtsWithPxlValue)reuseLabeledRgnFtsWithPxlValue(comb_ft_name, REUSE);

     if (rst == null) {
       rst = getLabeledRgnFtsWithPxlValue(img, feautres_str, scale, rst_scale, size_threshold);
     }

     outputLabeledRgnFtsWithPxlValue(OUTPUT, comb_ft_name, rst);

     return rst;
  }

  public LabeledRgnFtsWithPxlValue getLabeledRgnFtsWithPxlValue(String img_name, String feautres_str, int scale, int rst_scale, int size_threshold)
  throws Exception
  {
    String[] features = feautres_str.split(";");

    // process
    String[] paras = features[0].split(",");
    String proc_name = paras[0];
    String ft_name = paras[1];
    LabeledRgnFtsWithPxlValue ft = (LabeledRgnFtsWithPxlValue) Class.forName(
        ft_name).newInstance();
    LabeledRgnFtsWithPxlValue ft1 = (LabeledRgnFtsWithPxlValue) ft.
        createFromFile(proc_name, scale, rst_scale, img_name);

    paras = features[1].split(",");
    proc_name = paras[0];
    ft_name = paras[1];
    ft = (LabeledRgnFtsWithPxlValue) Class.forName(ft_name).newInstance();
    LabeledRgnFtsWithPxlValue ft2 = (LabeledRgnFtsWithPxlValue) ft.
        createFromFile(proc_name, scale, rst_scale, img_name);

    return combineTwoRegionFeature(ft1, ft2, size_threshold);
  }

  /**
   * Generate the ColorLabeledRgnFts (region features with labels)
   */
  public static class CombLabeledRgnFtsWithPxlValue {

    public final static String USAGE = "Usage: -i img_list_file [-f processor_name,feature_class_name[;processor_name,feature_class_name]*] [-s scale] [-r rst_scale] [-n new_feature_name] [-t size_threshold] [-o original_image_path] [-p feature_path]";

    public static void main(String[] args)
    {
      // init configuration
      Configuration.init(args);

      // get the image name
      String img_name = ReadArgu.getOption('i', args);
      if (img_name == null) {
        System.err.println("Usage: -i image_name");
        System.exit(1);
      }

      String from_path = ReadArgu.getOption('o', args, "");
      String to_path = ReadArgu.getOption('p', args, "");

      // get the scale
      String scale_str = ReadArgu.getOption('s', args);
      int scale = 0;
      if (scale_str != null) {
        scale = Integer.parseInt(scale_str);
      }

      // get the scale
      String rst_scale_str = ReadArgu.getOption('r', args);
      int rst_scale = 0;
      if (rst_scale_str != null) {
        rst_scale = Integer.parseInt(rst_scale_str);
      }

     // get the features to combine
     String features_str = ReadArgu.getOption('f', args, "yi.iu.processor.color.reg.merge.KMeansHSISeg,yi.iu.processor.color.reg.ColorLabRgnFtsPxlVal;yi.iu.processor.texture.reg.ColorGuidedTextureSegNCC,yi.iu.processor.texture.reg.TextureLabRgnFtsPxlVal");

     // get the new feature name
     String new_ft_name = ReadArgu.getOption('n', args, "combined");

     // get the scale
     String size_t = ReadArgu.getOption('t', args);
     int size_threshold = 256;
     if (size_t != null) {
       size_threshold = Integer.parseInt(size_t);
     }

     try {
       // process
       Configuration.setParameter("SOURCE_NAME", img_name);
       Configuration.setParameter("DEST_PATH", to_path);
       yi.util.io.File.makeDirectory(to_path + img_name, true);

       LabeledRgnFtsWithPxlValue dummy = new LabeledRgnFtsWithPxlValue();
       LabeledRgnFtsWithPxlValue ds = dummy.getReusableLabeledRgnFtsWithPxlValue(img_name,
           features_str, scale, rst_scale, new_ft_name, size_threshold);

       int[] demo = ds.demo();
       String scaled_img_name = (scale == 0)? img_name : img_name + ".s" + scale;
       scaled_img_name = (rst_scale == 0)? scaled_img_name : scaled_img_name + ".r" + rst_scale;
       yi.util.io.OutputResult.outputGIFImage(to_path + scaled_img_name + ".ct.rgn.gif",
                                              demo, ds.width, ds.height, false);

       System.out.println("<img src=" + from_path + img_name + ">" +
                          "<img src=" + to_path + scaled_img_name + ".color.rgn.gif>" +
                          "<img src=" + to_path + scaled_img_name + ".text.rgn.gif>" +
                          "<img src=" + to_path + scaled_img_name + ".ct.rgn.gif><br>");


     } catch (Exception e) {
       e.printStackTrace();
     }

     System.exit(0);
    }

  }


}
