Finding the biggest square in a rectangle with a condition - algorithm

In a rectangle with given height and width. I'm supposed to find the square with most 1s and print the number of 1s on stdout, also in that same square there must not be more 2s than half of 1s, i.e:((# of 1s) /2) >= (# of 2s).
Square is always at least 2x2 big.
So for the input (first two numbers are height and width):
6 8
0 0 2 2 2 1 2 1
0 1 2 2 1 0 1 1
0 0 1 0 1 2 0 2
2 1 0 2 2 1 1 1
1 2 1 0 0 0 1 0
1 2 0 1 1 2 1 1
The correct answer is 9.(square is 5x5 big and the upperleft corner is on second row, third column)
Now i managed to somewhat write a program that does this correctly, but it's too slow.
So my I'm asking for an advice how to write the algorithm so that it solves this: https://justpaste.it/1cfem under 1 second(correct answer 15) and this: https://justpaste.it/1cfen under 4 seconds(correct answer 556).
EDIT: I forgot to mention by square I mean only the perimeter of the square (the four sides)
My code works something like this:
Iterate trough all the fields in the input and iterate trough all the possible squares that start in this field(starting from the biggest square possible). Then I have some conditions like that I break the iteration when the possible perimeter of the square is smaller than the already biggest number of 1s i have found so far in a perimete etc. Also when I'm trying to find the squares starting from the given field, I remember the up side and left side of the preceding square and then just decrement it(if there is a 1 or 2).
But this isn't enough, since solution like this solves the second input in like 1 and a half minute a I need it in four seconds.
The code:
NOTE: the minerals represent 1s and toxics represent 2s
#include <stdio.h>
#include <stdlib.h>
int maxMinerals;
void traverseforH(const int const *map, const int height, const int width) {
const int h1 = height - 1;
const int w1 = width - 1;
int lineOffset = 0;
for (int startY = 0; startY < h1; startY++) {
int yside = height - startY;
if (!(yside * 2 + (yside - 2)*2 > maxMinerals)) {
break;
}
for (int startX = 0; startX < w1; startX++) {
int xside = width - startX;
if (!(xside * 2 + (xside - 2)*2 > maxMinerals)) {
break;
}
int maxBoundl = width;
int maxBoundm = width;
if (startY + maxBoundm - height - startX > 0) {
maxBoundl = height;
maxBoundm = height;
if (startX - startY > 0) {
maxBoundl = maxBoundl + startY - startX;
} else {
maxBoundm = maxBoundm + startX - startY;
}
} else if (startY - startX > 0) {
maxBoundm = maxBoundm + startY - startX;
maxBoundl = maxBoundm;
maxBoundm = maxBoundm + startX - startY;
} else {
maxBoundl = maxBoundl + startY - startX;
}
int mBw = (maxBoundl - 1) * width;
int toxicsLeftSide = 0;
int mineralsLeftSide = 0;
int toxicsUpSide = 0;
int mineralsUpSide = 0;
int mw;
int lastMinerals = 0;
int toxics = 0;
int sidey = lineOffset + width;
for (int x = startX; x < maxBoundm; x++) {
mw = x + lineOffset;
if (map[mw] == 1) {
mineralsUpSide++;
lastMinerals++;
} else if (map[mw]) {
toxicsUpSide++;
toxics++;
}
mw = x + mBw;
if (map[mw] == 1) {
lastMinerals++;
} else if (map[mw]) {
toxics++;
}
}
for (int y = startY + 1; y < maxBoundl - 1; y++) {
mw = startX + sidey;
if (map[mw] == 1) {
mineralsLeftSide++;
lastMinerals++;
} else if (map[mw]) {
toxicsLeftSide++;
toxics++;
}
mw = maxBoundm - 1 + sidey;
if (map[mw] == 1) {
lastMinerals++;
} else if (map[mw]) {
toxics++;
}
sidey = sidey + width;
}
if (map[startX + mBw] == 1) {
mineralsLeftSide++;
} else if (map[startX + mBw]) {
toxicsLeftSide++;
}
int upsideData [2];
upsideData[0] = mineralsUpSide;
upsideData[1] = toxicsUpSide;
if (!(lastMinerals / 2.0 < toxics) && lastMinerals > maxMinerals) {
maxMinerals = lastMinerals;
}
mBw = mBw - width;
int noOfSquares;
if (xside < yside) {
noOfSquares = xside - 1;
} else {
noOfSquares = yside - 1;
}
for (int k = 1; k < noOfSquares; k++) {
int maxBoundy = maxBoundl - k;
int maxBoundx = maxBoundm - k;
if (!(((maxBoundx - startX)*2 + (maxBoundx - 2 - startX)*2) > maxMinerals)) {
break;
}
sidey = lineOffset + width;
lastMinerals = 0;
toxics = 0;
if (map[maxBoundx + lineOffset] == 1) {
mineralsUpSide--;
} else if (map[maxBoundx + lineOffset]) {
toxicsUpSide--;
}
if (map[startX + mBw + width] == 1) {
mineralsLeftSide--;
} else if (map[startX + mBw + width]) {
toxicsLeftSide--;
}
for (int x = startX + 1; x < maxBoundx; x++) {
mw = x + mBw;
if (map[mw] == 1) {
lastMinerals++;
} else if (map[mw]) {
toxics++;
}
}
for (int y = startY + 1; y < maxBoundy - 1; y++) {
mw = maxBoundx - 1 + sidey;
if (map[mw] == 1) {
lastMinerals++;
} else if (map[mw]) {
toxics++;
}
sidey = sidey + width;
}
int finalMinerals = lastMinerals + mineralsLeftSide + mineralsUpSide;
int finalToxics = toxics + toxicsLeftSide + toxicsUpSide;
if (!(finalMinerals / 2.0 < finalToxics) && finalMinerals > maxMinerals) {
maxMinerals = finalMinerals;
}
mBw = mBw - width;
}
}
lineOffset = lineOffset + width;
}
printf("%d\n", maxMinerals);
}
void traverseforW(int *map, const int height, const int width) {
int h1 = height - 1;
int w1 = width - 1;
int lineOffset = 0;
for (int startY = 0; startY < h1; startY++) {
int yside = height - startY;
if (!(yside * 2 + (yside - 2)*2 > maxMinerals)) {
break;
}
for (int startX = 0; startX < w1; startX++) {
int xside = width - startX;
if (!(xside * 2 + (xside - 2)*2 > maxMinerals)) {
break;
}
int maxBoundl = height;
int maxBoundm = height;
if (startX + maxBoundl - width - startY > 0) {
maxBoundl = width;
maxBoundm = width;
if (startX - startY > 0) {
maxBoundl = maxBoundl + startY - startX;
} else {
maxBoundm = maxBoundm + startX - startY;
}
} else if (startY - startX > 0) {
maxBoundm = maxBoundm + startX - startY;
} else {
maxBoundl = maxBoundl + startX - startY;
maxBoundm = maxBoundl;
maxBoundl = maxBoundl + startY - startX;
}
int mBw = (maxBoundl - 1) * width;
int toxicsLeftSide = 0;
int mineralsLeftSide = 0;
int toxicsUpSide = 0;
int mineralsUpSide = 0;
int mw;
int lastMinerals = 0;
int toxics = 0;
int sidey = lineOffset + width;
for (int x = startX; x < maxBoundm; x++) {
mw = x + lineOffset;
if (map[mw] == 1) {
mineralsUpSide++;
lastMinerals++;
} else if (map[mw]) {
toxicsUpSide++;
toxics++;
}
mw = x + mBw;
if (map[mw] == 1) {
lastMinerals++;
} else if (map[mw]) {
toxics++;
}
}
for (int y = startY + 1; y < maxBoundl - 1; y++) {
mw = startX + sidey;
if (map[mw] == 1) {
mineralsLeftSide++;
lastMinerals++;
} else if (map[mw]) {
toxicsLeftSide++;
toxics++;
}
mw = maxBoundm - 1 + sidey;
if (map[mw] == 1) {
lastMinerals++;
} else if (map[mw]) {
toxics++;
}
sidey = sidey + width;
}
if (map[startX + mBw] == 1) {
mineralsLeftSide++;
} else if (map[startX + mBw]) {
toxicsLeftSide++;
}
if (!(lastMinerals / 2.0 < toxics) && lastMinerals > maxMinerals) {
maxMinerals = lastMinerals;
}
mBw = mBw - width;
int noOfSquares;
if (xside < yside) {
noOfSquares = xside - 1;
} else {
noOfSquares = yside - 1;
}
for (int k = 1; k < noOfSquares; k++) {
int maxBoundy = maxBoundl - k;
int maxBoundx = maxBoundm - k;
if (!(((maxBoundx - startX)*2 + (maxBoundx - 2 - startX)*2) > maxMinerals)) {
break;
}
sidey = lineOffset + width;
lastMinerals = 0;
toxics = 0;
if (map[maxBoundx + lineOffset] == 1) {
mineralsUpSide--;
} else if (map[maxBoundx + lineOffset]) {
toxicsUpSide--;
}
if (map[startX + mBw + width] == 1) {
mineralsLeftSide--;
} else if (map[startX + mBw + width]) {
toxicsLeftSide--;
}
int finalMinerals = mineralsUpSide + mineralsLeftSide;
int finalToxics = toxicsLeftSide + toxicsUpSide;
for (int x = startX + 1; x < maxBoundx; x++) {
mw = x + mBw;
if (map[mw] == 1) {
lastMinerals++;
} else if (map[mw]) {
toxics++;
}
}
for (int y = startY + 1; y < maxBoundy - 1; y++) {
mw = maxBoundx - 1 + sidey;
if (map[mw] == 1) {
lastMinerals++;
} else if (map[mw]) {
toxics++;
}
sidey = sidey + width;
}
finalMinerals += lastMinerals;
finalToxics += toxics;
if (!(finalMinerals / 2.0 < finalToxics) && finalMinerals > maxMinerals) {
maxMinerals = finalMinerals;
}
mBw = mBw - width;
}
}
lineOffset = lineOffset + width;
}
printf("%d\n", maxMinerals);
}
int main() {
char hw[14];
FILE * file = fopen("pub01.in", "r");
char c;
int k = 0;
while ((c = fgetc(file)) != '\n') {
hw[k] = c;
k++;
}
int h, w;
sscanf(hw, "%d %d", &h, &w);
int size = h * w;
int* input = malloc(size * sizeof (int) + 1);
k = 0;
while ((c = fgetc(file)) != EOF) {
if (c == '0' || c == '1' || c == '2') {
input[k] = c - '0';
k++;
}
}
input[k] = '\0';
if (h > w) {
traverseforH(input, h, w);
} else {
traverseforW(input, h, w);
}
return 0;
}

