/*
This file is part of the Dandere2x project.
Dandere2x 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
(at your option) any later version.
Dandere2x 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 Foobar. If not, see .
*/
/*
========= Copyright aka_katto 2018, All rights reserved. ============
Original Author: aka_katto
Date: 4/11/20
Purpose:
===================================================================== */
#include "DiamondSearch.h"
#include
//-----------------------------------------------------------------------------
// Purpose: An iterative implementation of diamond search, plus or minus some
// custom heuristics I've added myself.
//-----------------------------------------------------------------------------
Block DiamondSearch::match_block(int x, int y) {
// These variables stay the same
int x_bounds = 5; // desired_image.get_width();
int y_bounds = 5; // desired_image.get_height();
int x_origin = x;
int y_origin = y;
// These variables change per each iteration
int initial_x = x;
int initial_y = y;
// Recycled variables that are cleared after each iteration
std::vector blocks = std::vector();
Block::Point point_array[CHECKS_PER_STEP];
// Main loop .Note that if it hits the end of the for loop, we've gone over our max_checks, and this
// are cutting the search short in order to keep the searching time having a constant worse-case search.
// In other words, we're artificially capping the upper bounds.
for (int x = 0; x < max_checks; x++) {
// Base Cases (if we were doing this recursively, these essentially would be the base cases)
{
// If we ran out of checks, return what we're at right now
if (x == max_checks - 1) {
// double sum = AbstractBlockMatch::mse_blocks(initial_x, initial_y, x_origin, y_origin);
// return Block(initial_x, initial_y, x_origin, y_origin, sum);
}
// If step size is 0, return where we are at right now, since we've reached the end of our search
if (step_size <= 0) {
// double sum = AbstractBlockMatch::mse_blocks(initial_x, initial_y, x_origin, y_origin);
// return Block(initial_x, initial_y, x_origin, y_origin, sum);
}
}
// Reset variables unique for each iteration
blocks.clear();
bool flag_array[16] = {true};
{
point_array[0].x = x_origin + step_size;
point_array[0].y = y_origin;
point_array[1].x = x_origin + step_size / 2;
point_array[1].y = y_origin + step_size / 2;
point_array[2].x = x_origin;
point_array[2].y = y_origin + step_size;
point_array[3].x = x_origin - step_size / 2;
point_array[3].y = y_origin + step_size / 2;
point_array[4].x = x_origin - step_size;
point_array[4].y = y_origin;
point_array[5].x = x_origin + step_size / 2;
point_array[5].y = y_origin - step_size / 2;
point_array[6].x = x_origin + step_size;
point_array[6].y = y_origin;
point_array[7].x = x_origin;
point_array[7].y = y_origin;
point_array[8].x = x_origin + step_size * 2;
point_array[8].y = y_origin;
point_array[9].x = x_origin + step_size;
point_array[9].y = y_origin + step_size;
point_array[10].x = x_origin;
point_array[10].y = y_origin + step_size * 2;
point_array[11].x = x_origin - step_size;
point_array[11].y = y_origin + step_size;
point_array[12].x = x_origin - step_size * 2;
point_array[12].y = y_origin;
point_array[13].x = x_origin + step_size;
point_array[13].y = y_origin - step_size;
point_array[14].x = x_origin + step_size * 2;
point_array[14].y = y_origin;
point_array[15].x = x_origin - step_size;
point_array[15].y = y_origin - step_size;
}
// Create an array that is used to signal if a point is "valid" or not, i.e if it is legal to probe.
bool any_legal_points = flag_invalid_points(x_bounds, y_bounds, point_array, CHECKS_PER_STEP, 30,
flag_array);
// Cycle through each search point (if it's legal that is) and add it to the block vector.
for (int j = 0; j < CHECKS_PER_STEP; j++) {
if (!flag_array[j]) { // checks if point is legal
// double sum = AbstractBlockMatch::mse_blocks(initial_x, initial_y, point_array[j].x, point_array[j].y);
//
// Block block = Block(initial_x, initial_y, point_array[j].x, point_array[j].y, sum);
// blocks.push_back(block);
}
}
// Get the most promising block from the list (i.e the block with the smallest 'sum')
std::vector::iterator smallest_block = min_element(blocks.begin(), blocks.end());
// Custom-Implemented Heuristics #todo
{
// /** If the smallest block we found meets the MSE requirements, stop here*/
// if (smallest_block->sum <= min_mse) {
// return *smallest_block;
// }
//
//
// /** Testing feature - if the smallest block is garishly larger than the minimum required,
// stop looking. */
// if (smallest_block->sum >= min_mse * min_mse) {
// return Block(0, 0, 0, 0, 10000);
// }
}
// Assignments for next iteration
if ((smallest_block->x_end == x_origin) && smallest_block->y_end == y_origin) {
x_origin = smallest_block->x_end;
y_origin = smallest_block->y_end;
step_size /= 2;
continue;
} else {
x_origin = smallest_block->x_end;
y_origin = smallest_block->y_end;
}
}
return Block();
}
void DiamondSearch::set_max_checks(int max_checks) {
this->max_checks = max_checks;
}
void DiamondSearch::set_step_size(int step_size) {
this->step_size = step_size;
}
//-----------------------------------------------------------------------------
// Purpose: Neatly construct all the points diamond search for probe.
//-----------------------------------------------------------------------------
Block::Point *DiamondSearch::get_diamond_search_points(int x_origin, int y_origin, int step_size) {
//create the points to be used in diamond searching
Block::Point point_array[CHECKS_PER_STEP];
//construct the list of "diamond" points to be checked if legal or not
point_array[0].x = x_origin + step_size;
point_array[0].y = y_origin;
point_array[1].x = x_origin + step_size / 2;
point_array[1].y = y_origin + step_size / 2;
point_array[2].x = x_origin;
point_array[2].y = y_origin + step_size;
point_array[3].x = x_origin - step_size / 2;
point_array[3].y = y_origin + step_size / 2;
point_array[4].x = x_origin - step_size;
point_array[4].y = y_origin;
point_array[5].x = x_origin + step_size / 2;
point_array[5].y = y_origin - step_size / 2;
point_array[6].x = x_origin + step_size;
point_array[6].y = y_origin;
point_array[7].x = x_origin;
point_array[7].y = y_origin;
point_array[8].x = x_origin + step_size * 2;
point_array[8].y = y_origin;
point_array[9].x = x_origin + step_size;
point_array[9].y = y_origin + step_size;
point_array[10].x = x_origin;
point_array[10].y = y_origin + step_size * 2;
point_array[11].x = x_origin - step_size;
point_array[11].y = y_origin + step_size;
point_array[12].x = x_origin - step_size * 2;
point_array[12].y = y_origin;
point_array[13].x = x_origin + step_size;
point_array[13].y = y_origin - step_size;
point_array[14].x = x_origin + step_size * 2;
point_array[14].y = y_origin;
point_array[15].x = x_origin - step_size;
point_array[15].y = y_origin - step_size;
return point_array;
}
bool DiamondSearch::flag_invalid_points(int x_bounds, int y_bounds, Block::Point *points, int size, int block_size,
bool *flagged) {
int count = 0;
for (int i = 0; i < size; i++) {
if ((points[i].x + block_size > x_bounds) || (points[i].x < 0) ||
(points[i].y + block_size > y_bounds) || (points[i].y < 0)) {
flagged[i] = true;
count++;
}
}
return count != size;
}