【合并棋盘格】

TEST2

/**
* Copyright 2018, ftdlyc <yclu.cn@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/

/*
% Copyright 2012. All rights reserved.
% Author: Andreas Geiger
%         Institute of Measurement and Control Systems (MRT)
%         Karlsruhe Institute of Technology (KIT), Germany

% This is free software; you can redistribute it and/or modify it under the
% terms of the GNU General Public License as published by the Free Software
% Foundation; either version 3 of the License, or any later version.

% This software is distributed in the hope that it will be useful, but WITHOUT ANY
% WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
% PARTICULAR PURPOSE. See the GNU General Public License for more details.

% You should have received a copy of the GNU General Public License along with
% this software; if not, write to the Free Software Foundation, Inc., 51 Franklin
% Street, Fifth Floor, Boston, MA 02110-1301, USA
*/

#include <algorithm>
#include <chrono>
#include <iostream>
#include <random>
#include <vector>

#include <opencv2/opencv.hpp>

#include "libcbdetect/board_energy.h"
#include "libcbdetect/boards_from_corners.h"
#include "libcbdetect/config.h"
#include "libcbdetect/filter_board.h"
#include "libcbdetect/grow_board.h"
#include "libcbdetect/init_board.h"

namespace cbdetect {

/*该函数的作用是在图像上显示角点和提议的位置,并在图像上显示方向。
具体实现过程是先将灰度图像转换为BGR图像,然后在图像上绘制角点和提议的位置,最后在图像上显示方向。*/
void debug_grow_process(const cv::Mat& img, const Corner& corners, const Board& board,
                        const std::vector<cv::Point2i>& proposal, int direction, bool type) {
  cv::Mat img_show;
  if(img.channels() != 3) {
#if CV_VERSION_MAJOR >= 4
    cv::cvtColor(img, img_show, cv::COLOR_GRAY2BGR);
#else
    cv::cvtColor(img, img_show, CV_GRAY2BGR);
#endif
  } else {
    img_show = img.clone();
  }

  cv::Point2d mean(0.0, 0.0);
  for(int i = 0; i < board.idx.size(); ++i) {
    for(int j = 0; j < board.idx[i].size(); ++j) {
      if(board.idx[i][j] < 0) {
        continue;
      }
      cv::circle(img_show, corners.p[board.idx[i][j]], 4, cv::Scalar(255, 0, 0), -1);//蓝色
      cv::putText(img_show, std::to_string(board.idx[i][j]),
                  cv::Point2i(corners.p[board.idx[i][j]].x - 12, corners.p[board.idx[i][j]].y - 6),
                  cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 255), 1);
      mean += corners.p[board.idx[i][j]];
    }
  }
  mean /= (double)(board.num);
  mean.x -= 10;
  mean.y += 10;
  cv::putText(img_show, std::to_string(direction), mean,
              cv::FONT_HERSHEY_SIMPLEX, 1.3, cv::Scalar(196, 196, 0), 2);

  for(const auto& i : proposal) {
    if(board.idx[i.y][i.x] < 0) {
      continue;
    }
    if(type) {
      cv::circle(img_show, corners.p[board.idx[i.y][i.x]], 4, cv::Scalar(0, 255, 0), -1);//绿色
    } else {
      cv::circle(img_show, corners.p[board.idx[i.y][i.x]], 4, cv::Scalar(0, 0, 255), -1);//红色
    }
  }

  cv::imshow("grow_process", img_show);
  cv::waitKey();
}