Preprocess step:
First pre-process matrix, using prefix sum method all rows and columns so that you will be able to calculate # of 1s and # of 2s in the perimeter of square in O(1).
By now you will have 4 data-structures: rowSumFor1, rowSumFor2, colSumFor1, colSumFor2. For example: rowSumFor1[i][j] would tell us # of 1s in ith row for column indices between 0 and j inclusive.
Time complexity: O(w x h)
Complete Code:
#include<stdio.h>
int min(int a,int b){
return (a<=b)?a:b;
}
int max(int a,int b){
return (a>=b)?a:b;
}
// currently hard-coding dimensions for test purposes
// horizontal sums
int rowSumFor1[600][600];
int rowSumFor2[600][600];
// vertical sums
int colSumFor1[600][600];
int colSumFor2[600][600];
int main(){
int w,h;
scanf("%d %d",&h,&w);
for(int row=1;row <= h;row++)for(int col=1;col <= w;col++){
int temp;
scanf("%d",&temp);
// first add previous sum
rowSumFor1[row][col]=rowSumFor1[row][col - 1];
rowSumFor2[row][col]=rowSumFor2[row][col - 1];
colSumFor1[col][row]=colSumFor1[col][row - 1];
colSumFor2[col][row]=colSumFor2[col][row - 1];
if(temp==1){
rowSumFor1[row][col]++;
colSumFor1[col][row]++;
}
else if(temp==2){
rowSumFor2[row][col]++;
colSumFor2[col][row]++;
}
else{
// do nothing
}
}
int result = 0,rowId,colId,mlength;
for(int len=min(w,h); len > 1 ; len-- ) // iteration on possible lengths
{
for(int row=1;row <= (h - len + 1);row++)for(int col=1;col <= (w - len + 1);col++){ // iteration on all co-ordinates as upper-left corner of our square
// Do calculation here for properties and necessary checking constraints for validity of this square
// Note: not checking trivial conditions like boundary conditions in square, you will have to!!
// Beware of over-counting of corners here, one way to avoid is to select indices such that they don't overcount corners
// 4x4 square example for counting
// aaab
// d b
// d b
// dccc
int topEdge1 = rowSumFor1[row][col + len - 2] - rowSumFor1[row][col - 1];
int bottomEdge1 = rowSumFor1[row + len - 1][col + len - 1] - rowSumFor1[row + len - 1][col];
int leftEdge1 = colSumFor1[col][row + len - 1] - colSumFor1[col][row];
int rightEdge1 = colSumFor1[col + len - 1][row + len - 2] - colSumFor1[col + len - 1][row - 1];
int ones= topEdge1 + bottomEdge1 + leftEdge1 + rightEdge1; // # of 1s on perimeter of this square
int topEdge2 = rowSumFor2[row][col + len - 2] - rowSumFor2[row][col-1];
int bottomEdge2 = rowSumFor2[row+len-1][col+len-1] - rowSumFor2[row+len-1][col];
int leftEdge2 = colSumFor2[col][row + len - 1] - colSumFor2[col][row];
int rightEdge2 = colSumFor2[col + len - 1][row + len - 2] - colSumFor2[col + len -1][row - 1];
int twos= topEdge2 + bottomEdge2 + leftEdge2 + rightEdge2; // # of 2s on perimeter of this square
if(ones >= 2* twos){
if(ones > result){
result = ones;
rowId = row;
colId = col;
mlength = len;
}
}
}
}
printf("%d %d %d\n",rowId,colId,mlength);
printf("%d\n",result);
return 0;
}
Time complexity: O(w x h x min(w,h))
EDIT:
Replaced pseudo-code with complete code. It results as expected for all 3 tests presented by OP.

