This is regarding unpacking the encoded rgb values in a pcl file. I did this with the procedure described in the pcl documentation, but the unpacked rgb values I get are not quite correct. When I plot them with R the representation given does not correspond to the colors in the real setting (I am to a certain degree sure the problem is not with the way it was plotted with R).
For example in the image attached the area demarcated should have colors gray and blue (two chairs and a table).
Source pcl file could be found at: https://docs.google.com/open?id=0Bz5-HVcDiF6SanBZU0JWVmJwWHM and the
file with the unpacked color values at: https://docs.google.com/open?id=0Bz5-HVcDiF6SV2pYQ0xUbTAwVmM. Also following is the code used for unpacking the color values in a c plus plus setting:
uint32_t rgbD = *reinterpret_cast<int*>(&kinectValue);
uint16_t rD = (rgbD >> 16) & 0x0000ff;
uint16_t gD = (rgbD >> 8) & 0x0000ff;
uint16_t bD = (rgbD) & 0x0000ff;
I would really appreciate if you could let me know where I have gone wrong.
Update:
Following is the R code snippet I used in plotting the values in 3D:
library(rgl)
pcd <- read.table(file.choose(),sep="")
names(pcd) <- c("x","y","z","r","g","b")
plot3d(pcd$x,pcd$y,pcd$z,col=rgb(pcd$r,pcd$g,pcd$b,maxColorValue=255))
Update:
Following is the code I used to read data, in C++:
/*
Reads in a file from Kinect with unpacked color values, filter the color value component and
sends it to be unpacked
*/
int fileRead(){
string line;
int lineNum = 0;
ifstream myfile ("res/OnePerson4.pcd");
if (myfile.is_open())
{
while ( myfile.good() )
{
lineNum++;
getline (myfile,line);
// Exclude the header information in the kinect file from the unpacking process
//if(lineNum > 10 && lineNum <20){//This for loop is activated when testing
if(lineNum > 10){
//Test code to extract the x,y,z values
string xyzvalFromKinectStr = line.substr(0,line.find_last_of(' '));
//cout<<xyzvalFromKinectStr<<"\n";
//Extract the packed rgb value
string valFromKinectStr = line.substr(line.find_last_of(' '));
double kinectVal = ::atof(valFromKinectStr.c_str());
kinectToRgb(kinectVal, xyzvalFromKinectStr);
}
}
myfile.close();
}
else
{
cout << "Unable to open file";
}
return 0;
}
Here's my working solution. First I ran your input through grep to filter out NANs in coordinates:
$ grep -v nan OnePerson4.pcd > OnePerson4.pcd.filtered
Then I extracted the data via C++ code like this:
#include <stdio.h>
int main()
{
if (FILE *f = fopen("OnePerson4.pcd.filtered", "rt"))
{
for (;;)
{
float x = 0;
float y = 0;
float z = 0;
float color_float = 0;
if (fscanf(f, "%f %f %f %f", &x, &y, &z, &color_float) != 4)
{
break;
}
unsigned color = *(unsigned const *)&color_float;
unsigned r = color & 0xff;
unsigned g = (color >> 8) & 0xff;
unsigned b = (color >> 16) & 0xff;
printf("%f,%f,%f,%d,%d,%d\n", x, y, z, r, g, b);
}
fclose(f);
}
return 0;
}
I didn't know in which byte order RGB is stored, so you might have to swap R and B. It's usually either RGB or BGR.
Then I used your code to plot the points (I changed read.table to read.csv):
library(rgl)
pcd <- read.csv(file.choose())
names(pcd) <- c("x","y","z","r","g","b")
plot3d(pcd$x,pcd$y,pcd$z,col=rgb(pcd$r,pcd$g,pcd$b,maxColorValue=255))
And this is what I get:
So I'm assuming the problem is with the code where you read your color from the pcd file. The rest looks fine to me.
Update: Your problem is the double type. Change it to float and it should work. Though storing unsigned int as a float is, at the very least, questionable. This is fragile and doesn't not guarantee the colors would be correct after you read them. Some bits might be off.
Another note: you could use >> stream operator to extract numbers from the file. It's much easier than manually parsing it with string methods. You can read about it, for example, here.
Related
I am working on rendering some volume data via cuda v6.5 sample code - volumeRender. I have some voxel data with different RGB color in another program. I want to render them by outputing them to .raw file format. However, how to output the exact same .raw format as input .raw file in volumeRender is confusing me a lot.
In my knowledgement, a .raw file can contain an array of volume data.
I tried to open .raw file, named "Bucky.raw" , in volumrRender, with text editor, but it didn't work. The text was garbled text. So I have no clue of the format of the .raw file.
Next, I tried to read sample code and figure out how the .cpp file read this format. The only information I get was the volume size. It is
unsigned char * width * height * depth.
Dose that mean each voxel data is represented by only one unsigned char? What does this unsigned char mean? Is it the gray scale of voxel?
I tried to output gray scale of my voxel RGB data, but the result is quite wired like below.
At the top is my voxel data and visualize by PCL. The other is the render result.
Obviously, it's the wrong format for the volumeRender program.
I know there are lots of different formats of .raw files, but I think maybe there is only one kind of .raw format just for cuda sample code.
Does anyone know how to store .raw format just like "Bucky.raw" format?
Does that mean each voxel data is represented by only one unsigned char? What does this unsigned char mean? Is it the gray scale of voxel?
Yes, each voxel is represented by one unsigned char (i.e. VolumeType), the value (0-255) represents the "transmissivity" of the voxel (i.e. the inverse of the density), with a voxel value of 0 being the lowest transmissivity/highest "density" (creating "darker" areas) and voxel value of 255 being low density (creating "brighter" areas).
The storage order has a rapidly varying dimension in x, then y, then z. The actual dimensions of the volume can be easily discovered in the program as volumeSize.width (x), volumeSize.height (y), and volumeSize.depth (z). x represents the horizontal direction, y the vertical, and z represents the direction into or out of the screen.
Does anyone know how to store .raw format just like "Bucky.raw" format?
Here is a program you can use to experiment with writing different kinds of "Bucky.raw" files. The dimensions will be 32,32,32 which is the default values in the program.
If you compile this program, then run it with a command line parameter of 0-4, you can see different patterns when you run the volumeRender sample code.
cat buckywriter.cpp
#include <fstream>
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
const int sz = 32;
const int method_max = 4;
int myfunc(int x, int y, int z, int method){
switch (method){
case 0:
return x;
break;
case 1:
return y;
break;
case 2:
return z;
break;
case 3:
return x+y;
break;
case 4:
return (x+y)*2*((z+1)/float(sz));
break;
default:
return x;
break;
}
return 0;
}
int main(int argc, char *argv[]){
int method = 0;
if (argc > 1) method = atoi(argv[1]);
ofstream fout;
string foname("Bucky.raw");
fout.open(foname.c_str());
if (!fout) {std::cout << "file open failed" << std::endl; return 1;}
for (int z = 0; z < sz; z++)
for (int y = 0; y < sz; y++)
for (int x = 0; x < sz; x++)
fout << (unsigned char)(myfunc(x, y, z, method));
if (!fout) {std::cout << "file write failed" << std::endl; return 1;}
fout.close();
return 0;
}
$ g++ buckywriter.cpp -o buckywriter
$ ./buckywriter 3
$ ./volumeRender
This is the graphical output for the above buckywriter 3 case, which creates an increasing transmissivity gradient in x and y:
I created a simple example program in Swift using Xcode that will convert a Goxel model into the .raw format used by the NVIDIA CUDA example programs VolumeRender and VolumeFilter.
Build a model in Goxel, export it as .txt
Then run it through the Goxel2Raw program.
Goxel2Raw on Github
I'm developing a uni project for reading the image data of P6-type, 255-depth .ppm images. The problem I encounter is that when I try to print the average values of each color (R,G,B) for an Image, the output I get is wrong (the proffessor has given us an output file which says what float values to expect for each given image).
Now, I'm at a loss here. Through many checks, I have concluded that the function reads the whole data from the image, without leaving out pixels or whatever, converts them correctly from 0-255 to 0.f - 1.f values (by dividing with 255.0), adds every red, every green and every blue value to three seperate counters and then divides them by the Width*Height of the given image to get the desired average brightness of each colour. I will provide part of the function that does this process for calculating the average red for a 960*642 Image (sorry for the hardcoded stuff, it's just there for debugging purposes).
The output I get for this is 0.58... when it should be 0.539068. seekg() is called with 14 as an argument because position 14 is the last space after the header and before the data. Could you provide any insight to why this isn't working as expected? One thing I found through the checks is the sum I get after adding all the red float values, is not a float but an int. Possible loss of data? I'm grasping at straws here.
Here is the code:
std::ifstream infile;
infile.open("Image02.ppm", std::ios::in | std::ios::binary);
const unsigned char* buffer;
float * data_ptr;
infile.seekg(0, std::ios::end);
int length = infile.tellg(); //calculating length of data
buffer = new unsigned char[length];
ptr = new unsigned char[length];
data_ptr = new float[length];
infile.seekg(14, std::ios::beg); //restoring pointer to the start of data stream
infile.read((char*)buffer, length); //reading the image
for (int i = 0; i < length; i++){ //casting the char data to floats to get the 0-255 values
data_ptr[i] = ((float)buffer[i]);
data_ptr[i] = data_ptr[i] / 255.f; // converting to 0.0 - 1.0
}
int j = 0;
float a = 0.f;
while (j < length){ //calculating sum of red pixel values
a = a + data_ptr[j];
j = j + 3;
}
std::cout << a / (960*642); //calculating average
FYI, PPM image files that are P6 have their image data stored from left to right, with the first line being line 0 and the last line of the image being the last. They are structured like this R G B R G B R G B so on, where the first RGB correspond to the first pixel and so forth.
Thanks in advance!
You need pixels only for average calculation.
But in your source code, additional 14 garbage values are being used.
During the encoding process with x265 encoder (https://x265.readthedocs.org/en/default/api.html) I want to write image pixel values (specifically values of Y channel) into .txt file after a new image is encoded (not important why). For that, I'm using 'planes' variable of class x265_picture:
x265_picture* pic_out; # variable where encoded image is to be stored
... # encoding process
uint8_t *plane = (uint8_t*)pic_out->planes[0];
uint32_t pixelCount = x265_picturePlaneSize(pic_out->colorSpace, m_param->sourceWidth, m_param->sourceHeight, 0);
ofstream out_file("out_file.txt");
for (uint32_t j = 0; j < pixelCount; j++) # loop for all pixels
{
int pix_val = plane[j];
out << pix_val;
}
ofstream.close()
But when I reconstruct the output data into image, I get
instead of
or another example:
instead of
(color is not important, the "stripes" are the concern)
In the output file there seem to be intervals of data in (apparently) correct order (let's say 89,90,102,98,...) followed always by long sequence of equal numbers (eg. 235,235,235,235... or 65,65,65,65...), that "create" the stripes. Could someone please tell me what I'm missing?
thanks guys, just solved this...the key is using 'src += srcStride':
ofstream out_file("out_file.txt");
int srcStride = pic_out->stride[0] / sizeof(pixel);
uint8_t* src = (uint8_t*) pic_out->planes[0];
for (int y = 0; y < m_param->sourceHeight; y++, src += srcStride)
{
for (int x = 0; x < m_param->sourceWidth; x++)
out_file << (int)(src[x]) << ",";
}
out_file.close();
I'd like to write a normal map to a .bmp file, so I've implemented a simple .bmp writer first:
void BITMAPLOADER::writeHeader(std::ofstream& out, int width, int height)
{
BITMAPFILEHEADER tWBFH;
tWBFH.bfType = 0x4d42;
tWBFH.bfSize = 14 + 40 + (width*height*3);
tWBFH.bfReserved1 = 0;
tWBFH.bfReserved2 = 0;
tWBFH.bfOffBits = 14 + 40;
BITMAPINFOHEADER tW2BH;
memset(&tW2BH,0,40);
tW2BH.biSize = 40;
tW2BH.biWidth = width;
tW2BH.biHeight = height;
tW2BH.biPlanes = 1;
tW2BH.biBitCount = 24;
tW2BH.biCompression = 0;
out.write((char*)(&tWBFH),14);
out.write((char*)(&tW2BH),40);
}
bool TERRAINLOADER::makeNormalmap(unsigned int width, unsigned int height)
{
std::ofstream file;
file.open("terrainnormal.bmp");
if(!file)
{
file.close();
return false;
}
bitmaploader.writeHeader(file,width,height);
for(int y = 0; y < height; y++)
{
for(int x = 0; x < width; x++)
{
file << static_cast<unsigned char>(255*x/height); //(unsigned char)((getHeight(float(x)/float(width),float(y)/float(height))));
file << static_cast<unsigned char>(0); //(unsigned char)((getHeight(float(x)/float(width),float(y)/float(height))));
file << static_cast<unsigned char>(0); //(unsigned char)((getHeight(float(x)/float(width),float(y)/float(height))));
};
};
file.close();
return true;
};
The writeHeader(...) function is from SO, from a solved,working post. (I've forgot the name of it)
The getHeight(...) is using bicubic interpolation, so I can write it to big resolution images, and it stays smooth. It will be also used for collision detection and now is used as a LOD factor for my clipmaps.
Now the problem is that this outputs a distorted image. The pictures will tell everything I think:
The expected/distorted result(s):
for the heightmap: I have the function that describes a mesh: getHeight(x,z). It gives back the correct results because I've tested it with shaders (by sending heights as vertex attribs) too. The image downloaded from internet:
And with the y(x,z) function values written to a .BMP: (the commented out part of the code):
With a simple function: file << static_cast<unsigned char>(255*(float)x/height)
which should be a simple blend from black to white to the right.
I used an image size of 256 x 256, because I've read it should be multiple of 4. I CAN use libraries, but I'd like to solve this problem without one. So, what caused this distortion?
EDIT:
On the last image some lines are also colored, but they shouldn't be. This post is similar, but my heightmap is not distorted linearly as in this post: Image Distortion with Lock Bits
EDIT:
Another strange issue is when I don't make all colors the same, it get's distorted in colors too. For example set only the RED to the heights, and leave G and B 0, it became not only RED, but a noisy colored heightmap.
EDIT /comments/
If I understood them right, there's the size of the header, then comes my pixel data. Now before the pixel data there must be 4 * n bytes. So that padding mean after the header I put some more data that fills the place.
For example assuming (I will look up hot to get it exactly) my header is 55 bytes, then I should add 1 more byte to it because 55+1 = 56 and 4|56.
So
file << static_cast<unsigned char>('a');
for(int y = 1; y <= width; y++)
{
for(int x = 1; x <= height; x++)
{
file << static_cast<unsigned char>(x);
file << static_cast<unsigned char>(x);
file << static_cast<unsigned char>(x);
};
};
should be correct.
But I realized the real issue (as Jigsore commented). When I cast from int to char, it seems like a 1 digit number becomes 1 byte, 2 digits number 2, and 3 digits 3 bytes. Clamping the height to 3 digits works well, but the image is a bit whitey, because 'darkest' color becomes (100,100,100) instead of (0,0,0). Also, this is the cause of the non-regular distortion, because it depends on how many 'hills' or 'mountains' are there in one row. How can I solve this, and I hope the last problem? I don't want to compress the image to 100-256 range.;)
Open your file in binary mode.
Under Windows, if you open a file in the default text mode, it will write an extra 0x0d (Return) character after every 0x0a (Linefeed) that gets written out. The first time this happens it will change the colors of the following pixels, as the RGB order gets out of alignment. After it happens 3 times you'll be off by a full pixel.
Yes i have been through the other questions that are related to this, but i found them not much help. They were some help but i am still a bit confused. So here what what i need to do:
We have a 132x65 screen. I have a 132x65 .bmp. I want to go through the .bmp and separate it into little 1x8 columns to get the binary of that 32-bit column. Then do that 132 times across, and do that 9 times down. Anything that is not white should be counted as a bit. example:
If the top left pixel of the picture is any color that is not white and the 7 pixels below that are white then that would be the first element of the array, the hex of that number, so the array would look like this:
array [] = { 0x01 } and then it would continue to fill through those 132 columns and then do it again for 9 "sections" of rows. And the file result would be ONLY that array in a separate file.
I understand the header format for this, i have read the wiki article on .bmp file formats, my main problem is i don't really know how to interact with the .bmp when i actually want it to go inside and interact with each pixel from the image. I really dont need the whole thing, but maybe just an example of grabbing each pixel from the .bmp and outputting the color of the pixel into a file or something. My c++ is a little rusty (been doing java and javscript lately).
If you want to read a known format BMP and don't care about how it's done (ie, internal-only thing) you can just take the BMP, ignore the header and use it as a pixel array. It is stored line by line starting at the bottom left. There are some detail snags for how it's packed but in my experience if you take a 32bpp image it can be completely ignored.
As a really simple example:
unsigned int *buffer;
void readfile() {
FILE *f = fopen("file.bmp", "rb");
buffer = new unsigned int[132*65];
fseek(f, 54);
fread(buffer, 132*65*4, 1, f);
fclose(f);
}
unsigned int getpixel(int x, int y) {
//assuming your x/y starts from top left, like I usually do
return buffer[(64 - y) * 132 + x];
}
I had the same problem, but by reading BMP file format description I wrote a function that reads a .BMP file and stores it into a array.
Maybe this function can help you:
unsigned int PIC::BinToNum(char *b,int bytes)
{
unsigned int tmpx = 0;
unsigned int pw = 1;
for(int i=0;i<bytes;i++)
{
tmpx += ((unsigned char)b[i]* pw);
pw = pw * 256;
}
return tmpx;
}
int PIC::Open(const char *path)
{
int pad = 0;
unsigned int sof = 0;
unsigned int tx = 0;
char tmp[4] = {0,0,0,0};
fstream file;
file.open(path,ios::in);
if(file.fail())
{
width=height=ColorBits=size=0;
return -1;
}
else
{
file.seekg(0,ios::beg);
file.read(tmp,2);
if(!(tmp[0] == 66 && tmp[1] == 77))
{
width=height=ColorBits=size=0;
return 0;
}
else
{
file.seekg(2,ios::beg); // 0x2 size
file.read(tmp,4);
size = BinToNum(tmp,4);
file.seekg(18,ios::beg); // 0x12 width
file.read(tmp,4);
width = BinToNum(tmp,4);
file.seekg(22,ios::beg); // 0x16 height
file.read(tmp,4);
height = BinToNum(tmp,4);
file.seekg(28,ios::beg); // 0x1C Bits per Pixel
file.read(tmp,2);
ColorBits = BinToNum(tmp,2);
file.seekg(10,ios::beg); // 0x0A start offset
file.read(tmp,4);
sof=BinToNum(tmp,4);
file.seekg(34,ios::beg); // 0x22 Padding
file.read(tmp,4);
pad = BinToNum(tmp,4);
pad = (int)(pad / height); // Compute Spacing in each row
pad = pad - (width*ColorBits/8);
// Initialize Matrix//
matrix = new(unsigned int[height*width]);
for(int h=height-1;h>=0;h--)
{
for(int w=0;w<=width-1;w++)
{
file.seekg(sof,ios::beg);
file.read(tmp,(int)(ColorBits/8));
tx = BinToNum(tmp,(int)(ColorBits/8));
matrix[(h*width)+w] = tx;
sof+=(int)(ColorBits/8);
}
sof +=pad;
}
}
}
file.close();
return 1;
}
Note:This functions is member of a class that i named it "PIC"...