/*
1.在棋盘扩展的过程中,记录每个棋盘格的边界,即记录每个棋盘格的最小和最大行列坐标。

2.在新生成的棋盘格与已有的棋盘格进行比较时,判断它们的边界是否相邻,如果相邻,则将它们合并成为一个新的棋盘格。

3.合并棋盘格时,需要将它们的角点和标记向量合并,并更新新的棋盘格的边界。

4.最后,将新的棋盘格加入棋盘格向量中。
*/
void boards_from_corners(const cv::Mat& img, const Corner& corners, std::vector<Board>& boards, const Params& params) {
  // intialize boards
  boards.clear();
  Board board;
  std::vector<int> used(corners.p.size(), 0);

  int start = 0;
  if(!params.overlay) 
  {
    std::default_random_engine e;
    auto time = std::chrono::system_clock::now().time_since_epoch();
    e.seed(static_cast<unsigned long>(time.count()));
    start = e() % corners.p.size();
  }

  int n = 0;
  while(n++ < corners.p.size()) 
  {
    int i = (n + start) % corners.p.size();
    if(used[i] == 1 || !init_board(corners, used, board, i)) 
    {
      continue;
    }

    cv::Point3i maxE_pos = board_energy(corners, board, params);
    double energy        = board.energy[maxE_pos.y][maxE_pos.x][maxE_pos.z];
    if(energy > -6.0) 
    {
      for(int jj = 0; jj < 3; ++jj) 
      {
        for(int ii = 0; ii < 3; ++ii) 
        {
          used[board.idx[jj][ii]] = 0;
        }
      }
      continue;
    }

    while(1) 
    {
      int num_corners = board.num;

      for(int j = 0; j < (params.corner_type == MonkeySaddlePoint ? 6 : 4); ++j) 
      {
        std::vector<cv::Point2i> proposal;
        GrowType grow_type = grow_board(corners, used, board, proposal, j, params);
        if(grow_type == GrowType_Failure) 
        {
          continue;
        }

        if(params.show_grow_processing) 
        {
          for(int ii = 0; ii < board.idx.size(); ++ii) 
          {
            for(int jj = 0; jj < board.idx[ii].size(); ++jj) 
            {
              std::cout << board.idx[ii][jj] << " ";
            }
            std::cout << "\n";
          }
          std::cout << "\n";
          debug_grow_process(img, corners, board, proposal, j, false);
        }

        filter_board(corners, used, board, proposal, energy, params);

        if(params.show_grow_processing) {
          for(int ii = 0; ii < board.idx.size(); ++ii) 
          {
            for(int jj = 0; jj < board.idx[ii].size(); ++jj) 
            {
              std::cout << board.idx[ii][jj] << " ";
            }
            std::cout << "\n";
          }
          std::cout << "\n";
          debug_grow_process(img, corners, board, proposal, j, true);
        }

        if(grow_type == GrowType_Inside) {
          --j;
        }
      }

      if(board.num == num_corners) {
        break;
      }
    }

    // check if new chessboard proposal overlaps with existing chessboards
    bool merged = false;
    for(int j = 0; j < boards.size(); ++j) 
    {
      // check if new chessboard proposal overlaps with existing chessboards
      bool overlap = false;
      for(int k1 = 0; k1 < board.idx.size(); ++k1) 
      {
        for(int k2 = 0; k2 < board.idx[0].size(); ++k2) 
        {
          for(int l1 = 0; l1 < boards[j].idx.size(); ++l1) 
          {
            for(int l2 = 0; l2 < boards[j].idx[0].size(); ++l2) 
            {
              if(board.idx[k1][k2] != -1 && board.idx[k1][k2] != -2 && board.idx[k1][k2] == boards[j].idx[l1][l2]) 
              {
                overlap = true;
                goto GOTO_BREAK;
              }
            }
          }
        }
      }
    GOTO_BREAK:;

      if(overlap) 
      {
        // check if the two boards are adjacent
        bool adjacent = false;
        for(int k1 = 0; k1 < board.idx.size(); ++k1) 
        {
          for(int k2 = 0; k2 < board.idx[0].size(); ++k2) 
          {
            if(board.idx[k1][k2] != -1 && board.idx[k1][k2] != -2) 
            {
              for(int l1 = 0; l1 < boards[j].idx.size(); ++l1) 
              {
                for(int l2 = 0; l2 < boards[j].idx[0].size(); ++l2) 
                {
                  if(boards[j].idx[l1][l2] != -1 && boards[j].idx[l1][l2] != -2) 
                  {
                    if(abs(board.idx[k1][k2] - boards[j].idx[l1][l2]) == 1 || abs(board.idx[k1][k2] - boards[j].idx[l1][l2]) == params.board_w) 
                    {
                      adjacent = true;
                      goto GOTO_BREAK2;
                    }
                  }
                }
              }
            }
          }
        }
      GOTO_BREAK2:;

        if(adjacent) 
        {
          // merge the two boards
          Board new_board;
          std::vector<int> new_used(corners.p.size(), 0);
          for(int k1 = 0; k1 < board.idx.size(); ++k1) 
          {
            for(int k2 = 0; k2 < board.idx[0].size(); ++k2) 
            {
              if(board.idx[k1][k2] != -1 && board.idx[k1][k2] != -2) 
              {
                new_board.idx[k1][k2] = board.idx[k1][k2];
                new_board.energy[k1][k2] = board.energy[k1][k2];
                new_used[board.idx[k1][k2]] = 1;
              }
            }
          }
          for(int k1 = 0; k1 < boards[j].idx.size(); ++k1) 
          {
            for(int k2 = 0; k2 < boards[j].idx[0].size(); ++k2) 
            {
              if(boards[j].idx[k1][k2] != -1 && boards[j].idx[k1][k2] != -2) 
              {
                new_board.idx[k1 + board.idx.size() - 1][k2] = boards[j].idx[k1][k2];
                new_board.energy[k1 + board.idx.size() - 1][k2] = boards[j].energy[k1][k2];
                new_used[boards[j].idx[k1][k2]] = 1;
              }
            }
          }
          new_board.num = board.num + boards[j].num - 2;
          new_board.min_row = std::min(board.min_row, boards[j].min_row);
          new_board.max_row = std::max(board.max_row, boards[j].max_row);
          new_board.min_col = std::min(board.min_col, boards[j].min_col);
          new_board.max_col = std::max(board.max_col, boards[j].max_col);
          board = new_board;
          used = new_used;
          merged = true;
          break;
        }
      }
    }

    if(!merged) 
    {
      boards.emplace_back(board);
    }

    std::fill(used.begin(), used.end(), 0);
    n += 2;
  }
}