Related

Digital Image Processing Contrast Stretching Histogram

Here I attach my code that I use to Draw the Histogram of the Contrasted image and also to convert a gray image into Contrast Image. Here I used low pint as 122 and highest point as 244. In the output histogram it reduce the height of the histogram.
I cannot find the error in my code
#include "opencv2/opencv.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/core.hpp"
using namespace cv;
using namespace std;
int main(int argc, char* argv[]) {
Mat img = imread(argv[1], 1);
if (!img.data) {
cout << "Could not find the image!" << endl;
return -1;
}
int height = img.rows;
int width = img.cols;
int widthstep = img.step;
int ch = img.channels();
printf("Height : %d\n", height);
printf("Width : %d\n", width);
printf("Widthstep : %d\n", widthstep);
printf("No of channels : %d\n", ch);
Mat gray_image(height, width, CV_8UC1, Scalar(0));
cvtColor(img, gray_image, COLOR_BGR2GRAY);
Mat new_image = gray_image.clone();
int v;
int output{};
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int v = (int)gray_image.at<uchar>(y, x);
if (v >= 0 && v <= 122) {
output = int((6 / 122) * v);
}
else if (v > 100 && v <= 244) {
output = int(((244) / (122)) * (v - 122) + 6);
}
else if (v > 244 && v <= 255) {
output = int(((5) / (11)) * (v - 244) + 250);
}
new_image.at<uchar>(y, x) = (uchar)output;
}
}
int histn[256];
for (int i = 0; i < 256; i++) {
histn[i] = 0;
}
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
histn[(int)new_image.at<uchar>(y, x)] = histn[(int)new_image.at<uchar>(y, x)] + 1;
}
}
for (int i = 0; i < 256; i++) {
cout << i << ":" << histn[i] << endl;
}
int hist_wn = 512;
int hist_hn = 400;
int bin_wn = cvRound((double)hist_wn / 256);
Mat new_histogramImage(hist_hn, hist_wn, CV_8UC1, Scalar(255));
int maxn = histn[0];
for (int i = 0; i < 256; i++) {
if (maxn < histn[i]) {
maxn = histn[i];
}
}
for (int i = 0; i < 256; i++) {
histn[i] = ((double)histn[i] / maxn) * new_histogramImage.rows;
}
for (int i = 0; i < 256; i++) {
line(new_histogramImage, Point(bin_wn * (i), hist_hn), Point(bin_wn * (i), hist_hn - histn[i]), Scalar(0), 1, 8, 0);
}
imwrite("Gray_Image.png", gray_image);
imwrite("newcontrast_Image.png", new_image);
imwrite("Histogram.png", new_histogramImage);
namedWindow("Image");
imshow("Image", img);
namedWindow("Gray_Image");
imshow("Gray_Image", gray_image);
namedWindow("newcontrast_Image");
imshow("newcontrast_Image", new_image);
namedWindow("New_Histogram");
imshow("New_Histogram", new_histogramImage);
namedWindow("Old_Histogram");
imshow("Old_Histogram", histImage);
waitKey(0);
return 0;
}
Here are the new and old histograms that I got as outputs
I found the solution for the question. Here I changed the lowest and highest point values as 100 and 240 and when using the values set those as decimals values.
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int v = (int)gray_image.at<uchar>(y, x);
if (v >= 0 && v <= 100) {
output = int((5.0/ 100.0) * v);
}
else if (v > 100 && v <= 240) {
output = int(((245.0) / (140.0)) * (v - 100.0) + 5.0);
}
else if (v > 240 && v <= 255) {
output = int(((5.0) / (15.0)) * (v - 240.0) + 250.0);
}
new_image.at<uchar>(y, x) = (uchar)output;
}
}

