I'm able to read the header file of an image fine, but I'm having trouble putting the first data value for the red channel,for example, 206, into a 2D array ppmImage.red[0][0]. A white space follows and then the first value for the green channel, and so on.
Below is what I am currently doing and instead of 206 being in ppmImage.red[0][0], I have ppmImage.red[0][0]= 2, ppmImage.green[0][0]=0, and ppmImage.blue[0][0]=6. For reference, these will only be 8 bit values and thus red, green, and blue are of type pixel and are unsigned char.
void readTextData(fstream &fin, struct ppmImage &image)
{
int iii, jjj;
for(iii = 0; iii < image.rows ; iii++)
{
for(jjj = 0; jjj < image.cols; jjj++)
{
fin >> image.red[iii][jjj];
fin >> image.green[iii][jjj];
fin >>image.blue[iii][jjj];
}
}
fin.close();
}
I thought fin >> would read until it hit white space but I was mistaken. I also tried using fin.read((char *) & image.redgray[iii][jjj],sizeof(pixel)); but ended up with the same results.
The data could be in a form like:
1 2
3 4 5
6 7 8 9
and I'm not sure how I would deal with the '\n'.
I've searched for information and end up more confused than I already am. I'd appreciate a nudge in the right direction or someone pointing out my stupidity. Thanks in advance.
This sounds like a simple fix, you have to read integers not unsigned char. Since your image uses unsigned char all you need to do add is some temporary ints for the read.
int red, green, blue;
fin >> red >> green >> blue;
image.red[iii][jjj] = red;
image.green[iii][jjj] = green;
image.blue[iii][jjj] = blue;
I am assuming that your image file is a text file, that seems to be the case from your description.
If at all possible, I'd change from a structure containing arrays, to an array of structures:
struct pixel {
unsigned char red, green, blue;
friend std::istream &operator>>(std::istream &is, pixel &p) {
unsigned int red, green, blue;
is >> red >> green >> blue;
p.red = red;
p.green = green;
p.blue = blue;
return is;
}
};
// ...
for (i = 0; i<image.cols; i++)
for (j=0; j<image.rows; j++)
if (!infile >> pixels[i][j])
break; // read failed
Related
I've been hacking away at this code trying to get this Parametric Line to make a gradient from Magenta to Cyan based upon the length of the line (so it doesn't get cut off by a short line, or happen too soon on a longer line) I'm trying to figure out the formula to find what I'd be subtracting, but I can't seem to figure it out, any ideas?
void ParametricLine(unsigned int _X1, unsigned int _Y1,
unsigned int _X2, unsigned int _Y2)
{
unsigned int lengthX;
unsigned int lengthY;
lengthX = abs((int)_X2 - (int)_X1);
lengthY = abs((int)_Y2 - (int)_Y1);
int longest;
if (lengthX > lengthY)
{
longest = lengthX;
}
else
{
longest = lengthY;
}
unsigned int color = 16711935; //magenta is green 0, others 255
unsigned int magenta = 16711935; //magenta is green 0, others 255
unsigned int cyan = 65535; //cyan is red = 0, G & B are 255
//all 255 = 16777215
unsigned int colorsubtract = (magenta - cyan)/longest;
//MAGENTA: R: 255, G: 0, B: 255
//CYAN: R:0, G: 255, B: 255
for (int i = 0; i < longest; i++)
{
float Ratio = (float)i / longest;
unsigned int CurrY = LERP(_Y1, _Y2, Ratio);
unsigned int CurrX = LERP(_X1, _X2, Ratio);
/*color = LERP(16711935, 65535, longest/65535);*/
if (color > cyan)
color = color - colorsubtract;
else if (color < cyan)
color = cyan;
//interpolate from magenta to cyan
raster[Position(CurrX, floor(CurrY + 0.5))] = color;
}
raster[Position(_X1, _Y1)] = 16777215;
raster[Position(_X2, _Y2)] = 16777215;
}
edit: here's the Lerp function for those asking-
unsigned int LERP(unsigned int _startval, unsigned int _endval, float _ratio){
return (((int)_endval - (int)_startval) * _ratio + (int)_startval);}
You're doing terrible things in your code. If you want to rasterize the line, the easiest way would be to use DDA algorithm (sometimes called Bresenham algorithm), which does not require floating point arithmetic and does not draw the same points several times.
Here's another explanation of the same concept.
And here's yet another one with the C code included.
And once you read all the mentioned pages, treat the colour as one of the coordinates and apply the exactly same DDA algorithm for the colour as well.
I'm trying to follow this pseudocode to implement a water colour filter in Open CV.
http://supercomputingblog.com/graphics/oil-painting-algorithm/
I've previously achieved the effect using this method in javascript with a canvas because I could iterate over the pixels however I'm not sure how to do that with Open CV.
Mat im = imread(...); //input image
Mat paint; // output after processing
for(int i = 0; i < im.rows; i++)
{
for (int j = 0; j < im.cols; j++) //for each pixel
{
//here I need a reference to the pixel colour from im
}
}
I tried to use:
im.at<uchar>(i,j)
However this is giving me values around 350 for the most part which suggested to me that it's the cumulation of the rgb channels (a multi-channel array I think). So I tried to split it like this:
vector<Mat> three_channels;
split(im, three_channels);
But it just gives me the same value 3 times. Any suggestions?
I ended up just accessing them, thusly:
int r = im.at<cv::Vec3b>(y,x)[0];
int g = im.at<cv::Vec3b>(y,x)[1];
int b = im.at<cv::Vec3b>(y,x)[2];
as was mentioned in the answer to a previous question.
Most of the time, colors are just 8-bit combined rather than in an array, so you need masks to manipulate them.
short red = (color >> 16) & 0xFF;
short green = (color >> 8) & 0xFF;
short blue = (color) & 0xFF;
(via how to color mask in c)
I have the following c++ typedef struct that I work with:
typedef struct TriclopsColorImage
{
// The number of rows in the image.
int nrows;
// The number of columns in the image.
int ncols;
// The row increment of the image.
int rowinc;
// The pixel data for red band of the image.
unsigned char* red;
// The pixel data for green band of the image.
unsigned char* green;
// The pixel data for blue band of the image.
unsigned char* blue;
} TriclopsColorImage;
I have an image which gets passed to a mex function as prhs[1]
How do I correctly assign the fields of red, green and blue. Here I have
TriclopsColorImage colorImage;
And I am doing something like this:
colorImage.nrows=(int) mxGetN(prhs[1]);
colorImage.ncols=(int) mxGetM(prhs[1]);
colorImage.rowinc=colorImage.ncols*2;
colorImage.red=?
colorImage.green=?
colorImage.blue=?
You must pass the image to your mex function as a uint8 type of size m-by-n-by-3.
For example:
img = imread( 'football.jpg' );
myMeFunction( someArg, img ); % note that prhs[1] is the SECOND argument
Now inside your mex:
colorImage.nrows=(int) mxGetM(prhs[1]); // M is number of rows!
colorImage.ncols=(int) mxGetN(prhs[1]) / 3; // assuming third dimension is three.
// for the colors:
unsigned char* p = (unsigned char*)mxGetData(prhs[1]);
colorImage.red = p;
colorImage.green = p + colorImage.nrows*colorImage.ncols;
colorImage.blue = p + 2*colorImage.nrows*colorImage.ncols;
Please read carefully the description of mxGetN.
If I do the following using Qt:
Load a bitmap in QImage::Format_RGB32.
Convert its pixels to RGB565 (no Qt format for this so I must do it "by hand").
Create a new bitmap the same size as the one loaded in step 1.
Convert the RGB565 buffer pixels back to RGB88 in to the image created in step 3.
The image created from step 4 looks like the image from step 1, however they're not exactly the same if you compare the RGB values.
Repeating steps 2 to 5 results in the final image losing colour - it seems to become darker and darker.
Here are my conversion functions:
qRgb RGB565ToRGB888( unsigned short int aTextel )
{
unsigned char r = (((aTextel)&0x01F) <<3);
unsigned char g = (((aTextel)&0x03E0) >>2);
unsigned char b = (((aTextel)&0x7C00 )>>7);
return qRgb( r, g, b, 255 );
}
unsigned short int RGB888ToRGB565( QRgb aPixel )
{
int red = ( aPixel >> 16) & 0xFF;
int green = ( aPixel >> 8 ) & 0xFF;
int blue = aPixel & 0xFF;
unsigned short B = (blue >> 3) & 0x001F;
unsigned short G = ((green >> 2) < 5) & 0x07E0;
unsigned short R = ((red >> 3) < 11) & 0xF800;
return (unsigned short int) (R | G | B);
}
An example I found from my test image which doesn't convert properly is 4278192128 which gets converted back from RGB565 to RGB888 as 4278190080.
Edit: I should also mention that the original source data is RGB565 (which my test RGB888 image was created from). I am only converting to RGB888 for display purposes but would like to convert back to RGB565 afterwards rather than keeping two copies of the data.
Beforehand I want to mention that the component order in your two conversion functions aren't the same. In 565 -> 888 conversion, you assume that the red component uses the low order bits (0x001F), but when encoding the 5 bits of the red component, you put them at the high order bits (0xF800). Assuming that you want a component order analogous to 0xAARRGGBB (binary representation in RGB565 is then 0bRRRRRGGGGGGBBBBB), you need to change the variable names in your RGB565ToRGB888 method. I fixed this in the code below.
Your RGB565 to RGB888 conversion is buggy. For the green channel, you extract 5 bits, which gives you only 7 bit instead of 8 bit in the result. For the blue channel you take the following bits which is a consequential error. This should fix it:
QRgb RGB565ToRGB888( unsigned short int aTextel )
{
// changed order of variable names
unsigned char b = (((aTextel)&0x001F) << 3);
unsigned char g = (((aTextel)&0x07E0) >> 3); // Fixed: shift >> 5 and << 2
unsigned char r = (((aTextel)&0xF800) >> 8); // shift >> 11 and << 3
return qRgb( r, g, b, 255 );
}
In the other function, you accidentally wrote less-than operators instead of left-shift operators. This should fix it:
unsigned short int RGB888ToRGB565( QRgb aPixel )
{
int red = ( aPixel >> 16) & 0xFF; // why not qRed(aPixel) etc. ?
int green = ( aPixel >> 8 ) & 0xFF;
int blue = aPixel & 0xFF;
unsigned short B = (blue >> 3) & 0x001F;
unsigned short G = ((green >> 2) << 5) & 0x07E0; // not <
unsigned short R = ((red >> 3) << 11) & 0xF800; // not <
return (unsigned short int) (R | G | B);
}
Note that you can use the already existing (inline) functions qRed, qGreen, qBlue for component extraction analogous to qRgb for color construction from components.
Also note that the final bit masks in RGB888ToRGB565 are optional, as the component values are in the 8-bit-range and you cropped them by first right-, then left-shifting the values.
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.