TEST3

void boards_from_corners(const cv::Mat& img, const Corner& corners, std::vector<Board>& boards, const Params& params) {
  // intialize boards
  boards.clear();
  Board board;
  std::vector<int> used(corners.p.size(), 0);

  int start = 0;
  if(!params.overlay) 
  {
    std::default_random_engine e;
    auto time = std::chrono::system_clock::now().time_since_epoch();
    e.seed(static_cast<unsigned long>(time.count()));
    start = e() % corners.p.size();
  }

  int n = 0;
  while(n++ < corners.p.size()) 
  {
    int i = (n + start) % corners.p.size();
    if(used[i] == 1 || !init_board(corners, used, board, i)) 
    {
      continue;
    }

    cv::Point3i maxE_pos = board_energy(corners, board, params);
    double energy        = board.energy[maxE_pos.y][maxE_pos.x][maxE_pos.z];
    if(energy > -6.0) 
    {
      for(int jj = 0; jj < 3; ++jj) 
      {
        for(int ii = 0; ii < 3; ++ii) 
        {
          used[board.idx[jj][ii]] = 0;
        }
      }
      continue;
    }

    while(1) 
    {
      int num_corners = board.num;

      for(int j = 0; j < (params.corner_type == MonkeySaddlePoint ? 6 : 4); ++j) 
      {
        std::vector<cv::Point2i> proposal;
        GrowType grow_type = grow_board(corners, used, board, proposal, j, params);
        if(grow_type == GrowType_Failure) 
        {
          continue;
        }

        if(params.show_grow_processing) 
        {
          for(int ii = 0; ii < board.idx.size(); ++ii) 
          {
            for(int jj = 0; jj < board.idx[ii].size(); ++jj) 
            {
              std::cout << board.idx[ii][jj] << " ";
            }
            std::cout << "\n";
          }
          std::cout << "\n";
          debug_grow_process(img, corners, board, proposal, j, false);
        }

        filter_board(corners, used, board, proposal, energy, params);

        if(params.show_grow_processing) {
          for(int ii = 0; ii < board.idx.size(); ++ii) 
          {
            for(int jj = 0; jj < board.idx[ii].size(); ++jj) 
            {
              std::cout << board.idx[ii][jj] << " ";
            }
            std::cout << "\n";
          }
          std::cout << "\n";
          debug_grow_process(img, corners, board, proposal, j, true);
        }

        if(grow_type == GrowType_Inside) {
          --j;
        }
      }

      if(board.num == num_corners) {
        break;
      }
    }

    // check if new chessboard proposal overlaps with existing chessboards
    std::vector<int> overlap_idx;
    for(int j = 0; j < boards.size(); ++j) 
    {
      bool is_overlap = false;
      for(int k1 = 0; k1 < board.idx.size(); ++k1) 
      {
        for(int k2 = 0; k2 < board.idx[0].size(); ++k2) 
        {
          for(int l1 = 0; l1 < boards[j].idx.size(); ++l1) 
          {
            for(int l2 = 0; l2 < boards[j].idx[0].size(); ++l2) 
            {
              if(board.idx[k1][k2] != -1 && board.idx[k1][k2] != -2 && board.idx[k1][k2] == boards[j].idx[l1][l2]) 
              {
                is_overlap = true;
                overlap_idx.push_back(j);
                break;
              }
            }
            if(is_overlap) {
              break;
            }
          }
          if(is_overlap) {
            break;
          }
        }
        if(is_overlap) {
          break;
        }
      }
    }

    // merge overlapping chessboards
    if(!overlap_idx.empty()) 
    {
      Board merged_board;
      std::vector<int> merged_used(corners.p.size(), 0);
      for(int j = 0; j < overlap_idx.size(); ++j) 
      {
        for(int k1 = 0; k1 < boards[overlap_idx[j]].idx.size(); ++k1) 
        {
          for(int k2 = 0; k2 < boards[overlap_idx[j]].idx[0].size(); ++k2) 
          {
            if(boards[overlap_idx[j]].idx[k1][k2] != -1 && boards[overlap_idx[j]].idx[k1][k2] != -2) 
            {
              merged_board.idx[k1][k2] = boards[overlap_idx[j]].idx[k1][k2];
              merged_used[boards[overlap_idx[j]].idx[k1][k2]] = 1;
              merged_board.num++;
            }
          }
        }
        boards.erase(boards.begin() + overlap_idx[j]);
        for(int k = j + 1; k < overlap_idx.size(); ++k) 
        {
          if(overlap_idx[k] > overlap_idx[j]) 
          {
            overlap_idx[k]--;
          }
        }
      }
      for(int j = 0; j < board.idx.size(); ++j) 
      {
        for(int k = 0; k < board.idx[0].size(); ++k) 
        {
          if(board.idx[j][k] != -1 && board.idx[j][k] != -2 && !merged_used[board.idx[j][k]]) 
          {
            merged_board.idx[j][k] = board.idx[j][k];
            merged_board.num++;
          }
        }
      }
      boards.push_back(merged_board);
    } 
    else 
    {
      boards.push_back(board);
    }
    std::fill(used.begin(), used.end(), 0);
    n += 2;
  }
}