How does recursive division to generate maze work? [duplicate]

I am currently developing a random maze generator that stores the maze in a 2-dimensional array called grid. This will then be used later on to generate a real 3D maze that the user can then walk through.
After doing some research, I attempted to create this maze generator using the recursive division algorithm, however due to the nature of the format of the maze, this isn't really working for me.
From what I understand, the recursive division method does not treat walls as cells.
For instance, my grid would look like this:
a b c d e f g h
1 - - - - - - - -
2 | | | | |
3 | | |
4 | - - | - |
5 | | | |
6 | - | - |
7 x |
8 - - - - - - - -
The point that I'm trying to get across here is that the grid I am trying to create will be represented something like this:
w w w w w w w w
w w w w w
w w w
w w w w w w
w w w w
w w w w w
g w
w w w w w w w w
Where 'w' is a wall and 'g' is the entrance/exit. So walls are placed into the grid, e.g. grid[1][2] == 'w'
The problem with the recursive division algorithm is that walls are not treated as members of the cell. All of the 'cells' would essentially contain whitespace and the walls would be placed around them.
So when I tried to implement this algorithm in my situation, I ended up with a result like this: (the black squares are walls, the white squares are empty, and the red square is the entrance)
My JSFiddle is located here.
Essentially the user will start at the red square and have to go through the maze and find keys that will open the door (which is the red square) to escape, so all of the whitespace in the maze would have to be accessible.
Does anyone have any ideas on how I can rewrite this algorithm to make sure that there is always a path from the red square to any other space in the maze? Ideally, the path would never be more than one square wide.
Code:
var grid;
function generate(dimensions, numDoors) {
//numDoors is unused right now
grid = new Array();
for (var i = 0; i < dimensions; i++) {
grid[i] = new Array();
for (var j = 0; j < dimensions; j++) {
grid[i][j] = "";
}
}
addOuterWalls();
var ent = addEntrance();
addInnerWalls(true, 1, grid.length - 2, 1, grid.length - 2, ent);
}
function addOuterWalls() {
for (var i = 0; i < grid.length; i++) {
if (i == 0 || i == (grid.length - 1)) {
for (var j = 0; j < grid.length; j++) {
grid[i][j] = "w";
}
} else {
grid[i][0] = "w";
grid[i][grid.length - 1] = "w";
}
}
}
function addEntrance() {
var x = randomNumber(1, grid.length - 1);
grid[grid.length - 1][x] = "g";
return x;
}
function addInnerWalls(h, minX, maxX, minY, maxY, gate) {
if (h) {
if (maxX - minX < 2) {
return;
}
var y = randomNumber(minY, maxY);
addHWall(minX, maxX, y);
addInnerWalls(!h, minX, maxX, minY, y-1, gate);
addInnerWalls(!h, minX, maxX, y + 1, maxY, gate);
} else {
if (maxY - minY < 2) {
return;
}
var x = randomNumber(minX, maxX);
addVWall(minY, maxY, x);
addInnerWalls(!h, minX, x-1, minY, maxY, gate);
addInnerWalls(!h, x + 1, maxX, minY, maxY, gate);
}
}
function addHWall(minX, maxX, y) {
var hole = randomNumber(minX, maxX);
for (var i = minX; i <= maxX; i++) {
if (i == hole) grid[y][i] = "";
else grid[y][i] = "w";
}
}
function addVWall(minY, maxY, x) {
var hole = randomNumber(minY, maxY);
for (var i = minY; i <= maxY; i++) {
if (i == hole) grid[i][x] = "";
else grid[i][x] = "w";
}
}
function randomNumber(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
function display() {
document.getElementById("cnt").innerHTML = "";
for (var i = 0; i < grid.length; i++) {
var output = "<div>";
for (var j = 0; j < grid.length; j++) {
output += "<b " + grid[i][j] + "></b>";
}
output += "</div>";
document.getElementById("cnt").innerHTML += output;
}
}
generate(30, 1, 1);
display();
Put walls only in even cells, and doors in odd cells, and make "dimensions" odd.
http://jsfiddle.net/tPm3s/1/
Code:
var grid;
function generate(dimensions, numDoors) {
grid = new Array();
for (var i = 0; i < dimensions; i++) {
grid[i] = new Array();
for (var j = 0; j < dimensions; j++) {
grid[i][j] = "";
}
}
addOuterWalls();
var ent = addEntrance();
addInnerWalls(true, 1, grid.length - 2, 1, grid.length - 2, ent);
}
function addOuterWalls() {
for (var i = 0; i < grid.length; i++) {
if (i == 0 || i == (grid.length - 1)) {
for (var j = 0; j < grid.length; j++) {
grid[i][j] = "w";
}
} else {
grid[i][0] = "w";
grid[i][grid.length - 1] = "w";
}
}
}
function addEntrance() {
var x = randomNumber(1, grid.length - 1);
grid[grid.length - 1][x] = "g";
return x;
}
function addInnerWalls(h, minX, maxX, minY, maxY, gate) {
if (h) {
if (maxX - minX < 2) {
return;
}
var y = Math.floor(randomNumber(minY, maxY)/2)*2;
addHWall(minX, maxX, y);
addInnerWalls(!h, minX, maxX, minY, y-1, gate);
addInnerWalls(!h, minX, maxX, y + 1, maxY, gate);
} else {
if (maxY - minY < 2) {
return;
}
var x = Math.floor(randomNumber(minX, maxX)/2)*2;
addVWall(minY, maxY, x);
addInnerWalls(!h, minX, x-1, minY, maxY, gate);
addInnerWalls(!h, x + 1, maxX, minY, maxY, gate);
}
}
function addHWall(minX, maxX, y) {
var hole = Math.floor(randomNumber(minX, maxX)/2)*2+1;
for (var i = minX; i <= maxX; i++) {
if (i == hole) grid[y][i] = "";
else grid[y][i] = "w";
}
}
function addVWall(minY, maxY, x) {
var hole = Math.floor(randomNumber(minY, maxY)/2)*2+1;
for (var i = minY; i <= maxY; i++) {
if (i == hole) grid[i][x] = "";
else grid[i][x] = "w";
}
}
function randomNumber(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
function display() {
document.getElementById("cnt").innerHTML = "";
for (var i = 0; i < grid.length; i++) {
var output = "<div>";
for (var j = 0; j < grid.length; j++) {
output += "<b " + grid[i][j] + "></b>";
}
output += "</div>";
document.getElementById("cnt").innerHTML += output;
}
}
generate(31, 1, 1);
display();

Check if object is in range in a matrix

I would like to check if an object is in range in a matrix.
A 1 range would be 9 blocks around the player (orange).
But a two range would be 25 blocks (blue). The player is the red cross.I tried the following code:`
int size = ((range * 2) +1) * ((range * 2) + 1);
int sq = (range * 2) + 1;
int startX = x - range; if (startX < 0) startX = 0;
int startY = y - range; if (startY < 0) startY = 0;
int endX = x + range; if (endX > arrayWitdth) endX = arrayWitdth;
int endY = y + range; if (endY > arrayLenght) endY = arrayLenght;
//printf("Range: %d\n", range);
for (size_t i = startX; i < endX; i++)
{
for (size_t j = startY; j < endY; j++)
{
//printf("Looking at (%d,%d)\n", i, j);
if (map[i][j] == charTocheck) return 1;
}
}
`
You don't check the last block, so the correct implementation would be:
int size = ((range * 2) +1) * ((range * 2) + 1);
int sq = (range * 2) + 1;
int startX = x - range; if (startX < 0) startX = 0;
int startY = y - range; if (startY < 0) startY = 0;
int endX = x + range + 1; if (endX > arrayWitdth) endX = arrayWitdth;
int endY = y + range + 1; if (endY > arrayLenght) endY = arrayLenght;
//printf("Range: %d\n", range);
for (size_t i = startX; i < endX; i++)
{
for (size_t j = startY; j < endY; j++)
{
//printf("Looking at (%d,%d)\n", i, j);
if (map[i][j] == charTocheck) return 1;
}
}
notice that endX and endY have slightly changed.

Blobs detecting algorithm

I am trying to make blobs finding algorithm with 8 connectivity for binary image(monochrome) (coordinates of bounding boxes up-left and down-right dots)which use small amount of memory (needed because the large resolution of the image) on C++.
There are such tools like OpenCV, but it has a lot of filters and is too slow if you want to detect each blob in binary image, there is also CvBlobsLib but the support is outdated(last version is before 5 years) and I couldn't set it up for Visual Studio 2013 (it must be compiled with Cmake, and it is giving errors). In wikipedia there are two types of algorithms - "one component of a time" and "two-pass" connected-component , but they both use labels, which mean you will have another 2D array of integers, but this will take a lot of memory because of the size of int(4 bytes), and we need int because of the image size and possibility of more than 65535 labels(which is short). If it is even short it will take twice less memory, which is again a lot of it. I found a "quickblob" written in C quicblobsalgol but I couldn't run it from the source(but exe is working properly), tried to analyze the code, and I got something, but the whole idea behind it stayed vague for me, so I tried also something like floodFill algorithm and something like "disjoined-set data structure" link which to hold the blobs, and this means the used memory theoretically is defined of the number of blobs(single black pixels are not recognize as blobs). Here is the C++ code:
#include <cstdlib>
#include <iostream>
#include <ctime>
#include <math.h>
#define ROWS 4000
#define COLS 4000
#define BLOBS 1000000
using namespace std;
void floodFillAlgorithm(short(&arr)[ROWS][COLS]);
int recurciveMarkBlob(short(&arr)[ROWS][COLS], int **ptr_labels, int i, int j, int group);
int main(){
short arr[ROWS][COLS];
srand((unsigned int)time(0)); // use current time as seed for random generator
for (int i = 0; i < ROWS; i++)
{
for (int j = 0; j < COLS; j++)
{
arr[i][j] = rand() % 2;
}
}
/*for (int i = 0; i < ROWS; i++)
{
for (int j = 0; j < COLS; j++)
{
cout << arr[i][j] << '\t';
}
cout << '\n';
}*/
floodFillAlgorithm(arr);
cout << '\n';
cout << '\n';
/*for (int i = 0; i < ROWS; i++)
{
for (int j = 0; j < COLS; j++)
{
cout << arr[i][j] << '\t';
}
cout << '\n';
}*/
system("PAUSE");
return 0;}
void floodFillAlgorithm(short(&arr)[ROWS][COLS])
{
int group = 0;
int **ptr_labels;
ptr_labels = (int **)malloc(BLOBS * sizeof(int*));
if (ptr_labels == 0)
{
printf("ERROR: Out of memory\n");
}
for (int i = 0; i < BLOBS; i++)
{
ptr_labels[i] = NULL;
}
for (int i = 0; i < ROWS; i++)
{
for (int j = 0; j < COLS; j++)
{
if (arr[i][j] == 1)
{
recurciveMarkBlob(arr, ptr_labels,i, j, ++group);
arr[i][j] = 1;
}
}
}
int count = 0;
for (int i = 0; i < BLOBS; i++)
{
if (ptr_labels[i] != NULL)
{
count++;
//cout << "Label: " << i << " ; X1: " << ptr_labels[i][0] << " ; Y1: " << ptr_labels[i][1] << " ; X2: " << ptr_labels[i][2] << " ; Y2: " << ptr_labels[i][3] << " ; X3: " << ptr_labels[i][4] << " ; Y3: " << ptr_labels[i][5] << " ; POINTS: " << ptr_labels[i][6] << endl;
}
}
cout << "Count: " << count << endl;
system("PAUSE");
for (int i = 0; i < BLOBS; i++)
{
if (ptr_labels[i] != NULL)
{
free(ptr_labels[i]);
}
}
free(ptr_labels);
}
int recurciveMarkBlob(short(&arr)[ROWS][COLS], int **ptr_labels, int i, int j, int group)
{
//cout << " i : " << i << " j: " << j << endl;
if (j != 0)
{
if ((arr[i][j] == arr[i][j - 1]) && (arr[i][j - 1] == 1))
{
if (ptr_labels[group] == NULL)
{
ptr_labels[group] = (int *)malloc(7 * sizeof(int*));
ptr_labels[group][0] = j - 1;
ptr_labels[group][1] = i;
ptr_labels[group][2] = j;
ptr_labels[group][3] = i;
ptr_labels[group][4] = j;
ptr_labels[group][5] = i;
ptr_labels[group][6] = 2; // taken points (area) for current shape
}
else
{
if (ptr_labels[group][0] > j - 1)
{
ptr_labels[group][0] = j - 1;
}
ptr_labels[group][6]++;
}
arr[i][j] = 0;
recurciveMarkBlob(arr, ptr_labels, i, j - 1, group);
arr[i][j] = 1;
}
}
if (j != COLS - 1)
{
if ((arr[i][j] == arr[i][j + 1]) && (arr[i][j + 1] == 1))
{
if (ptr_labels[group] == NULL)
{
ptr_labels[group] = (int *)malloc(7 * sizeof(int*));
ptr_labels[group][0] = j;
ptr_labels[group][1] = i;
ptr_labels[group][2] = j + 1;
ptr_labels[group][3] = i;
ptr_labels[group][4] = j;
ptr_labels[group][5] = i;
ptr_labels[group][6] = 2; // taken points (area) for current shape
}
else
{
if (ptr_labels[group][2] < j + 1)
{
ptr_labels[group][2] = j + 1;
}
ptr_labels[group][6]++;
}
arr[i][j] = 0;
recurciveMarkBlob(arr, ptr_labels, i, j + 1, group);
arr[i][j] = 1;
}
}
if (i != 0)
{
if ((arr[i][j] == arr[i - 1][j]) && (arr[i - 1][j] == 1))
{
if (ptr_labels[group] == NULL)
{
ptr_labels[group] = (int *)malloc(7 * sizeof(int*));
ptr_labels[group][0] = j;
ptr_labels[group][1] = i - 1;
ptr_labels[group][2] = j;
ptr_labels[group][3] = i;
ptr_labels[group][4] = j;
ptr_labels[group][5] = i;
ptr_labels[group][6] = 2; // taken points (area) for current shape
}
else
{
if (ptr_labels[group][1] > i - 1)
{
ptr_labels[group][1] = i - 1;
}
ptr_labels[group][6]++;
}
arr[i][j] = 0;
recurciveMarkBlob(arr, ptr_labels, i - 1, j, group);
arr[i][j] = 1;
}
}
if (i != ROWS - 1)
{
if ((arr[i][j] == arr[i + 1][j]) && (arr[i + 1][j] == 1))
{
if (ptr_labels[group] == NULL)
{
ptr_labels[group] = (int *)malloc(7 * sizeof(int*));
ptr_labels[group][0] = j;
ptr_labels[group][1] = i;
ptr_labels[group][2] = j;
ptr_labels[group][3] = i + 1;
ptr_labels[group][4] = j;
ptr_labels[group][5] = i;
ptr_labels[group][6] = 2; // taken points (area) for current shape
}
else
{
if (ptr_labels[group][3] < i + 1)
{
ptr_labels[group][3] = i + 1;
}
ptr_labels[group][6]++;
}
arr[i][j] = 0;
recurciveMarkBlob(arr, ptr_labels, i + 1, j, group);
arr[i][j] = 1;
}
}
if ((i != 0) && (j != 0))
{
if ((arr[i][j] == arr[i - 1][j - 1]) && (arr[i - 1][j - 1] == 1))
{
if (ptr_labels[group] == NULL)
{
ptr_labels[group] = (int *)malloc(7 * sizeof(int*));
ptr_labels[group][0] = j - 1;
ptr_labels[group][1] = i - 1;
ptr_labels[group][2] = j;
ptr_labels[group][3] = i;
ptr_labels[group][4] = j;
ptr_labels[group][5] = i;
ptr_labels[group][6] = 2; // taken points (area) for current shape
}
else
{
if (ptr_labels[group][0] > j - 1)
{
ptr_labels[group][0] = j - 1;
}
if (ptr_labels[group][1] > i - 1)
{
ptr_labels[group][1] = i - 1;
}
ptr_labels[group][6]++;
}
arr[i][j] = 0;
recurciveMarkBlob(arr, ptr_labels, i - 1, j - 1, group);
arr[i][j] = 1;
}
}
if ((i != 0) && (j != COLS - 1))
{
//cout << "i: " << i << " ; j: " << j << endl;
if ((arr[i][j] == arr[i - 1][j + 1]) && (arr[i - 1][j + 1] == 1))
{
//cout << "i: " << i << " ; j: " << j << endl;
if (ptr_labels[group] == NULL)
{
ptr_labels[group] = (int *)malloc(7 * sizeof(int*));
ptr_labels[group][0] = j;
ptr_labels[group][1] = i - 1;
ptr_labels[group][2] = j + 1;
ptr_labels[group][3] = i;
ptr_labels[group][4] = j;
ptr_labels[group][5] = i;
ptr_labels[group][6] = 2; // taken points (area) for current shape
//cout << "Label: " << group << " ; X1: " << ptr_labels[group][0] << " ; Y1: " << ptr_labels[group][1] << " ; X2: " << ptr_labels[group][2] << " ; Y2: " << ptr_labels[group][3] << endl;
}
else
{
if (ptr_labels[group][2] < j + 1)
{
ptr_labels[group][2] = j + 1;
}
if (ptr_labels[group][1] > i - 1)
{
ptr_labels[group][1] = i - 1;
}
ptr_labels[group][6]++;
}
arr[i][j] = 0;
recurciveMarkBlob(arr, ptr_labels, i - 1, j + 1, group);
arr[i][j] = 1;
}
}
if ((i != ROWS - 1) && (j != 0))
{
if ((arr[i][j] == arr[i + 1][j - 1]) && (arr[i + 1][j - 1] == 1))
{
if (ptr_labels[group] == NULL)
{
ptr_labels[group] = (int *)malloc(7 * sizeof(int*));
ptr_labels[group][0] = j - 1;
ptr_labels[group][1] = i;
ptr_labels[group][2] = j;
ptr_labels[group][3] = i + 1;
ptr_labels[group][4] = j;
ptr_labels[group][5] = i;
ptr_labels[group][6] = 2; // taken points (area) for current shape
}
else
{
if (ptr_labels[group][0] > j - 1)
{
ptr_labels[group][0] = j - 1;
}
if (ptr_labels[group][3] < i + 1)
{
ptr_labels[group][3] = i + 1;
}
ptr_labels[group][6]++;
}
arr[i][j] = 0;
recurciveMarkBlob(arr, ptr_labels, i + 1, j - 1, group);
arr[i][j] = 1;
}
}
if ((i != ROWS - 1) && (j != COLS - 1))
{
if ((arr[i][j] == arr[i + 1][j + 1]) && (arr[i + 1][j + 1] == 1))
{
if (ptr_labels[group] == NULL)
{
ptr_labels[group] = (int *)malloc(7 * sizeof(int*));
ptr_labels[group][0] = j;
ptr_labels[group][1] = i;
ptr_labels[group][2] = j + 1;
ptr_labels[group][3] = i + 1;
ptr_labels[group][4] = j; // x of pixel in black
ptr_labels[group][5] = i; // y of pixel in black
ptr_labels[group][6] = 2; // taken points (area) for current shape
}
else
{
if (ptr_labels[group][2] < j + 1)
{
ptr_labels[group][2] = j + 1;
}
if (ptr_labels[group][3] < i + 1)
{
ptr_labels[group][3] = i + 1;
}
ptr_labels[group][6]++;
}
arr[i][j] = 0;
recurciveMarkBlob(arr, ptr_labels, i + 1, j + 1, group);
arr[i][j] = 1;
}
}
/**/
arr[i][j] = 0;
return 0;
}
The main question is why before end of the main function so much RAM is still in use(147 MB). The tail recursion "recurciveMarkBlob()" is using parameters by value i,j, group, and dynamic allocation of memory and that is why the memory temporary jumps to 600 MB(mostly from the parameters), after freeing the dynamically allocated memory it still takes 148 MB, the image is 4 000 x 4 000 x 2 bytes = 16 000 000 bytes = 16 MB. I have read about "function taken memory" here but I still cant understand why. If someone can explain it with assembler code what is happening and is this occurrence normal. I am using Release mode release vs debug
system("PAUSE") in main()
In process of recursion
Also everyone can give idea for fast and low memory taking algorithm for blob detection of large binary images.
The elementary recursive solution requires a lot of stack space, on the order of the size of the blobs. Multiply that by the size of the stack frame, and you get horrible bytes/pixel requirements.
The scanline filling principle can reduce that requirement by orders of magnitude. Anyway, blob detection in textures ("porous" blobs) remains problematic.
You may also consider implementing this gem: "A Linear-Time Component-Labeling Algorithm Using Contour Tracing Technique, Fu Chang, Chun-Jen Chen, and Chi-Jen Lu."

how to generate Chase's sequence

In the draft section 7.2.1.3 of The art of computer programming, generating all combinations, Knuth introduced Algorithm C for generating Chase's sequence.
He also mentioned a similar algorithm (based on the following equation) working with index-list without source code (exercise 45 of the draft).
I finally worked out a c++ version which I think is quite ugly. To generate all C_n^m combination, the memory complexity is about 3 (m+1) and the time complexity is bounded by O(m n^m)
class chase_generator_t{
public:
using size_type = ptrdiff_t;
enum class GET : char{ VALUE, INDEX };
chase_generator_t(size_type _n) : n(_n){}
void choose(size_type _m){
m = _m;
++_m;
index.resize(_m);
threshold.resize(_m + 1);
tag.resize(_m);
for (size_type i = 0, j = n - m; i != _m; ++i){
index[i] = j + i;
tag[i] = tag_t::DECREASE;
using std::max;
threshold[i] = max(i - 1, (index[i] - 3) | 1);
}
threshold[_m] = n;
}
bool get(size_type &x, size_type &y, GET const which){
if (which == GET::VALUE) return __get<false>(x, y);
return __get<true>(x, y);
}
size_type get_n() const{
return n;
}
size_type get_m() const{
return m;
}
size_type operator[](size_t const i) const{
return index[i];
}
private:
enum class tag_t : char{ DECREASE, INCREASE };
size_type n, m;
std::vector<size_type> index, threshold;
std::vector<tag_t> tag;
template<bool GetIndex>
bool __get(size_type &x, size_type &y){
using std::max;
size_type p = 0, i, q;
find:
q = p + 1;
if (index[p] == threshold[q]){
if (q >= m) return false;
p = q;
goto find;
}
x = GetIndex ? p : index[p];
if (tag[p] == tag_t::INCREASE){
using std::min;
increase:
index[p] = min(index[p] + 2, threshold[q]);
threshold[p] = index[p] - 1;
}
else if (index[p] && (i = (index[p] - 1) & ~1) >= p){
index[p] = i;
threshold[p] = max(p - 1, (index[p] - 3) | 1);
}
else{
tag[p] = tag_t::INCREASE;
i = p | 1;
if (index[p] == i) goto increase;
index[p] = i;
threshold[p] = index[p] - 1;
}
y = index[p];
for (q = 0; q != p; ++q){
tag[q] = tag_t::DECREASE;
threshold[q] = max(q - 1, (index[q] - 3) | 1);
}
return true;
}
};
Does any one has a better implementation, i.e. run faster with the same memory or use less memory with the same speed?
I think that the C code below is closer to what Knuth had in mind. Undoubtedly there are ways to make it more elegant (in particular, I'm leaving some scaffolding in case it helps with experimentation), though I'm skeptical that the array w can be disposed of. If storage is really important for some reason, then steal the sign bit from the a array.
#include <stdbool.h>
#include <stdio.h>
enum {
N = 10,
T = 5
};
static void next(int a[], bool w[], int *r) {
bool found_r = false;
int j;
for (j = *r; !w[j]; j++) {
int b = a[j] + 1;
int n = a[j + 1];
if (b < (w[j + 1] ? n - (2 - (n & 1)) : n)) {
if ((b & 1) == 0 && b + 1 < n) b++;
a[j] = b;
if (!found_r) *r = j > 1 ? j - 1 : 0;
return;
}
w[j] = a[j] - 1 >= j;
if (w[j] && !found_r) {
*r = j;
found_r = true;
}
}
int b = a[j] - 1;
if ((b & 1) != 0 && b - 1 >= j) b--;
a[j] = b;
w[j] = b - 1 >= j;
if (!found_r) *r = j;
}
int main(void) {
typedef char t_less_than_n[T < N ? 1 : -1];
int a[T + 1];
bool w[T + 1];
for (int j = 0; j < T + 1; j++) {
a[j] = N - (T - j);
w[j] = true;
}
int r = 0;
do {
for (int j = T - 1; j > -1; j--) printf("%x", a[j]);
putchar('\n');
if (false) {
for (int j = T - 1; j > -1; j--) printf("%d", w[j]);
putchar('\n');
}
next(a, w, &r);
} while (a[T] == N);
}

Resources