int WangTilesProcessor::SanitizeSmall(const TilePack & tiles, const Array3D<Pixel> & input, Array3D<Pixel> & output) { if((tiles.size() <= 0) || (input.Size(0)%tiles.size()) || (input.Size(1)%tiles[0].size())) { // small image, just make it a constant average of input output = input; for(int cha = 0; cha < input.Size(2); cha++) { Pixel sum = 0; { for(int row = 0; row < input.Size(0); row++) for(int col = 0; col < input.Size(1); col++) { sum += input[row][col][cha]; } sum /= (input.Size(0)*input.Size(1)); } { for(int row = 0; row < output.Size(0); row++) for(int col = 0; col < output.Size(1); col++) { output[row][col][cha] = sum; } } } return 1; } else { return 0; } }
int WangTilesProcessor::TileMismatch(const TilePack & tiles, const Array3D<Pixel> & input) { int mismatch = 0; // count the number of edge colors int e_colors[4] = {0, 0, 0, 0}; if(!CountEdgeColors(tiles, e_colors[0], e_colors[1], e_colors[2], e_colors[3])) { return 0; } // compute tile size const int tile_height = (tiles.size() > 0) ? input.Size(0)/tiles.size() : 0; const int tile_width = (tiles.size() > 0 && tiles[0].size() > 0) ? input.Size(1)/tiles[0].size() : 0; const int tile_depth = input.Size(2); // make sure all edges with // (1) the same S/E/N/W orientations and // (2) same edge id // have identical images for(int e_index = 0; e_index < 4; e_index++) for(int e_color = 0; e_color < e_colors[e_index]; e_color++) { // find a tile with e_color in e_index int t_row = -1; int t_col = -1; { for(unsigned int i = 0; i < tiles.size(); i++) for(unsigned int j = 0; j < tiles[i].size(); j++) { const WangTiles::Tile & tile = tiles[i][j]; const int my_e_colors[4] = {tile.e0(), tile.e1(), tile.e2(), tile.e3()}; if(my_e_colors[e_index] == e_color) { // found the tile t_row = i; t_col = j; break; } } } if((t_row >= 0) && (t_col >= 0)) { const WangTiles::Tile & sample_tile = tiles[t_row][t_col]; const int row_offset1 = t_row*tile_height; const int col_offset1 = t_col*tile_width; for(unsigned int i = 0; i < tiles.size(); i++) for(unsigned int j = 0; j < tiles[i].size(); j++) { const WangTiles::Tile & tile = tiles[i][j]; const int my_e_colors[4] = {tile.e0(), tile.e1(), tile.e2(), tile.e3()}; if(my_e_colors[e_index] == e_color) { // try to see if they match const int row_offset2 = i*tile_height; const int col_offset2 = j*tile_width; int row_start, row_end, col_start, col_end; EdgeIndices(e_index, tile_height, tile_width, row_start, row_end, col_start, col_end); for(int row = row_start; row <= row_end; row++) for(int col = col_start; col <= col_end; col++) for(int cha = 0; cha < tile_depth; cha++) { if(input[row+row_offset1][col+col_offset1][cha] != input[row+row_offset2][col+col_offset2][cha]) { mismatch = 1; } } } } } } // done return mismatch; }
int WangTilesProcessor::SanitizeCorners(const TilePack & tiles, const Array3D<Pixel> & input, Array3D<Pixel> & output) { if(SanitizeSmall(tiles, input, output)) { return 1; } const int tile_height = input.Size(0)/tiles.size(); const int tile_width = input.Size(1)/tiles[0].size(); const int tile_depth = input.Size(2); // initialize // note that for each row we have all possible corner combinations MeanTile mean_corner_tile; { Array3D<Pixel> image(tile_height, tile_width, tile_depth); for(int row = 0; row < image.Size(0); row++) for(int col = 0; col < image.Size(1); col++) for(int cha = 0; cha < image.Size(2); cha++) { image[row][col][cha] = 0; } mean_corner_tile.image = image; mean_corner_tile.count = 0; } // compute mean/average tiles for corner // note that we need to consider all tiles to get correct results! { for(unsigned int i = 0; i < tiles.size(); i++) for(unsigned int j = 0; j < tiles[i].size(); j++) { const WangTiles::Tile & tile = tiles[i][j]; const int input_row_start = i*tile_height; const int input_col_start = j*tile_width; for(int row = 0; row < tile_height; row++) for(int col = 0; col < tile_width; col++) for(int cha = 0; cha < tile_depth; cha++) { mean_corner_tile.image[row][col][cha] += input[row+input_row_start][col+input_col_start][cha]; } mean_corner_tile.count++; } } // normalization { if(mean_corner_tile.count > 0) { Array3D<Pixel> & image = mean_corner_tile.image; for(int row = 0; row < image.Size(0); row++) for(int col = 0; col < image.Size(1); col++) for(int cha = 0; cha < image.Size(2); cha++) { image[row][col][cha] /= mean_corner_tile.count; } mean_corner_tile.count = 1; } } // assign to the output { for(unsigned int i = 0; i < tiles.size(); i++) for(unsigned int j = 0; j < tiles[i].size(); j++) { const WangTiles::Tile & tile = tiles[i][j]; const int tile_edges[4] = {tile.e0(), tile.e1(), tile.e2(), tile.e3()}; const int output_row_start = i*tile_height; const int output_col_start = j*tile_width; for(int k = 0; k < 4; k++) { int row, col; CornerIndices(k, tile_height, tile_width, row, col); // only touch the corners for(int cha = 0; cha < tile_depth; cha++) { output[row+output_row_start][col+output_col_start][cha] = mean_corner_tile.image[row][col][cha]; } } } } // done return 1; }
int WangTilesProcessor::SanitizeEdges(const TilePack & tiles, const Array3D<Pixel> & input, Array3D<Pixel> & output) { // error checking if(SanitizeSmall(tiles, input, output)) { return 1; } const int tile_height = input.Size(0)/tiles.size(); const int tile_width = input.Size(1)/tiles[0].size(); const int tile_depth = input.Size(2); // count the number of edge colors int e_colors[4] = {0, 0, 0, 0}; { if(!CountEdgeColors(tiles, e_colors[0], e_colors[1], e_colors[2], e_colors[3])) { return 0; } // check consistency if((e_colors[0] != e_colors[2]) || (e_colors[1] != e_colors[3])) { return 0; } } // initialize vector< vector<MeanTile> > mean_tiles(4); { Array3D<Pixel> image(tile_height, tile_width, tile_depth); for(int row = 0; row < image.Size(0); row++) for(int col = 0; col < image.Size(1); col++) for(int cha = 0; cha < image.Size(2); cha++) { image[row][col][cha] = 0; } for(unsigned int i = 0; i < mean_tiles.size(); i++) { mean_tiles[i] = vector< MeanTile >(e_colors[i]); for(unsigned int j = 0; j < mean_tiles[i].size(); j++) { mean_tiles[i][j].image = image; mean_tiles[i][j].count = 0; } } } // compute mean/average tiles per edge color { for(unsigned int i = 0; i < tiles.size(); i++) for(unsigned int j = 0; j < tiles[i].size(); j++) { const WangTiles::Tile & tile = tiles[i][j]; const int input_row_start = i*tile_height; const int input_col_start = j*tile_width; const int tile_edges[4] = {tile.e0(), tile.e1(), tile.e2(), tile.e3()}; for(int k = 0; k < 4; k++) { MeanTile & output_tile = mean_tiles[k][tile_edges[k]]; for(int row = 0; row < tile_height; row++) for(int col = 0; col < tile_width; col++) for(int cha = 0; cha < tile_depth; cha++) { output_tile.image[row][col][cha] += input[row+input_row_start][col+input_col_start][cha]; } output_tile.count++; } } } { for(unsigned int i = 0; i < mean_tiles.size(); i++) for(unsigned int j = 0; j < mean_tiles[i].size(); j++) { MeanTile & tile = mean_tiles[i][j]; if(tile.count > 0) { Array3D<Pixel> & image = tile.image; for(int row = 0; row < image.Size(0); row++) for(int col = 0; col < image.Size(1); col++) for(int cha = 0; cha < image.Size(2); cha++) { image[row][col][cha] /= tile.count; } tile.count = 1; } } } // fix the output tile boundaries output = input; Array3D<Pixel> boundary(output); Array3D<Pixel> boundary_count(output); { // initialization for(int i = 0; i < boundary.Size(0); i++) for(int j = 0; j < boundary.Size(1); j++) for(int k = 0; k < boundary.Size(2); k++) { boundary[i][j][k] = 0; boundary_count[i][j][k] = 0; } } { // compute the correct tile boundary for(unsigned int i = 0; i < tiles.size(); i++) for(unsigned int j = 0; j < tiles[i].size(); j++) { const WangTiles::Tile & tile = tiles[i][j]; const int output_row_offset = i*tile_height; const int output_col_offset = j*tile_width; const int tile_edges[4] = {tile.e0(), tile.e1(), tile.e2(), tile.e3()}; for(int k = 0; k < 4; k++) { const Array3D<Pixel> & mean_tile = mean_tiles[k][tile_edges[k]].image; int row_start, row_end, col_start, col_end; EdgeIndices(k, tile_height, tile_width, row_start, row_end, col_start, col_end); for(int row = row_start; row <= row_end; row++) for(int col = col_start; col <= col_end; col++) for(int cha = 0; cha < tile_depth; cha++) { boundary[row+output_row_offset][col+output_col_offset][cha] += mean_tile[row][col][cha]; boundary_count[row+output_row_offset][col+output_col_offset][cha] += 1.0; } } } } { // normalization and assign to the output for(int i = 0; i < boundary.Size(0); i++) for(int j = 0; j < boundary.Size(1); j++) for(int k = 0; k < boundary.Size(2); k++) { if(boundary_count[i][j][k] > 0) { output[i][j][k] = boundary[i][j][k]/boundary_count[i][j][k]; } } } // done return 1; }