TEST4

/**
* Copyright 2018, ftdlyc <yclu.cn@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/

/*
% Copyright 2012. All rights reserved.
% Author: Andreas Geiger
%         Institute of Measurement and Control Systems (MRT)
%         Karlsruhe Institute of Technology (KIT), Germany

% This is free software; you can redistribute it and/or modify it under the
% terms of the GNU General Public License as published by the Free Software
% Foundation; either version 3 of the License, or any later version.

% This software is distributed in the hope that it will be useful, but WITHOUT ANY
% WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
% PARTICULAR PURPOSE. See the GNU General Public License for more details.

% You should have received a copy of the GNU General Public License along with
% this software; if not, write to the Free Software Foundation, Inc., 51 Franklin
% Street, Fifth Floor, Boston, MA 02110-1301, USA
*/

#include <algorithm>
#include <chrono>
#include <iostream>
#include <random>
#include <vector>

#include <opencv2/opencv.hpp>

#include "libcbdetect/board_energy.h"
#include "libcbdetect/boards_from_corners.h"
#include "libcbdetect/config.h"
#include "libcbdetect/filter_board.h"
#include "libcbdetect/grow_board.h"
#include "libcbdetect/init_board.h"

namespace cbdetect {

/*该函数的作用是在图像上显示角点和提议的位置,并在图像上显示方向。
具体实现过程是先将灰度图像转换为BGR图像,然后在图像上绘制角点和提议的位置,最后在图像上显示方向。*/
void debug_grow_process(const cv::Mat& img, const Corner& corners, const Board& board,
                        const std::vector<cv::Point2i>& proposal, int direction, bool type) {
  cv::Mat img_show;
  if(img.channels() != 3) {
#if CV_VERSION_MAJOR >= 4
    cv::cvtColor(img, img_show, cv::COLOR_GRAY2BGR);
#else
    cv::cvtColor(img, img_show, CV_GRAY2BGR);
#endif
  } else {
    img_show = img.clone();
  }

  cv::Point2d mean(0.0, 0.0);
  for(int i = 0; i < board.idx.size(); ++i) {
    for(int j = 0; j < board.idx[i].size(); ++j) {
      if(board.idx[i][j] < 0) {
        continue;
      }
      cv::circle(img_show, corners.p[board.idx[i][j]], 4, cv::Scalar(255, 0, 0), -1);//蓝色
      cv::putText(img_show, std::to_string(board.idx[i][j]),
                  cv::Point2i(corners.p[board.idx[i][j]].x - 12, corners.p[board.idx[i][j]].y - 6),
                  cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 255), 1);
      mean += corners.p[board.idx[i][j]];
    }
  }
  mean /= (double)(board.num);
  mean.x -= 10;
  mean.y += 10;
  cv::putText(img_show, std::to_string(direction), mean,
              cv::FONT_HERSHEY_SIMPLEX, 1.3, cv::Scalar(196, 196, 0), 2);

