Reputation: 2945
I receive some image data as unsigned char *image = load_image(…);
This data is a 3D matrix: x
(char),y
(char) and channel (RGB)
(char).
How can I access each element as image[x][y][channel]
by overloading []
? E.g. row 999, column 10000, green channel: image[999][10000][1]
Clarifications:
I'd like to use C multi-dimensional array syntax: array[x][y][z]
, not array[x * height * channels + y * channels + z]
I can access a 1D array as a 2D array:
unsigned char (*imageMatrix)[height] = (unsigned char (*)[height])image
imageMatrix[x][y] = 100
I already asked how to do it in pure C. Here I want to know how it can be better achieved in C++.
Upvotes: 3
Views: 525
Reputation: 961
You can create Image
class with a function that will get what you want
class Image {
int imgSize;
char * img;
public:
Image(): imgSize(0), img(nullptr) {}
Image(char* image, int size): imgSize(size), img(image) {}
char getPixel(int x, int y, int z) {
if(x < imgSize && y < imgSize && z < imgSize) {
return img[x * imgSize * imgSize + y * imgSize + z];
} else {
// Error
}
}
char operator(int x, int y, int z) {
// The same as getPixel
}
}
getPixel
is in my opinion the best approach because whenever you call it, you (and people working with your code) will exactly know what you do thanks to its name (even after 6 months you will immediately know you get a pixel). Overloading operator()
is also a good approach, but I wouldn't use it were it to cause confusion or unwanted behavior. Both hide the internal structure of your class and don't require any proxy classes.
Overloading operator[]
is an option, but to support chaining like [][][]
you need proxy classes which will badly affect the performance of your code if not designed correctly.
You can read C++ FAQ to learn more.
Upvotes: 3
Reputation: 206557
How can I access each element as
image[x][y][channel]
by overloading[]
?
When you overload an array operator for the image class, it can only support the syntax image[x]
in its interface.
In order to be able to support image[x][y]
, image[x]
needs to return an object or a reference to an object that needs to support the array operator.
In order to be able to support image[x][y][z]
, image[x][y]
needs to return an object or a reference to an object that needs to support the array operator.
Here's a sample program that demonstrates how it can be done.
Disclaimer Please note that this is not production ready code.
#include <iostream>
#include <cassert>
struct Image
{
Image(unsigned int x,
unsigned int y,
unsigned int z) : x_(x), y_(y), z_(z), data(new unsigned char [x*y*z]) {}
// Need appropriate copy constructor and destructor.
// Helper classes to support the 3D array operator syntax.
struct image_2
{
image_2(Image& im, unsigned i, unsigned j) : im_(im), i_(i), j_(j) {}
unsigned char& operator[](unsigned k)
{
assert( k < im_.z_ );
unsigned int index = i_*im_.y_*im_.z_ + j_*im_.z_ + k;
return im_.data[index];
}
Image& im_;
unsigned int i_;
unsigned int j_;
};
struct image_1
{
image_1(Image& im, unsigned i) : im_(im), i_(i) {}
image_2 operator[](unsigned int j)
{
assert( j < im_.y_ );
return image_2(im_, i_, j);
}
Image& im_;
unsigned int i_;
};
// The toplevel array operator
image_1 operator[](unsigned i)
{
assert( i < x_ );
return image_1(*this, i);
}
unsigned x_;
unsigned y_;
unsigned z_;
unsigned char* data;
};
int main()
{
unsigned int x = 5;
unsigned int y = 5;
unsigned int z = 3;
Image im(5, 5, 3);
for ( unsigned int i = 0; i < x; ++i )
{
for ( unsigned int j = 0; j < y; ++j )
{
for ( unsigned int k = 0; k < z; ++k )
{
// Set some arbitrary value
im[i][j][k] = (i+1) + (j+1)*5 + (k+1)*5;
// Get the value
std::cout << (int)im[i][j][k] << " ";
}
std::cout << std::endl;
}
}
}
Output:
11 16 21
16 21 26
21 26 31
26 31 36
31 36 41
12 17 22
17 22 27
22 27 32
27 32 37
32 37 42
13 18 23
18 23 28
23 28 33
28 33 38
33 38 43
14 19 24
19 24 29
24 29 34
29 34 39
34 39 44
15 20 25
20 25 30
25 30 35
30 35 40
35 40 45
Upvotes: 0