How to copy a pixel buffer into a larger one - c++

I’m trying to copy a set of pixels into a larger pixel buffer. Clearly, I’m calculating the coordinates wrong, probably with the strides, but I can’t find what I’m missing. I get a completely messed up result.
So in essence, what I try to achieve is to copy a RGBA pixel array into a larger RGB array (alpha gets discarded), keeping the strides correctly. See the image below for a visual representation of the expected result.
void draw(const uint8_t* tileRGBA, uint8_t* canvasRGB, const int canvasStride,
const int tileWidth, const int tileHeight)
{
for (int y = 0; y < tileHeight; y++)
{
for (int x = 0; x < tileWidth; x++)
{
long tileIndex = (4 * x) + (y * tileWidth);
long canvasIndex = (3 * x) + (y * canvasStride);
canvasRGB[canvasIndex] = tileRGBA[tileIndex];
canvasRGB[canvasIndex + 1] = tileRGBA[tileIndex + 1];
canvasRGB[canvasIndex + 2] = tileRGBA[tileIndex + 2];
}
}
}
uint8_t* test(uint32_t* tileRGBA, const int tileWidth, const int tileHeight)
{
int canvasStride = tileWidth * 5; // 5 is just an arbitrary value for this example, in this case a canvas 5 times the width of the tile
uint8_t* canvasRGB = new uint8_t[canvasStride * tileHeight * 3];
draw((uint8_t*)tileRGBA, canvasRGB, canvasStride, tileWidth, tileHeight);
return canvasRGB;
}
SOLVED: Thanks to the comments of Johnny Mopp. It was a matter of brackets.
This:
long tileIndex = (4 * x) + (y * tileWidth)
long canvasIndex = (3 * x) + (y * canvasStride);
Must be really this:
long tileIndex = 4 * (x + y * tileWidth);
long canvasIndex = 3 * (x + y * canvasStride);

The problem is in your calculation of the indexes.
To get a 2D index (row,col) in a 1D array you would do:
index = ((number_of_columns * row) + col) * sizeof(data)
Where number_of_columns is the intended number of "columns" in the data - in this case the width of the image. And sizeof(data) is the size in bytes of one item in the array - in this case, 4 bytes for RGBA and 3 for RGB. So, as you have determined, it should be:
long tileIndex = 4 * (x + y * tileWidth);
long canvasIndex = 3 * (x + y * canvasStride);
You can do away with the sizeof multiplication if you can represent the data as a single item. For example, in your case, create 2 structs:
struct RGB {
uint8_t r,g,b;
};
struct RGBA {
uint8_t r,g,b,a;
};
Then pass the parameters as arrays of these structs:
void draw(const RGBA* tileRGBA, RGB* canvasRGB, const int canvasStride, const int tileWidth, const int tileHeight)
Then the calculation simplifies to:
long tileIndex = x + y * tileWidth;
long canvasIndex = x + y * canvasStride;

Related

Trying to use perlinnoise for generation of terrain

