#pragma once
#include <maps/wikimap/mapspro/libs/tf_inferencer/tf_inferencer.h>
#include <maps/wikimap/mapspro/libs/tf_inferencer/maskrcnn_inferencer.h>
#include <opencv2/opencv.hpp>
#include <vector>

namespace maps {
namespace wiki {
namespace autocart {

using Polygon = std::vector<cv::Point2f>;

cv::Mat semSegmImage(const tf_inferencer::TensorFlowInferencer& segmentator,
                     const cv::Mat &image);

cv::Mat detectEdges(const tf_inferencer::TensorFlowInferencer& edgeDetector,
                    const cv::Mat &image);

/**
 * @brief Make raster markup
 *
 * @param image         satellite image
 * @param mask          mask of building on the image.
 *                      pixel has value 255 if it corresponds building on the satellite image
 *                      and zero value otherwise
 * @param edges         mask of the edges (can be empty)
 *                      pixel on the edges has zero value
 * @param rasterMarkup  every pixel has value which equal to index of building on the image
 *                      pixel = 0 - undefined
 *                      pixel = 1 - background
 * @return              number of detected building
 */
int extractRaster(const cv::Mat &image,
                  const cv::Mat &mask,
                  const cv::Mat &edges,
                  cv::Mat &rasterMarkup);

/**
 * @brief Convert raster markup to the set of rotated rectangles
 *
 * @param rasterMarkup    matrix with type 32S and one channel, which contain raster markup
 *                        all pixel of the connected component have same value
 *                        pixel = 0 - undefined
 *                        pixel = 1 - background
 * @param componentsCnt   amount of components in the raster markup
 * @return                vector of rotated rectangles,
 *                        every rectangle is cv::minAreaRect of one of connected component
 *                        but function return only rectangle for component, which contains
 *                        more than MIN_BLOB_PTS points.
 *                        Also area of rectangle must be great than MIN_RECT_AREA
 */
std::vector<cv::RotatedRect>
extractRectangles(const cv::Mat &rasterMarkup,
                  int componentsCnt);


/**
 * @brief detects buildings on sattelite image
 * @param image -- sattelite image to detect buildings on
 * @return container with detected polygons
 */
std::vector<Polygon>
detectBldByMinAreaRect(const tf_inferencer::TensorFlowInferencer& segmentator,
                       const tf_inferencer::TensorFlowInferencer& edgeDetector,
                       const cv::Mat &image);

/**
 * @brief detects buildings on sattelite image using only found edges
 * @param image -- sattelite image to detect buildings on
 * @return container with detected polygons
 */
std::vector<Polygon>
detectBldByEdges(const tf_inferencer::TensorFlowInferencer &edgeDetector,
                 const cv::Mat &image);

/**
 * @brief detects buildings on sattelite image using edges and vertices
 *        (use edgeDetector for two results network) and semantic segmentation
 * @param image -- sattelite image to detect buildings on
 * @return container with detected polygons
 */
std::vector<Polygon>
detectBldByVertsEdges(const tf_inferencer::TensorFlowInferencer& segmentator,
                      const tf_inferencer::TensorFlowInferencer& edgeDetector,
                      const cv::Mat &image);

/**
 * @brief detects buildings on sattelite image using semantic segmentation and
 *        polygon regularization on rectangular grid
 *        (https://arxiv.org/pdf/1504.06584.pdf)
 * @param image -- sattelite image to detect buildings on
 * @return container with detected polygons
 */
std::vector<Polygon>
detectComplexBldByGrid(const tf_inferencer::TensorFlowInferencer& segmentator,
                       const cv::Mat &image);

/**
 * @brief detects buildings on sattelite image using semantic segmentation and
 *        polygon regularization method with projection.
 * @param image -- sattelite image to detect buildings on
 * @return container with detected polygons
 */
std::vector<Polygon>
detectComplexBldByProjection(const tf_inferencer::TensorFlowInferencer& segmentator,
                             const cv::Mat &image);

/**
 * @brief detects buildings on sattelite image using instance segmentation and
 *        polygon regularization on rectangular grid.
 * @param image -- sattelite image to detect buildings on
 * @return container with detected polygons
 */
std::vector<Polygon>
detectComplexBldByMaskRCNN(const tf_inferencer::MaskRCNNInferencer& maskrcnn,
                           const cv::Mat &image,
                           size_t batchSize = 1);


} //namespace autocart
} //namespace wiki
} //namespace maps
