text: #! /usr/bin/env python
  
  """
  Początkowy moduł
  """
  import argparse
  
  import numpy
  
  from bitmap_mapper.min_max_difference_coordinates_bitmap_mapper import MinMaxDifferenceCoordinatesBitmapMapper
  from data_parsers.classify_data import ClassifyData
  from data_parsers.learning_data import LearningData
  from feature.simple_features.avg_size_of_hole_feature import AvgSizeOfHoleFeature
  from feature.simple_features.avg_size_of_island_feature import AvgSizeOfIslandFeature
  from feature.simple_features.first_quart_feature import FirstQuartFeature
  from feature.simple_features.first_raw_moment_horizontal import FirstRawMomentHorizontalFeature
  from feature.simple_features.first_raw_moment_vertical import FirstRawMomentVerticalFeature
  from feature.simple_features.fourth_quart_feature import FourthQuartFeature
  from feature.simple_features.longest_non_empty_antidiagonal_feature import LongestNonEmptyAntidiagonalFeature
  from feature.simple_features.longest_non_empty_column_feature import LongestNonEmptyColumnFeature
  from feature.simple_features.longest_non_empty_diagonal_feature import LongestNonEmptyDiagonalFeature
  from feature.simple_features.longest_non_empty_row_feature import LongestNonEmptyRowFeature
  from feature.simple_features.max_feature import MaxFeature
  from feature.simple_features.max_histogram_feature import MaxHistogramFeature
  from feature.simple_features.max_projection_horizontal_feature import MaxProjectionHorizontalFeature
  from feature.simple_features.max_projection_horizontal_value_feature import MaxProjectionHorizontalValueFeature
  from feature.simple_features.max_projection_vertical_feature import MaxProjectionVerticalFeature
  from feature.simple_features.max_projection_vertical_value_feature import MaxProjectionVerticalValueFeature
  from feature.simple_features.max_value_histogram_feature import MaxValueHistogramFeature
  from feature.simple_features.mean_feature import MeanFeature
  from feature.simple_features.median_feature import MedianFeature
  from feature.simple_features.min_feature import MinFeature
  from feature.simple_features.min_projection_horizontal_feature import MinProjectionHorizontalFeature
  from feature.simple_features.min_projection_horizontal_value_feature import MinProjectionHorizontalValueFeature
  from feature.simple_features.min_projection_vertical_feature import MinProjectionVerticalFeature
  from feature.simple_features.min_projection_vertical_value_feature import MinProjectionVerticalValueFeature
  from feature.simple_features.non_empty_columns_feature import NonEmptyColumnsFeature
  from feature.simple_features.non_empty_rows_feature import NonEmptyRowsFeature
  from feature.simple_features.number_of_holes_feature import NumberOfHolesFeature
  from feature.simple_features.number_of_islands_feature import NumberOfIslandsFeature
  from feature.simple_features.second_central_moment_horizontal import SecondCentralMomentHorizontalFeature
  from feature.simple_features.second_central_moment_vertical import SecondCentralMomentVerticalFeature
  from feature.simple_features.second_quart_feature import SecondQuartFeature
  from feature.simple_features.third_quart_feature import ThirdQuartFeature
  from feature_extractor.feature_extractor import FeatureExtractor
  from learning import Learning, LearningClassify
  
  
  def define_features() -> FeatureExtractor:
      """
      Funkcja inicjalizuje extractor wszystkimi feature'ami jakie mamy
      :return:
      """
      extractor = FeatureExtractor()
  
      extractor.add_feature(MaxFeature())#1
      extractor.add_feature(MinFeature())
      extractor.add_feature(MeanFeature())
      extractor.add_feature(MedianFeature())
      extractor.add_feature(NonEmptyColumnsFeature(0.05))#5 - blisko czarnego
      extractor.add_feature(NonEmptyRowsFeature(0.05))# blisko czarnego
      extractor.add_feature(ThirdQuartFeature())
      extractor.add_feature(SecondQuartFeature())
      extractor.add_feature(SecondCentralMomentVerticalFeature())
      extractor.add_feature(SecondCentralMomentHorizontalFeature())#10
      extractor.add_feature(NumberOfIslandsFeature(0.05))# blisko czarnego
      extractor.add_feature(NumberOfHolesFeature(0.95))# blisko bialego
      extractor.add_feature(FirstRawMomentVerticalFeature())
      extractor.add_feature(FirstRawMomentHorizontalFeature())
      extractor.add_feature(AvgSizeOfIslandFeature(0.05))# blisko czarnego # 15
      extractor.add_feature(AvgSizeOfHoleFeature(0.95))# blisko bialego
      extractor.add_feature(FourthQuartFeature())
      extractor.add_feature(LongestNonEmptyRowFeature(0.05))# blisko czarnego
      extractor.add_feature(LongestNonEmptyDiagonalFeature(0.05))# blisko czarnego
      extractor.add_feature(LongestNonEmptyColumnFeature(0.05))# blisko czarnego # 20
      extractor.add_feature(LongestNonEmptyAntidiagonalFeature(0.05))# blisko czarnego
      extractor.add_feature(FirstQuartFeature())# 22
      extractor.add_feature(MaxProjectionHorizontalFeature())
      extractor.add_feature(MaxProjectionHorizontalValueFeature())
      extractor.add_feature(MaxProjectionVerticalFeature())
      extractor.add_feature(MaxProjectionVerticalValueFeature())
      extractor.add_feature(MinProjectionHorizontalFeature())
      extractor.add_feature(MinProjectionHorizontalValueFeature())
      extractor.add_feature(MinProjectionVerticalFeature())
      extractor.add_feature(MinProjectionVerticalValueFeature())
      extractor.add_feature(MaxHistogramFeature())
      extractor.add_feature(MaxValueHistogramFeature())
  
      return extractor
  
  def classify_main(model_path: str, classify_data_path: str, output: str):
      extractor = define_features()
      data = ClassifyData(classify_data_path, extractor, MinMaxDifferenceCoordinatesBitmapMapper())
      data.get_classify_data()
      data.LoadDeletedColumns(model_path)
  
      model = LearningClassify(model_path)
      classes = model.classify(data)
  
      with open(output, "w") as f:
          for c in classes:
              f.write(f"{str(c)}\n")
  
  def train_main(training_path: str, test_path: str, output_path: str):
      extractor = define_features()
      data = LearningData(training_path, test_path, extractor, MinMaxDifferenceCoordinatesBitmapMapper())
  
      rowMask = CalculateFeaturesToIgnore(data, output_path)
      data.SetDeletedColumns(rowMask, output_path)
  
      model = Learning(extractor.feature_count() - len(numpy.where(rowMask)[0]), data.get_class_count()) # nie ma latwego sposobu na wylicznie ilosci klas. W moich danych testowych sa 4 klasy.
      model.plot_history(model.learn(data, 1024, 8), output_path)
      model.save_model(output_path)
  
  
  def CalculateFeaturesToIgnore(data, output_path):
      featuresMatrix = data.get_training_data()[0]
      corr = numpy.corrcoef(featuresMatrix.T)
      numpy.savetxt(output_path + ".corrarr", corr, fmt="%0.2e", delimiter=",")
      arrayCsv = open(output_path + ".corrarr", "r")
      lines = arrayCsv.readlines()
      k=0
      newlines = []
      classesList = data.GetFeaturesNames()
      classesStr = ","
      k=0
      for cls in classesList:
          if k==0:
              k+=1
          else:
              classesStr += ","
          classesStr += cls
      classesStr+="\n"
      newlines.append(classesStr)
      k=0
      for line in lines:
          newlines.append(classesList[k]+","+line)
          k+=1
      arrayCsv.close()
      arrayCsv = open(output_path + ".corrarr", "w")
      arrayCsv.writelines(newlines)
      arrayCsv.close()
  
      rowMask = numpy.all(numpy.isnan(corr), axis=1)
      for index in range(numpy.shape(corr)[0]):
          if rowMask[index] == True:
              pass
          else:
              for oIndex in range(numpy.shape(corr)[0]):
                  if oIndex <= index:
                      pass
                  else:
                      if numpy.abs(corr[index, oIndex]) > 0.9:
                          rowMask[oIndex] = True
      data.SetActiveFeatures(rowMask)
      return rowMask
  
  
  if __name__ == "__main__":
      parser = argparse.ArgumentParser(description='TAIO obrazki w skali szarosci')
      subparser = parser.add_subparsers(dest='mode')
      parser_training = subparser.add_parser('training', help="Training mode")
      parser_training.add_argument("train_path", help="path to training dataset")
      parser_training.add_argument("test_path", help="path to testing dataset")
      parser_training.add_argument("-o", "--output", help="Output path for model from learning process",
                                   default="model.keras")
      parser_classify = subparser.add_parser('classify', help="Classification mode")
      parser_classify.add_argument("model_path", help="path to model file")
      parser_classify.add_argument("classification_path", help="path to objects to classify")
      parser_classify.add_argument("-o", "--output", help="Output path for classification result",
                                   default="output.txt")
      args = parser.parse_args()
  
      if args.mode == "classify":
          classify_main(args.model_path, args.classification_path, args.output)
      elif args.mode == "training":
          train_main(args.train_path, args.test_path, args.output)
  