Many faces of 2d image visualization

Some tips about 2d visualization based on image.

RGBs and RsGsBs

When we look at one colored image with width*height pixels, there are actually three layers (red, green and blue). We can get colorful results when we blend these three values properly on screen.

There are two typical ways to store each pixel value, store results separately, such as RRRR…GGGG…BBBB we use RGBs to represent it, we store each channel separately. Another way is store it by RGBs namelly RGBRGBRGB… we need to know the how the data is stored in memory before we give image to specific paiting library.

Number of channels

Typical way is RGB for three channels and RGBA for four channels. The A value represents the alpha value which shows the transparency of each pixel. Using RGBA as an example, there are usually 4*8bit=32bit=4Bfor each pixle.

Using Cario as 2d painter example

Depending on little endian and small endian, the sequence of data can be different. For small endian, the first data is put from low memory address to high memory address. For big endian mode, the data is put into the high memory address firstly and then small address.

For cario RGB24, and the data is small endian, we actually put bbbbbbbbggggggggrrrrrrrr in memory (left is high memory address and right is low memory address)

TODO, add cario little small endian pattern

PPM data format

If we just want to input/output data for simple checking, we can use PPM as format, which is just naive way to write out the RGBA data format without encoding etc.

This is a simple code snippet for read the ppm data based on icet, if the original data buffer stores the rgb, we use offset=3 here, otherwise, if original data struct is rgba, we use offset=4. We can see that when writting out the ppm data, we do not include the alpha value in it (or assuming alpha is 1)

void write_ppm(const char *filename, unsigned char *image, int width, int height, int offset)
{
FILE *fd;
int x, y;
const unsigned char *color;
#ifndef _WIN32
fd = fopen(filename, "wb");
#else /*_WIN32*/
fopen_s(&fd, filename, "wb");
#endif /*_WIN32*/

fprintf(fd, "P6\n");
fprintf(fd, "# %s generated by IceT test suite.\n", filename);
fprintf(fd, "%d %d\n", width, height);
fprintf(fd, "255\n");

for (y = height - 1; y >= 0; y--)
{
color = image + y * width * offset;
for (x = 0; x < width; x++)
{
// rgb
fwrite(color, 1, 3, fd);
color += offset;
}
}
fclose(fd);
}

以下是从ppm文件读取RGBA buffer的相关代码,动态决定alpha值,对于背景部分,设置alpha值为0,对于非背景部分,设置alpha值为255:

#define RGB_COMPONENT_COLOR 255
unsigned char *readPPM(const char *filename, int &w, int &h)
{
char buff[16];
FILE *fp;
int c, rgb_comp_color;
// open PPM file for reading
fp = fopen(filename, "rb");
if (!fp)
{
fprintf(stderr, "Unable to open file '%s'\n", filename);
exit(1);
}
// read image format
if (!fgets(buff, sizeof(buff), fp))
{
perror(filename);
exit(1);
}
// check the image format
if (buff[0] != 'P' || buff[1] != '6')
{
fprintf(stderr, "Invalid image format (must be 'P6')\n");
exit(1);
}
// check for comments
c = getc(fp);
while (c == '#')
{
while (getc(fp) != '\n');
c = getc(fp);
}
ungetc(c, fp);
// read image size information
if (fscanf(fp, "%d %d", &w, &h) != 2)
{
fprintf(stderr, "Invalid image size (error loading '%s')\n", filename);
exit(1);
}
// read rgb component
if (fscanf(fp, "%d", &rgb_comp_color) != 1)
{
fprintf(stderr, "Invalid rgb component (error loading '%s')\n", filename);
exit(1);
}
// check rgb component depth
if (rgb_comp_color != RGB_COMPONENT_COLOR)
{
fprintf(stderr, "'%s' does not have 8-bits components\n", filename);
exit(1);
}
while (fgetc(fp) != '\n');
// memory allocation for pixel data
std::cout << "get w " << w << " h " << h << std::endl;
// assuming the return img using rgba to represent each pixel
unsigned char *img = (unsigned char *)malloc(w * h * 4 * sizeof(unsigned char));
if (!img)
{
fprintf(stderr, "Unable to allocate memory\n");
exit(1);
}
//for each row
for (int y = h - 1; y >= 0; y--)
{
//for each column, the color is set to the start
//position for a new pixel
unsigned char* color = img + y * w * 4;
for (int x = 0; x < w; x++)
{
// read three value from file stream
fread(color, 1, 3, fp);
// the background should be set to 0 0 0 0
if (*color == 0 && *(color + 1) == 0 && *(color + 2) == 0) {
// this is the bg region
*(color + 3) = 0;
}
else {
//this is not the bg region, we set alpha value as 255
//which is all 1 for each bit in this byte
*(color + 3) = 255;
}
color += 4;
}
}
fclose(fp);
return img;
}

NC data

NC data can be viewed as a kind of rectilinear grid. NC data itsself is flexible, but in geo related simulation, each point in 2d is a combination of latitude and longitude, we can simply use the Panoply to show the results, and use image show in python script to draw the results directly.

推荐文章