Related
recently moved from C# to C++ so I'm new to pointers and references and so on.
I've a pointer-to-pointer array declared like this
enum Type
{
Void,
DeepWater,
Water,
... etc }
Tile::Type** tiles;
TileManager::TileManager(int width, int height)
{
this->tiles = new Tile::Type*[width];
for (int w = 0; w < width; w++)
{
tiles[w] = new Tile::Type[height];
for (int h = 0; h < height; h++)
{
tiles[w][h] = Tile::Type::Dirt;
}
}
}
Now I'm putting together a method that returns the neighbours of a cell in the tiles array and checking if each neighbour is not-equal to NULL.
However even when checking whether it's null or not seems to throw an error, so I'm stumped.
Tile::Type * TileManager::GetNeighbours(int x, int y)
{
Tile::Type neighbours[8];
if(tiles[x][y+1] != NULL)
neighbours[0] = tiles[x ][y + 1];
...etc
if (tiles[x - 1][y - 1] != NULL) //<-- Error fires here
neighbours[5] = tiles[x - 1][y - 1];
return neighbours;
}
I know why it's throwing the error but shy of checking X and Y to see if they go over the limit or below 0... I figure there's a more practical way to prevent this so thought I'd best ask.
Edit:
Thank you, user4581301. I found most of this code elsewhere and adapted it to reflect the changes you suggested.
std::array<Tile::Type, 8> TileManager::GetNeighbours(int c, int r)
{
std::array<Tile::Type, 8> neighbours;
const int y[] = { -1, -1, -1, 1, 1, 1, 0, 0 };// 8 shifts to neighbors
const int x[] = { -1, 0, 1, -1, 0, 1, -1, 1 };// used in functions
for (int i = 0; i < 8; ++i)// visit the 8 spaces around it
if (inField(r + y[i], c + x[i]))
neighbours[i] = tiles[r + y[i]][c + x[i]];
else
neighbours[i] = Tile::Type::Void;
return neighbours;
}
bool TileManager::inField(int r, int c)
{
if (r < 0 || r >= 25) return false;
if (c < 0 || c >= 25) return false;
return true;
}
tiles[x][y+1], if y is the maximum valid value, will not be NULL except by the grace of . This goes out of bounds and as soon as you go out of bounds all bets are off. You've invoked Undefined Behaviour and pretty much anything can happen. Even what you expected to happen.
The same applies to the reported crash site, tiles[x - 1][y - 1].
Edit: Left out solution. Not helpful.
The only way, short of taking off and nuking the entire site from orbit, is to test the index to make sure it does not puncture the array bounds before using the index on the array. You'll probably want a function to handle this.
void assign_if(Type & neighbour, int x, int y)
{
if(x >= 0 && x < width && y >= 0 && y < height)
neighbour = tiles[x][y];
}
and call it
assign_if(neighbours[0], x, y+1);
and later
assign_if(neighbours[0], x-1, y-1);
Edit: Stealing this from Bob__ for completeness
It is impossible to return a raw array from a function. The array goes out of scope and the pointer to it becomes invalid. Either pass in the array as another parameter or use a std::array or std::vector, both of which can be returned. Thanks to Copy Elision, a smart compiler will likely eliminate the copying costs.
Example:
std::array<Tile::Type, 8> TileManager::GetNeighbours(int x, int y)
{
std::array<Tile::Type, 8> neighbours;
...
return neighbours;
}
Edit by original poster. Here is my solution:
std::array<Tile::Type, 8> TileManager::GetNeighbours(int c, int r)
{
std::array<Tile::Type, 8> neighbours;
const int y[] = { -1, -1, -1, 1, 1, 1, 0, 0 };// 8 shifts to neighbors
const int x[] = { -1, 0, 1, -1, 0, 1, -1, 1 };// used in functions
for (int i = 0; i < 8; ++i)// visit the 8 spaces around it
if (inField(r + y[i], c + x[i]))
neighbours[i] = tiles[r + y[i]][c + x[i]];
else
neighbours[i] = Tile::Type::Void;
return neighbours;
}
bool TileManager::inField(int r, int c)
{
if (r < 0 || r >= 25) return false;
if (c < 0 || c >= 25) return false;
return true;
}
Edit: Caveat
This answer deals directly with solving the problem as asked. See the answer by Kaz for a description of a more practical solution that trades a bit of memory to completely eliminate the need for testing and generating the neighbours array.
The more "practical" way (shorter code that avoids conditional checks) is to create the tile array so that it's it contains an additional "border" of tiles around the valid area. If any tile position is in the valid area, then is valid and so is .
You can have a special type for the border tiles which only they have, and simply include those tiles in the "neighbors" list. If your world has walls, then the border can consist of wall material.
Needless to say, you must never ask for the list of neighbors of a border tile. This is ensured by logic such as not allowing a border tile to be the valid position for anything.
This tile is in the valid area within the border" is a condition that is easier to check, in fewer places, and your program can be structured so that this check is actually just a removable assertion (a check for a situation that should not happen if the program is correct, rather than a check for an expected situation).
In C and C++, we can displace the pointers so that position [0][0] is still the corner of the valid area, yet the out-of-bounds coordinates [-1][-1] are valid indices, as are [w][h].
Firstly, the column array is allocated two elements larger than necessary, and the pointer is the incremented by one. Then the columns are allocated two elements larger, and each pointer is incremented by one before being assigned into the main array.
When freeing the arrays with delete [], you have to remember to decrement each pointer by one.
So I have tried to implement a Sudoku via backtracking algorithm. I don't see why my code is not giving an expected output.
What I did was, I created a loop in which it checks for an empty cell (represented with 0) in the sudoku. As it finds it, the co-ordinates for it are passed to a function called possibleEntriescheck(). This function writes into a globally declared array called possibleEntries[9], the digits which can be possibly filled into the cell of which the co-ordinates are passed initially.
I learnt this algorithm from these videos:
https://www.youtube.com/watch?v=NuodN41aK3g
https://www.youtube.com/watch?v=QI0diwmx3OY
The expected output is a solved Sudoku. It doesn't perform expectedly. Rather, it freezes. A little help would mean a lot. Thank you.
#include <stdio.h>
#include <stdlib.h>
int board[9][9] = {
{3, 0, 6, 5, 0, 8, 4, 0, 0},
{5, 2, 0, 0, 0, 0, 0, 0, 0},
{0, 8, 7, 0, 0, 0, 0, 3, 1},
{0, 0, 3, 0, 1, 0, 0, 8, 0},
{9, 0, 0, 8, 6, 3, 0, 0, 5},
{0, 5, 0, 0, 9, 0, 6, 0, 0},
{1, 3, 0, 0, 0, 0, 2, 5, 0},
{0, 0, 0, 0, 0, 0, 0, 7, 4},
{0, 0, 5, 2, 0, 6, 3, 0, 0},
};
int possibleEntries[9];
void possibleEntriescheck(int i, int j)
{
int x,a=0,k,l,y;
for(x=0;x<9;x++)
possibleEntries[x]=0;
for(x=0;x<9;x++)
{
if(board[i][x]!=0)
possibleEntries[board[i][x]-1]=1;
}
for(x=0;x<9;x++)
{
if(board[x][j]!=0)
possibleEntries[board[x][j]-1]=1;
}
if(i==0 || i==1 || i==2)
k=0;
else if(i==3 || i==4 || i==5)
k=3;
else
k=6;
if(j==0 || j==1 || j==2)
l=0;
else if(j==3 || j==4 || j==5)
l=3;
else
l=6;
for(x=k;x<k+3;x++)
{
for(y=l;y<l+3;y++)
if(board[x][y]!=0)
possibleEntries[board[x][y]-1]=1;
}
for(x=0;x<9;x++)
{
if(possibleEntries[x]==0)
possibleEntries[x]=x+1;
else
possibleEntries[x]=0;
}
}
int isFull()
{
int i,j;
for(i=0;i<9;i++)
{
for(j=0;j<9;j++)
{
if(board[i][j]==0)
return 0;
}
}
return 1;
}
void solveSudoku()
{
int i,j,x,b=0,k;
if(isFull())
{
printf("The sudoku board is:\n");
for(i=0;i<9;i++)
{
for(j=0;j<9;j++)
printf("\t%d",board[i][j]);
printf("\n");
}
}
else
{
for(i=0;i<9;i++)
{
for(j=0;j<9;j++)
{
if(board[i][j]==0)
{
possibleEntriescheck(i,j);
for(x=0;x<9;x++)
{
if(possibleEntries[x]!=0)
{
board[i][j]=possibleEntries[x];
solveSudoku();
board[i][j]=0;
}
}
}
}
}
}
return;
}
int main()
{
solveSudoku();
}
You implemented backtracking incorrectly. As also explained in the video, the actual algorithm should look like this:
solve():
if the sudoku is solved
print field
terminate
x,y = the next vacant field
for each possible value in that field
assign value to x,y
call solve() recursively to try with the assigned value
clear vacant field
Now what your code does is
solve():
if the sudoku is solved
print field
return
for each field in the sudoku
if field is vacant
for each possible value
assign value
solve recursively
reset field to unassigned
Now this actually does solve the sudoku. But there are two problems with this approach:
A: It won't terminate once it's solved the sudoku. Actually this mistake was also in the code presented in the video. A simple return in a recursive call will terminate the method on the current call and continue with the recursion "one call above". So basically the algorithm solves the sudoku in every possible way (provided there are multiple, otherwise it simply tries any possible way of assigning the values).
B: This one's way more serious. Your algorithm doesn't only generate all possible solutions, but it also tries every order of assigning the values it can possibly find. The overhead is gigantic and the reason why your code simply doesn't terminate. Solving the sudoku once already takes quite some time, but your code does so a bazillion times.
If you solve these problems, your code should work find, provided the rest is implemented correctly. I'd also recommend optimizing both the search for vacant fields and the test whether the field is empty, as these can be done fairly simple and will provide some speedup. Generate a list of vacant fields in the beginning, iterate over it (one field for each recursion-level) and terminate once the entire list was processed. E.g.:
solve(vacant, count):
if count == 0
print the field
terminate
x, y = vacant[count]
count++
for each possible value assignable to the field
assign value to x, y
call solve(vacant, count) recursively
clear field
Another problem you will encounter, which will get rather ugly to debug is thanks to this line:
int possibleEntries[9];
Global variables that are used and overwritten in a recursion are a bad idea to say the least. Imagine a possible run of the program like this (ident indicates recursion-level, where no ident means the action is global):
solve
|
---> board empty? Nope
x,y <- next vacant field
possible values <- possible values for x, y
field[x, y] <- first value from possible values
solve
|
---> board empty? Nope
x, y <- next vacant field
possible values <- possible values for x, y (overwrites global variable!!!)
field[x, y] <- first value from possible values
solve
|
---> ...
<--- return
field[x, y] <- second value from possible values (WRONG!!!)
...
The last assignment won't use the list of possible values generated for the field you're currently working on, but of another one that you visited somewhere in the recursion before returning back. You can solve this in two ways:
Iterate from 1 to 9 and check for each number separately whether it can be assigned to the field
Keeping a separate list for each level of recursion
I have written a Neural Network Program. It works for Logic Gates, but when I try to use it for recognizing handwritten digits - it simply does not learn.
Please find the code below:
// This is a single neuron; this might be necessary in order to understand remaining code
typedef struct SingleNeuron
{
double outputValue;
std::vector<double> weight;
std::vector<double> deltaWeight;
double gradient;
double sum;
}SingleNeuron;
Then I initialize the net. I set weights to be random value between -0.5 to +0.5, sum to 0, deltaWeight to 0
Then comes the FeedForward:
for (unsigned i = 0; i < inputValues.size(); ++i)
{
neuralNet[0][i].outputValue = inputValues[i];
neuralNet[0][i].sum = 0.0;
// std::cout << "o/p Val = " << neuralNet[0][i].outputValue << std::endl;
}
for (unsigned i = 1; i < neuralNet.size(); ++i)
{
std::vector<SingleNeuron> prevLayerNeurons = neuralNet[i - 1];
unsigned j = 0;
double thisNeuronOPVal = 0;
// std::cout << std::endl;
for (j = 0; j < neuralNet[i].size() - 1; ++j)
{
double sum = 0;
for (unsigned k = 0; k < prevLayerNeurons.size(); ++k)
{
sum += prevLayerNeurons[k].outputValue * prevLayerNeurons[k].weight[j];
}
neuralNet[i][j].sum = sum;
neuralNet[i][j].outputValue = TransferFunction(sum);
// std::cout << neuralNet[i][j].outputValue << "\t";
}
// std::cout << std::endl;
}
My transfer function and its derivative is mentioned at the end.
After this I try to back-propagate using:
// calculate output layer gradients
for (unsigned i = 0; i < outputLayer.size() - 1; ++i)
{
double delta = actualOutput[i] - outputLayer[i].outputValue;
outputLayer[i].gradient = delta * TransferFunctionDerivative(outputLayer[i].sum);
}
// std::cout << "Found Output gradients "<< std::endl;
// calculate hidden layer gradients
for (unsigned i = neuralNet.size() - 2; i > 0; --i)
{
std::vector<SingleNeuron>& hiddenLayer = neuralNet[i];
std::vector<SingleNeuron>& nextLayer = neuralNet[i + 1];
for (unsigned j = 0; j < hiddenLayer.size(); ++j)
{
double dow = 0.0;
for (unsigned k = 0; k < nextLayer.size() - 1; ++k)
{
dow += nextLayer[k].gradient * hiddenLayer[j].weight[k];
}
hiddenLayer[j].gradient = dow * TransferFunctionDerivative(hiddenLayer[j].sum);
}
}
// std::cout << "Found hidden layer gradients "<< std::endl;
// from output to 1st hidden layer, update all weights
for (unsigned i = neuralNet.size() - 1; i > 0; --i)
{
std::vector <SingleNeuron>& currentLayer = neuralNet[i];
std::vector <SingleNeuron>& prevLayer = neuralNet[i - 1];
for (unsigned j = 0; j < currentLayer.size() - 1; ++j)
{
for (unsigned k = 0; k < prevLayer.size(); ++k)
{
SingleNeuron& thisNeueon = prevLayer[k];
double oldDeltaWeight = thisNeueon.deltaWeight[j];
double newDeltaWeight = ETA * thisNeueon.outputValue * currentLayer[j].gradient + (ALPHA * oldDeltaWeight);
thisNeueon.deltaWeight[j] = newDeltaWeight;
thisNeueon.weight[j] += newDeltaWeight;
}
}
}
These are the TransferFuntion and its derivative;
double TransferFunction(double x)
{
double val;
//val = tanh(x);
val = 1 / (1 + exp(x * -1));
return val;
}
double TransferFunctionDerivative(double x)
{
//return 1 - x * x;
double val = exp(x * -1) / pow((exp(x * -1) + 1), 2);
return val;
}
One thing I observed If i use standard sigmoid function to be my transfer function AND if I pass output of neuron to transfer function - Result is INFINITY. But tanh(x) works fine with this value
So if I am using 1/1+e^(-x) as transfer function I have to pass Sum of Net Inputs and with tanh being my transfer function I have to pass output of current neuron.
I do not completely understand why this is the way it is, may be this calls for a different question.
But this question is really about something else: NETWORK IS WORKING FOR LOGIC GATES BUT NOT FOR CHARACTER RECOGNITION
I have tried many variations/combinations of Learning Rate and Acceleration and # hidden layers and their sizes. Please find the results below:
AvgErr: 0.299399 #Pass799
AvgErr : 0.305071 #Pass809
AvgErr : 0.303046 #Pass819
AvgErr : 0.299569 #Pass829
AvgErr : 0.30413 #Pass839
AvgErr : 0.304165 #Pass849
AvgErr : 0.300529 #Pass859
AvgErr : 0.302973 #Pass869
AvgErr : 0.299238 #Pass879
AvgErr : 0.304708 #Pass889
AvgErr : 0.30068 #Pass899
AvgErr : 0.302582 #Pass909
AvgErr : 0.301767 #Pass919
AvgErr : 0.303167 #Pass929
AvgErr : 0.299551 #Pass939
AvgErr : 0.301295 #Pass949
AvgErr : 0.300651 #Pass959
AvgErr : 0.297867 #Pass969
AvgErr : 0.304221 #Pass979
AvgErr : 0.303702 #Pass989
After looking at the results you might feel this guy is simply stuck into local minima, but please wait and read through:
Input = [0, 0, 0, 0, 0, 0, 1, 0, 0, 0]
Output = 0.0910903, 0.105674, 0.064575, 0.0864824, 0.128682, 0.0878434, 0.0946296, 0.154405, 0.0678767, 0.0666924
Input = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Output = 0.0916106, 0.105958, 0.0655508, 0.086579, 0.126461, 0.0884082, 0.110953, 0.163343, 0.0689315, 0.0675822
Input = [0, 0, 0, 1, 0, 0, 0, 0, 0, 0]
Output = 0.105344, 0.105021, 0.0659517, 0.0858077, 0.123104, 0.0884107, 0.116917, 0.161911, 0.0693426, 0.0675156
Input = [0, 0, 0, 0, 0, 0, 1, 0, 0, 0]
Output = , 0.107113, 0.101838, 0.0641632, 0.0967766, 0.117149, 0.085271, 0.11469, 0.153649, 0.0672772, 0.0652416
Above is the output of epoch #996, #997,#998 and #999
So simply network is not learning. For this e.g. I have used ALPHA = 0.4, ETA = 0.7, 10 hidden layers each of 100 neurons and average is over 10 epochs. If you are worried about Learning Rate being 0.4 or so many hidden layers I have already tried their variations. For e.g. for learning rate being 0.1 and 4 hidden layers - each of 16
Input = [0, 0, 0, 0, 0, 0, 1, 0, 0, 0]
Output = 0.0883238, 0.0983253, 0.0613749, 0.0809751, 0.124972, 0.0897194, 0.0911235, 0.179984, 0.0681346, 0.0660039
Input = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Output = 0.0868767, 0.0966924, 0.0612488, 0.0798343, 0.120353, 0.0882381, 0.111925, 0.169309, 0.0676711, 0.0656819
Input = [0, 0, 0, 1, 0, 0, 0, 0, 0, 0]
Output = 0.105252, 0.0943837, 0.0604416, 0.0781779, 0.116231, 0.0858496, 0.108437, 0.1588, 0.0663156, 0.0645477
Input = [0, 0, 0, 0, 0, 0, 1, 0, 0, 0]
Output = 0.102023, 0.0914957, 0.059178, 0.09339, 0.111851, 0.0842454, 0.104834, 0.149892, 0.0651799, 0.063558
I am so damn sure that I have missed something. I am not able to figure it out. I have read Tom Mitchel's algorithm so many times, but I don't know what is wrong. Whatever example I solve by hand - works! (Please don't ask me to solve MNIST data images by hand ;) ) I do not know where to change the code, what to do.. please help out..
EDIT -- Uploading more data as per suggestions in comments
1 Hidden Layer of 32 -- still no learning.
Expected Output -- Input is images between 0-9, so a simple vector describing which is current image, that bit is 1 all others are 0. So i would want output to be as close to 1 for that particular bit and others being close to 0 For e.g. if input is Input = [0, 0, 0, 0, 0, 0, 1, 0, 0, 0] I would want output to be something like Output = 0.002023, 0.0914957, 0.059178, 0.09339, 0.011851, 0.0842454, 0.924834, 0.049892, 0.0651799, 0.063558 (THis is vague, hand-generated)
Here are the links of other researcher's work.
Stanford
SourceForge -- This is rather a library
Not only these 2, there are so many sites showing the demos.
Things are working quite fine for them. If I set my network parameters(Alpha, ETA) like them I am not getting results like them, so this is reassurance that something is wrong with my code.
EDIT 2
Adding more failure cases
Accelaration - 0.7, Learning Rate 0.1
Accelaration - 0.7, Learning Rate 0.6
In both of the above cases Hidden layers were 3, each of 32 neurons.
This answer is copied from the OP's comment on the question.
I solved the puzzle. I had made the worst possible mistake. I was giving wrong input. I have used opencv to scan the images, instead of using reshape I was using resize and so input was linear interpolation of images. So my input was wrong. There was nothing wrong with the code. My network is 784 - 65 - 10 giving 96.43% accuracy.
I want to access image pixels as float array in opencv. Ive done the following:
Mat input = imread("Lena.jpg",CV_LOAD_IMAGE_GRAYSCALE);
int height = input.rows;
int width = input.cols;
Mat out;
input.convertTo(input, CV_32FC1);
copyMakeBorder(input, input, 3, 3, 3, 3, 0);
out = Mat(height, width, input.type());
float *outdata = (float*)out.data;
float *indata = (float*)input.data;
for(int j = 0; j < height; j++){
for(int i =0; i < width; i++){
outdata[j*width + i] = indata[(j* width + i)];
}
}
normalize(out, out,0,255,NORM_MINMAX,CV_8UC1);
imshow("output", out);
waitKey();
This should return the original image in "out", however, I'm getting some weird image. Can anyone explain whats wrong with the code. I think i need to use some step size (widthStep). Thanks.
the line
copyMakeBorder(input, input, 3, 3, 3, 3, 0);
changes the dimensions of input, it adds 6 rows and 6 columns to the image. That means your height and width variables are holding the wrong values when you define out and try to loop over the values on input.
if you change the order to
copyMakeBorder(input, input, 3, 3, 3, 3, 0);
int height = input.rows;
int width = input.cols;
it should work fine.
Some ideas:
Something like outdata[j*width + i] is a more standard pattern for this sort of thing.
According to the opencv documentation, there is a templated Mat::at(int y, int x) method that allows you to access individual elements of a matrix.
float f = input.at<float>(0, 0);
Note that this requires that your underlying matrix type is float -- it won't do a conversion for you.
Alternatively, you could access the data row-by-row, as in this example that sums up the positive elements of a matrix M of type double:
double sum=0;
for(int i = 0; i < M.rows; i++)
{
const double* Mi = M.ptr<double>(i);
for(int j = 0; j < M.cols; j++)
sum += std::max(Mi[j], 0.);
}
If none of these work, I'd suggest creating a small matrix with known values (e.g. a 2x2 matrix with 1 black pixel and 3 white pixels) and use that to help debug your code.
To really make it apparent what the problem is, imagine a 16 by 16 image. Now think of pixel number 17 in the linear representation.
17 is a prime number. There is no j*i that will index your source image at pixel 17 if the row or column width is 16. Thus elements like 17, 19, 23 and so on will be uninitialized or at best 0, resulting in a "weird" output.
How about pixel 8 in the linear representation? that one in contrast will get hit by your loop four times, i.e. by 1x8, 2x4, 4x2, and 8x1!
The indexing #NateKohl presents in his answer will fix it since he multiplies a row position by the length of the row and then simply walks along the columns.
You can try this loop...
for(int row=0;row<height;row++)
{
for(int col=0;col<width;col++)
{
float float_data = input.at<float>(row,col);
// do some processing with value of float_data
out.at<float>(row,col) = float_data;
}
}
Is there a need to cast the uchar pointers of input and out Mats to float pointers?
Currently I'm learning C++ and I've been trying to create a simple image processing library for learning purposes.
One of my features is eroding an image. As input it has two 2d arrays, and it returns another 2d array. All these arrays are of variable size. Let's give you an example of what I want to achieve.
int image[5][5] =
{
{'0', '0', '0', '0','0'},
{'0', '1', '1', '1','0'},
{'0', '0', '1', '0','0'},
{'0', '1', '1', '1','0'},
{'0', '0', '1', '0','0'},
};
int kernel[3][3] =
{
{'0', '1', '0'},
{'1', '1', '1'},
{'0', '1', '0'},
};
Then I want to pass them to my function (this doesn't compile, but it serves as an example of what I want).
int** erode(int image[][], int kernel[][]);
So far, I've read quite a bit about this. All I've read is that the columns can be of variable length, but the rows can't. So I should be change it to the following:
int** erode(int image[][5], int kernel[][3]);
But that's not really want I want either, because well, the image can be 10*10 and the kernel could be 5*5. So this isn't optimal in this situation either.
Then what I've read is creating a class, that internally stores the image as a 1d array and makes it look like a 2d array. Also I've read about using the Boost.MultiArray class to do this. But well I'm not too happy about that either. Because then I'm forcing the people that use it to also use those classes. And I think it's creating a lot of complexity for something that seems really simple (at least it is in C#)
To be honest, I can't imagine there isn't an easier way to do this. Optimally I'd say only use classes/methods from the standard C++11 library. How would you solve this problem?
Timo
see if you can use templates, eg:
template<int N>
void f(int (&arr)[N][N]);
if arrays have compile time bounds.
but really you should consider boost, armadillo, or tvmet
I would pass the array as a pointer and also pass another parameter which defines the size of the array.
int** erode(int* image, size_t imageSize, int* kernel, size_t kernelSize);
An array is just a list of consecutive variables when in memory and the array variable such as image[5][5] just points to the first element of the array. To pass the arrays you have shown into the function you would use.
int** ret = errode(image, 5, kernel, 3);
Be careful when using this however because it could easily cause a segmentation fault but when used correctly, it will be fine. Also this assumes that the array is square, to overcome this limitation just pass in another parameter which describes the other dimension of the array.
Update
I see Anycorn has posted a very nice solution. His is a safer solution however will require you knowing the size of the array at compile time. If this is the case I would recommend you use what he has said.
Returning a 2D vector is less complicated.
#include <vector>
#include <iostream>
using namespace std;
typedef std::vector<std::vector< int> > vector2D;
int image[5][5] =
{
{0, 0, 0, 0, 0},
{0, 1, 1, 1, 0},
{0, 0, 1, 0, 0},
{0, 1, 1, 1, 0},
{0, 0, 1, 0, 0},
};
int kernel[5][5] =
{
{0, 0, 0, 0, 0},
{0, 1, 1, 1, 0},
{0, 0, 1, 0, 0},
{0, 1, 1, 1, 0},
{0, 0, 1, 0, 0},
};
vector2D erode(int image[5][5], int kernel[5][5])
{
vector2D image_process_data ;
//create 2D vector array
image_process_data.resize(5);
for(int i = 0; i < 5; i++)
{
image_process_data[i].resize(5);
}
//perform calculations
for (int ix = 0; ix < 5; ix++)
{
for (int iy = 0; iy < 5; iy++)
{
image_process_data[ix][iy] = image[ix][iy] + kernel[ix][iy];
}
}
//return the 2D array
return image_process_data;
}
int main( )
{
vector2D new_image;
new_image = erode(image, kernel);
//display new_image
for (int ix = 0; ix < 5; ix++)
{
for (int iy = 0; iy < 5; iy++)
{
cout<<new_image[ix][iy]<<" ";
}
cout<<"\n";
}
return 0;
}
How to set up a 2D vector array:
#include <vector>
#include <iostream>
using std namespace;
#define HEIGHT 5
#define WIDTH 3
int main() {
vector<vector<double> > array2D;
// Set up sizes. (HEIGHT x WIDTH)
array2D.resize(HEIGHT);
for (int i = 0; i < HEIGHT; ++i)
array2D[i].resize(WIDTH);
// Put some values in
array2D[1][2] = 6.0;
array2D[3][1] = 5.5;
return 0;
}
What you wrote about internally storing 1D array is essentially the best solution. Using 2-dimensional array is usually dangerous and can easily lead to errors. If you don't want to create whole class, consider:
const int SizeX = 10, SizeY = 10;
int Array[SizeX*SizeY];
inline int& Get (int x, int y) { return Array[SizeX*y+x]; }
Of course, it is the very simple example, but usually solves a lot of errors.
struct MyOwnArray
{
int SizeX, int SizeY;
int* Data;
inline int& Get (int x, int y) { return Data[SizeX*y+x]; }
}
The code above will allow you to pass references to this struct in a convenient way. And it's only 6 lines of code!
Of course, the code above would need some more code; for example for allocating memory. However, if you carefully program all these parts, you will be pretty safe to use it and it should be well-protected from bugs.