  for(const auto& i : proposal) {
    if(board.idx[i.y][i.x] < 0) {
      continue;
    }
    if(type) {
      cv::circle(img_show, corners.p[board.idx[i.y][i.x]], 4, cv::Scalar(0, 255, 0), -1);//绿色
    } else {
      cv::circle(img_show, corners.p[board.idx[i.y][i.x]], 4, cv::Scalar(0, 0, 255), -1);//红色
    }
  }

  cv::imshow("grow_process", img_show);
  cv::waitKey();
}

double distance(const cv::Point2f& p1, const cv::Point2f& p2) {
  return std::sqrt(std::pow(p1.x - p2.x, 2) + std::pow(p1.y - p2.y, 2));
}


/*三、从给定的角点中提取棋盘
参数:
角点Corners是一个结构体,包含了角点的坐标信息
棋盘格向量boards是一个存储棋盘格的向量
参数params是一个结构体,包含了一些参数信息
*/
void boards_from_corners(const cv::Mat& img, const Corner& corners, std::vector<Board>& boards, const Params& params) {
  // intialize boards
  //1.清空棋盘格向量boards,初始化一个棋盘格和一个标记向量,用于记录角点是否被使用过
  boards.clear();
  Board board;
  std::vector<int> used(corners.p.size(), 0);

  //2.从一个随机的角点开始
  int start = 0;
  if(!params.overlay) 
  {
    // start from random index
    std::default_random_engine e;
    auto time = std::chrono::system_clock::now().time_since_epoch();
    e.seed(static_cast<unsigned long>(time.count()));
    start = e() % corners.p.size();
  }

  // for all seed corners do
  //3.初始化一个3*3的棋盘格
  int n = 0;
  while(n++ < corners.p.size()) 
  {
    // init 3x3 board from seed i
    int i = (n + start) % corners.p.size();
    if(used[i] == 1 || !init_board(corners, used, board, i)) 
    {
      continue;
    }

    // check if this is a useful initial guess
    //4.检查这个棋盘格是否是一个有用的初始猜测
    //如果是,函数会尝试扩展这个棋盘格,直到无法再扩展为止,如果扩展成功,则将这个棋盘格加入棋盘格向量boards中
    //board_energy函数返回一个三维坐标,表示具有最大结构能量的位置
    cv::Point3i maxE_pos = board_energy(corners, board, params);
    double energy        = board.energy[maxE_pos.y][maxE_pos.x][maxE_pos.z];
    if(energy > -6.0) 
    {
      for(int jj = 0; jj < 3; ++jj) 
      {
        for(int ii = 0; ii < 3; ++ii) 
        {
          used[board.idx[jj][ii]] = 0;
        }
      }
      continue;
    }

    // grow boards
    while(1) 
    {
      int num_corners = board.num;

      for(int j = 0; j < (params.corner_type == MonkeySaddlePoint ? 6 : 4); ++j) 
      {
        std::vector<cv::Point2i> proposal;
        //调用grow_board函数扩展棋盘格
        /*函数的输入参数包括棋盘的四个角点、已使用的角点、棋盘、建议的角点、生长方向和一些参数。
        函数的输出是一个枚举类型,表示生长的类型,包括内部角点、边界角点和失败。*/
        GrowType grow_type = grow_board(corners, used, board, proposal, j, params);
        if(grow_type == GrowType_Failure) 
        {
          continue;
        }

        if(params.show_grow_processing) 
        {
          for(int ii = 0; ii < board.idx.size(); ++ii) 
          {
            for(int jj = 0; jj < board.idx[ii].size(); ++jj) 
            {
              std::cout << board.idx[ii][jj] << " ";
            }
            std::cout << "\n";
          }
          std::cout << "\n";
          //调用debug_grow_process函数显示扩展过程的中间结果
          debug_grow_process(img, corners, board, proposal, j, false);//打印的是蓝色
        }

        //调用filter_board函数过滤掉一些不合适的棋盘格方案
        filter_board(corners, used, board, proposal, energy, params);

        if(params.show_grow_processing) {
          for(int ii = 0; ii < board.idx.size(); ++ii) 
          {
            for(int jj = 0; jj < board.idx[ii].size(); ++jj) 
            {
              std::cout << board.idx[ii][jj] << " ";
            }
            std::cout << "\n";
          }
          std::cout << "\n";
          //调用debug_grow_process函数显示扩展过程的中间结果
          debug_grow_process(img, corners, board, proposal, j, true);//打印的是绿色
        }

        if(grow_type == GrowType_Inside) {
          --j;
        }
      }

      // exit loop
      if(board.num == num_corners) {
        break;
      }
    }

    //如果参数params中的overlay为真,则函数会检查新生成的棋盘格是否与已有的棋盘格重叠
    if(!params.overlay) {
      boards.emplace_back(board);
      continue;
    }

    std::vector<std::pair<int, double>> overlap;
    for(int j = 0; j < boards.size(); ++j) 
    {
      // check if new chessboard proposal overlaps with existing chessboards
      //检查新棋盘方案是否与现有棋盘重叠
      for(int k1 = 0; k1 < board.idx.size(); ++k1) 
      {
        for(int k2 = 0; k2 < board.idx[0].size(); ++k2) 
        {
          for(int l1 = 0; l1 < boards[j].idx.size(); ++l1) 
          {
            for(int l2 = 0; l2 < boards[j].idx[0].size(); ++l2) 
            {
              if(board.idx[k1][k2] != -1 && board.idx[k1][k2] != -2 && board.idx[k1][k2] == boards[j].idx[l1][l2]) 
              {
                cv::Point3i maxE_pos_tmp = board_energy(corners, boards[j], params);
                overlap.emplace_back(std::make_pair(j, boards[j].energy[maxE_pos_tmp.y][maxE_pos_tmp.x][maxE_pos_tmp.z]));
                goto GOTO_BREAK;
              }
            }
          }
        }
      }
    }
  GOTO_BREAK:;

    //判断是否有重叠,如果没有重叠,则将新棋盘格加入棋盘格向量中
    if(overlap.empty()) 
    {
      boards.emplace_back(board);
    } 
    else 
    {
      //如果有重叠,则比较新棋盘格与已有棋盘格的能量值
      //如果新棋盘格的能量值更低,则将新棋盘格加入棋盘格向量boards中,并将原有的棋盘格从棋盘格向量中删除
      bool is_better = true;
      for(int j = 0; j < overlap.size(); ++j) 
      {
        if(overlap[j].second <= energy) 
        {
          is_better = false;
          break;
        }
      }
      if(is_better) 
      {
        std::vector<Board> tmp;
        for(int j = 0, k = 0; j < boards.size(); ++j) 
        {
          if(overlap[k].first == j) {
            continue;
            ++k;
          }
          tmp.emplace_back(boards[j]);
        }
        std::swap(tmp, boards);
        boards.emplace_back(board);
      }
    }
    std::fill(used.begin(), used.end(), 0);
    n += 2;
  }

  for(int i = 0; i < boards.size(); ++i) {
  for(int j = i + 1; j < boards.size(); ++j) {
    // check if two boards have adjacent corners
    bool has_adjacent_corners = false;
    for(int k1 = 0; k1 < boards[i].idx.size(); ++k1) {
      for(int k2 = 0; k2 < boards[i].idx[0].size(); ++k2) {
        if(boards[i].idx[k1][k2] != -1 && boards[i].idx[k1][k2] != -2) {
          for(int l1 = 0; l1 < boards[j].idx.size(); ++l1) {
            for(int l2 = 0; l2 < boards[j].idx[0].size(); ++l2) {
              if(boards[j].idx[l1][l2] != -1 && boards[j].idx[l1][l2] != -2) {
                double d = distance(corners.p[boards[i].idx[k1][k2]], corners.p[boards[j].idx[l1][l2]]);
                if(d <= max_distance) {
                  has_adjacent_corners = true;
                  goto GOTO_BREAK2;
                }
              }
            }
          }
        }
      }
    }
  GOTO_BREAK2:;
    // merge two boards if they have adjacent corners
    if(has_adjacent_corners) {
      Board merged_board;
      // copy corners from the first board
      for(int k1 = 0; k1 < boards[i].idx.size(); ++k1) {
        for(int k2 = 0; k2 < boards[i].idx[0].size(); ++k2) {
          if(boards[i].idx[k1][k2] != -1 && boards[i].idx[k1][k2] != -2) {
            merged_board.idx[k1][k2] = boards[i].idx[k1][k2];
            merged_board.num++;
          }
        }
      }
      // copy corners from the second board
      for(int l1 = 0; l1 < boards[j].idx.size(); ++l1) {
        for(int l2 = 0; l2 < boards[j].idx[0].size(); ++l2) {
          if(boards[j].idx[l1][l2] != -1 && boards[j].idx[l1][l2] != -2) {
            bool is_duplicate = false;
            for(int k1 = 0; k1 < boards[i].idx.size(); ++k1) {
              for(int k2 = 0; k2 < boards[i].idx[0].size(); ++k2) {
                if(boards[i].idx[k1][k2] == boards[j].idx[l1][l2]) {
                  is_duplicate = true;
                  goto GOTO_CONTINUE;
                }
              }
            }
          GOTO_CONTINUE:;
            if(!is_duplicate) {
              merged_board.idx[l1][l2] = boards[j].idx[l1][l2];
              merged_board.num++;
            }
          }
        }
      }
      // remove the two original boards and add the merged board
      //移除两个原始板并添加合并后的板
      std::vector<Board> tmp;
      for(int k = 0; k < boards.size(); ++k) {
        if(k != i && k != j) {
          tmp.emplace_back(boards[k]);
        }
      }
      tmp.emplace_back(merged_board);
      std::swap(tmp, boards);
      // start over
      i = -1;
      break;
    }
  }
}
}

} 

// namespace cbdetect


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值