I am trying to generate a procedural terrain using perlin noise. Before, I was just creating a 1000 * 1000 vertice terrain so I just had a simple function that would fill the height map with the noise values.
However now I am trying to generate a terrain that generates chunks as the camera moves around and I don't think this method is suitable since each chunk would be generated with it's own random heightmap and chunks will not look consistant with eachother. Instead I am using this header file to generate noise which just takes and x and y but whatever values I give it does not seem to generate consistant values and I am not sure why
class Noise {
public:
int seed;
Noise(int seed) {
this->seed = seed;
}
float noise(int x, int y) {
int n = x + y * 57 + seed;
n = ( n << 13 ) ^ n;
float rand = 1 - ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0f;
return rand;
}
float noise(int x, int y, int z) {
int n = x + y + z * 57 + seed;
n = ( n << 13 ) ^ n;
float rand = 1 - ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0f;
return rand;
}
float smoothNoise(int x, int y) {
float corners = (noise(x+1, y+1) + noise(x+1, y-1) + noise(x-1, y+1) + noise(x-1, y-1)) / 16.0f;
float sides = (noise(x, y+1) + noise(x, y-1) + noise(x-1, y) + noise(x+1, y)) / 8.0f;
float center = noise(x, y) / 4.0f;
return corners + sides + center;
}
float interpolatedNoise(float x, float y) {
int integerX = (int)x;
float fractionalX = x - integerX;
int integerY = (int)y;
float fractionalY = y - integerY;
float v1 = smoothNoise(integerX, integerY);
float v2 = smoothNoise(integerX + 1, integerY);
float v3 = smoothNoise(integerX, integerY + 1);
float v4 = smoothNoise(integerX + 1, integerY + 1);
float i1 = interpolateCosine(v1, v2, fractionalX);
float i2 = interpolateCosine(v3, v4, fractionalX);
return interpolateCosine(i1, i2, fractionalY);
}
// x must be in the range [0,1]
float interpolateLinear(float a, float b, float x) {
return a * (1 - x) + b * x;
}
float interpolateCosine(float a, float b, float x) {
float ft = x * (float)glm::pi<float>();
float f = (1 - ((float)glm::pi<float>())) * 0.5f;
return a * (1 - f) + b * f;
}
};`
I am calling interpolatedNoise() like this:
for(int y=x; x < config->width;x++)
{
for(int y = 0; y < config->height;y++)
{
map[x * config->height + y] = noise.interpolatedNoise((config->width * gridPosX + x) * 0.1f,(config->height * gridPosY + y) * 0.1f)/2.0f + 0.5f; // convert from -1:1 to 0:1
}
}
This is what the terrain looks like using this
but I want the terrain to be smooth. The parameters I pass into the function are divided by some value. The larger I make this value for more random the terrain is with the boxes being smaller and the smaller I make it I just get larger boxes but a more consistant looking terrain.
I am not quite sure how you are calling your Noise constructor, but one problem I see is in the constructor. It should be this->seed = seed;, otherwise you are assigning the argument seed to the value of itself. The seed variable of Noise then would just be a random number, and I feel like that's causing problems. Again, not sure how your callling Noise constructor, but thats my best guess.

How to set a value at memory offset from a const void pointer?

I have a pointer returned from a function
rs2::video_frame frame = frames.get_color_frame();
const void* data = frame.get_data();
I know that this pointer is an array of RGB values (i.e. 3 chars) of size frame.get_data_size().
How can I modify certain pixel colors given that
int bpp = frame.get_bytes_per_pixel();
int width = frame.get_width();
int height = frame.get_height();
int offset = (y * width * bpp) + (x * bpp);
int r = offset;
int g = offset + 1;
int b = offset + 2;
// ?data[r] = newRed;
// ?data[g] = newGreen;
// ?data[b] = newBlue;
You would have it easier if you would have an object oriented approach:
struct Pixel {
short red;
short green;
short blue;
};
Let your frame work with an std::vector<Pixel> pixels; which is returned by reference. std::vector<Pixel>& get_data();
pixels[y * width + x].red = newRed;
pixels[y * width + x].green = newGreen;
pixels[y * width + x].blue = newBlue;
If you really have to work with void* then try this
char* data = static_cast<char*>(const_cast<void*>(dataframe.get_data()));
// Since you also const cast it becomes more and more dangerous. You really need know what you are doing.
size_t bpp = frame.get_bytes_per_pixel();
size_t width = frame.get_width();
size_t height = frame.get_height();
size_t offset = (y * width * bpp) + (x * bpp);
size_t r = offset;
size_t g = offset + 1;
size_t b = offset + 2;
*(data + r) = newRed;
*(data + g) = newGreen;
*(data + b) = newBlue;
For bulk updates you can use memset.
See https://godbolt.org/z/xvc1xs for details.

Matlab image converter issue

I want to use the output of Matlab coder for image processing. I created an c++ output from Matlab coder, I would like to use this code for integrating it into some other application. The problem is we dont know exactly how the Matlab coder generates the image matrix into const unsigned char[...]. It would be great help if there is any possibility in checking the way it is created. So that we can create the image into unsigned char[..], the same way and convert it back to image.
This is the code generated by Matlab
* multiplyImage.c
*
* Code generation for function 'multiplyImage'
*
*/
/* Include files */
#include "rt_nonfinite.h"
#include "multiplyImage.h"
/* Function Declarations */
static double rt_roundd_snf(double u);
/* Function Definitions */
static double rt_roundd_snf(double u)
{
double y;
if (fabs(u) < 4.503599627370496E+15) {
if (u >= 0.5) {
y = floor(u + 0.5);
} else if (u > -0.5) {
y = u * 0.0;
} else {
y = ceil(u - 0.5);
}
} else {
y = u;
}
return y;
}
void multiplyImage(const unsigned char img[2115216], double parameter, unsigned
char imgout[2115216])
{
int i0;
double d0;
unsigned char u0;
/* implements a function that multiplies an image with a parameter */
for (i0 = 0; i0 < 2115216; i0++) {
d0 = rt_roundd_snf(parameter * (double)img[i0]);
if (d0 < 256.0) {
if (d0 >= 0.0) {
u0 = (unsigned char)d0;
} else {
u0 = 0;
}
} else if (d0 >= 256.0) {
u0 = MAX_uint8_T;
} else {
u0 = 0;
}
imgout[i0] = u0;
}
}
/* End of code generation (multiplyImage.c) */
I have an issue converting the unsigned char from the cpp file to multidimensional array, according to suggestion given as followed. But I have to represent the data in the format of c[] w[] h[], I am confused how to represent the red, green, blue information into c[] from following. I am confused is this the right way to represent it (as you can see this function is intended to get a const unsigned char[]) and create an output with three dimension c[] w[] h[] matrix. Any help would be great
double Marvin_To_UnsignedChar::Convert_To_Marvin_Image(const unsigned char input[])
{
int Initial_Color;
for (int Initial_Height = 0; Initial_Height < Height; ++Initial_Height)
{
for (int Initial_Width = 0; Initial_Width < Width; ++Initial_Width)
{
int red [Initial_Height * Width + Initial_Width] = input[Initial_Width * Height + Initial_Height];
int green[Initial_Height * Width + Initial_Width] = input[Height * Width + Initial_Width * Height + Initial_Height];
int blue [Initial_Height * Width + Initial_Width] = input[2 * Height * Width + Initial_Width * Height + Initial_Width * Height + 1];
int color((red[Initial_Height * Width + Initial_Width]) (green[Initial_Height * Width + Initial_Width]) (blue[Initial_Height * Width + Initial_Width]));
double Marvin_Matrix([color][Width][Height]);
return Marvin_Matrix([color][Width][Height]);
}
}
}

Set Pixel colour in an array

I have an array of pixels stored in a vector as follows:
typedef union RGBA
{
std::uint32_t Colour;
struct
{
std::uint8_t R, G, B, A;
};
} *PRGB;
std::vector<RGBA> Pixels; //My pixels are read into this vector.
I process it using the following two functions. One is for reading, the other is for writing.
The read function takes an array of bytes and flips them and stores them into the struct above. It takes padding into consideration so it works for both 24 and 32 bit bitmaps. The write function flips it back and writes it to an array of bytes.
void ReadPixels(const std::uint8_t* In, RGBA* Out)
{
for (std::size_t I = 0; I < height; ++I)
{
for (std::size_t J = 0; J < width; ++J)
{
Out[(height - 1 - I) * width + J].B = *(In++);
Out[(height - 1 - I) * width + J].G = *(In++);
Out[(height - 1 - I) * width + J].R = *(In++);
Out[(height - 1 - I) * width + J].A = (BitsPerPixel > 24 ? * (In++) : 0xFF);
}
if(BitsPerPixel == 24)
In += (-width * 3) & 3;
}
}
void WritePixels(const RGBA* In, std::uint8_t* Out)
{
for (std::size_t I = 0; I < height; ++I)
{
for (std::size_t J = 0; J < width; ++J)
{
*(Out++) = In[(height - 1 - I) * width + J].B;
*(Out++) = In[(height - 1 - I) * width + J].G;
*(Out++) = In[(height - 1 - I) * width + J].R;
if (BitsPerPixel > 24)
*(Out++) = In[(height - 1 - I) * width + J].A;
}
if(BitsPerPixel == 24)
Out += (-width * 3) & 3;
}
}
The thing is, if I want to change just one pixel in the array, I have to flip and copy the whole image into the vector, change the pixel using:
inline void SetPixel(int X, int Y, std::uint32_t Color)
{
Pixels[Y * width + X].Colour = Color;
}
And then flip it back into the array. Is there a better way to change a single pixel in the array without having to do this every single time?
I tried this formula (so that padding is taken into consideration):
ByteArray[((height - 1 - Y) * width + X) + (Y * ((-width * 3) & 3))] = Color;
But it doesn't work. Any ideas?
Your subscript->index formula looks all wrong.
Perhaps:
int stride = width * BitsPerPixel/8;
stride = ((stride - 1) & ~3) + 4; // round up to multiple of 4 bytes
RGBQUAD& selected_pixel = *reinterpret_cast<RGBQUAD*>(array + stride * (height - 1 - Y)) + X * BitsPerPixel/8);
selected_pixel.R = ...
...

How to optimize this code?

Profiler says that 50% of total time spends inside this function. How would you optimize it?
It converts BMP color scheme to YUV. Thanks!
Update: platform is ARMV6 (writing for IPhone)
#define Y_FROM_RGB(_r_,_g_,_b_) ( ( 66 * _b_ + 129 * _g_ + 25 * _r_ + 128) >> 8) + 16
#define V_FROM_RGB(_r_,_g_,_b_) ( ( 112 * _b_ - 94 * _g_ - 18 * _r_ + 128) >> 10) + 128
#define U_FROM_RGB(_r_,_g_,_b_) ( ( -38 * _b_ - 74 * _g_ + 112 * _r_ + 128) >> 10) + 128
/*!
* \brief
* Converts 24 bit image to YCrCb image channels
*
* \param source
* Source 24bit image pointer
*
* \param source_width
* Source image width
*
* \param dest_Y
* destination image Y component pointer
*
* \param dest_scan_size_Y
* destination image Y component line size
*
* \param dest_U
* destination image U component pointer
*
* \param dest_scan_size_U
* destination image U component line size
*
* \param dest_V
* destination image V component pointer
*
* \param dest_scan_size_V
* destination image V component line size
*
* \param dest_width
* Destination image width = source_width
*
* \param dest_height
* Destination image height = source image height
*
* Convert 24 bit image (source) with width (source_width)
* to YCrCb image channels (dest_Y, dest_U, dest_V) with size (dest_width)x(dest_height), and line size
* (dest_scan_size_Y, dest_scan_size_U, dest_scan_size_V) (in bytes)
*
*/
void ImageConvert_24_YUV420P(unsigned char * source, int source_width,
unsigned char * dest_Y, int dest_scan_size_Y,
unsigned char * dest_U, int dest_scan_size_U,
unsigned char * dest_V, int dest_scan_size_V,
int dest_width, int dest_height)
{
int source_scan_size = source_width*3;
int half_width = dest_width/2;
//Y loop
for (int y = 0; y < dest_height/2; y ++)
{
//Start of line
unsigned char * source_scan = source;
unsigned char * source_scan_next = source+source_scan_size;
unsigned char * dest_scan_Y = dest_Y;
unsigned char * dest_scan_U = dest_U;
unsigned char * dest_scan_V = dest_V;
//Do all pixels
for (int x = 0; x < half_width; x++)
{
int R = source_scan[0];
int G = source_scan[1];
int B = source_scan[2];
//Y
int Y = Y_FROM_RGB(B, G, R);
*dest_scan_Y = Y;
source_scan += 3;
dest_scan_Y += 1;
int R1 = source_scan[0];
int G1 = source_scan[1];
int B1 = source_scan[2];
//Y
Y = Y_FROM_RGB(B1, G1, R1);
R += (R1 + source_scan_next[0] + source_scan_next[3]);
G += (G1 + source_scan_next[1] + source_scan_next[4]);
B += (B1 + source_scan_next[2] + source_scan_next[5]);
//YCrCb
*dest_scan_Y = Y;
*dest_scan_V = V_FROM_RGB(B, G, R);
*dest_scan_U = U_FROM_RGB(B, G, R);
source_scan += 3;
dest_scan_Y += 1;
dest_scan_U += 1;
dest_scan_V += 1;
source_scan_next += 6;
};
//scroll to next line
source += source_scan_size;
dest_Y += dest_scan_size_Y;
dest_U += dest_scan_size_U;
dest_V += dest_scan_size_V;
//Start of line
source_scan = source;
dest_scan_Y = dest_Y;
//Do all pixels
for (int x = 0; x < half_width; x ++)
{
int R = source_scan[0];
int G = source_scan[1];
int B = source_scan[2];
//Y
int Y = Y_FROM_RGB(B, G, R);
*dest_scan_Y = Y;
source_scan += 3;
dest_scan_Y += 1;
R = source_scan[0];
G = source_scan[1];
B = source_scan[2];
//Y
Y = Y_FROM_RGB(B, G, R);
*dest_scan_Y = Y;
source_scan += 3;
dest_scan_Y += 1;
};
source += source_scan_size;
dest_Y += dest_scan_size_Y;
};
};
Unless I am missing something the follow code seems to be repeated in both loops, so, why not go through this loop once? This may require some changes to your algorithm, but it would improve performance.
for (int x = 0; x < half_width; x ++)
{
int R = source_scan[0];
int G = source_scan[1];
int B = source_scan[2];
//Y
int Y = Y_FROM_RGB(B, G, R);
*dest_scan_Y = Y;
source_scan += 3;
dest_scan_Y += 1;
R = source_scan[0];
G = source_scan[1];
B = source_scan[2];
But, before doing anything, move the two inside loops into separate functions, and then run your profiler, and see if you spend more time in one function than the other.
You have three loops in this function, and you don't know which section is actually where you are spending your time. So determine that before doing any optimization, otherwise you may find that you are fixing the wrong section.
I don't know what platform you are using but you might want to look SIMD
Arm Cotext-A8 has Neon technology that does support SIMD. You should be able to find more information on the ARM website.
Presuming that the memory they point to does not overlap, you should declare your source, dest_Y, dest_U and dest_V pointers with the restrict qualifier, to tell the compiler this and allow it to optimise better.