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.
Related
I have a 2D vector of float values that I need to create an image from it.
The code that I have is as follows:
inline cv::Mat ConvertToMat(vector<vector<float>> inputData)
{
static int MAXGREY = 255;
static int MAXRANGE = 255;
int Red, Blue, Green;
float maxValue = GetMaxValue(inputData); // find max value in input data
cv::Mat output(inputData.getXSize(), inputData.getXSize(), CV_8UC3, cv::Scalar::all(0));
// if the max value is equal to or less than 0, no data in the vector to convert.
if (maxValue > 0)
{
for (int x = 0; x < inputData.size(); x++)
{
for (int y = 0; y < inputData[x].size(); y++)
{
auto Value = inputData[x][y];
Green = 0;
Red = Value * 255 / maxValue;
Blue = (maxValue - Value) * 255 / maxValue;
cv::Vec3b xyzBuffer;
xyzBuffer[0] = Blue;
xyzBuffer[1] = Red;
xyzBuffer[2] = Green;
output.at<cv::Vec3b>(x, y) = xyzBuffer;
}
}
}
return output;
}
but this method doesn't generate suitable results when there is a pixel with a very high value and a lot of pixels with small values, all small values can not be seen on the output.
for example, lets look this set of data for input:
int main()
{
vector<vector<float>> inputData =
{
{1,2,3,4,5,6,7,8,9,10},
{1.5,2.5,3.5,4.5,5.5,6.5,7.5,8.5,9.5,10.5},
{1,2,3,4,5,6,7,8,9,10},
{1.5,2.5,3.5,4.5,5.5,6.5,7.5,8.5,9.5,10.5},
{1,2,3,4,2000,6,7,8,9,10},
{1.5,2.5,3.5,4.5,5.5,6.5,7.5,8.5,9.5,10.5},
{1,2,3,4,5,6,7,8,9,10},
{1.5,2.5,3.5,4.5,5.5,6.5,7.5,8.5,9.5,10.5},
{1,2,3,4,5,6,7,8,9,10},
{1.5,2.5,3.5,4.5,5.5,6.5,7.5,8.5,9.5,10.5}
};
cv::Mat image=ConvertToMat(inputData);
cv::imwrite("c://tmp//myimage.jpg", image);
return 0;
}
The generated out is as follow (the value of each pixel is shown on the pixel):
Since we have 3X byte data for colour, we should have enough dynamic range to show the data for each pixel in a different colour. but the above algorithm converts the value of 1 and 2 and 3 into the same colour (254,0,0).
How can I convert a float into three different colours so I can see all pixels with a different colour suitable for visual inspection (so each pixel which is near to the other has similar colour but not the same colour)?
Scenario
I want to create my own SetChannel function that will set a specific channel of an image. For example, I have an image input of type CV_16UC3 (BGR image of type ushort) and I want to change the green channel (=1 due to zero based index) to an ushort value of 32768. For this, I invoke SetChannel(input,1,32768).
template<typename T>
void SetChannel(Mat mat, uint channel, T value)
{
const uint channels = mat.channels();
if (channel + 1 > channels)
return;
T * data = (T*)mat.data;
// MBPR : number of Memory Block Per Row
// Mat.step : number of byte per row
// Mat.elemSize1() : number of byte per channel
const unsigned int MBPR = mat.step / mat.elemSize1();
// N : total number of memory blocks
const unsigned int N = mat.rows * MBPR;
for (uint i = channel; i < N; i += channels)
data[i] = value;
}
I prefer working in a single loop than nested looping so I define the number of iteration N as given above.
The code above works as expected but some other people said the part
T * data = (T*)mat.data;
is a code smell and regarded as a badly designed program.
Now I want to rewrite the new one with another approach as follows.
It is not working as expected because I don't know how to assign T value to data[i] of type uchar.
template<typename T>
void SetChannel(Mat mat, uint channel, T value)
{
const uint channels = mat.channels();
if (channel + 1 > channels)
return;
uchar * data = mat.data;
const unsigned int N = mat.rows * mat.step;// byte per image
const unsigned int bpc = mat.elemSize1();// byte per channel
const unsigned int bpp = mat.elemSize(); // byte per pixel
for (uint i = channel * bpc; i < N; i += bpp)
//data[i] = value;
}
Question
How to assign value of type T to data[i] of type uchar without any loss?
For those who don't know how Mat is, the following might be useful.
About OpenCV Mat class
OpenCV provides a bunch of types of images. For example,
CV_8UC1 represents gray scale image type in which each pixel has one channel of type uchar.
CV_8UC3 represents BGR (not RGB) image type in which each pixel has three channels, each of type uchar.
CV_16UC3 represents BGR (not RGB) image type in which each pixel has three channels, each of type ushort.
etc.
Mat is the class to encapsulate image. It has several attributes and functions. Let me list some of them that I will use in this question so you can understand my scenario better.
Mat.data: pointer of type uchar pointing to a block of image pixels.
Mat.rows: number of rows
Mat.channels(): number of channels per pixel
Mat.elemSize1() (ended with 1): number of byte per channel
Mat.elemSize(): number of byte per pixel.
Mat.elemSize() = Mat.channels() * Mat.elemSize1().
Mat.step: number of byte per row
Here Mat.step can be thought as the product of
- "effective" number of pixels per row (let me name it as EPPR),
- number of channels per pixel or Mat.channels(), and
- number of byte per channel or Mat.elemSize1().
Mathematically,
Mat.step = EPPR * Mat.elemSize()
Mat.step = EPPR * Mat.channels() * Mat.elemSize1()
Let me define EPPR * Mat.channels() as memory blocks per row (MBPR). If you know the correct term for MBPR, let me know.
As a result, MBPR = Mat.step / Mat.elemSize1().
I got it from someone offline. Hopefully it is useful for others as well.
template<typename T>
void SetChannel(Mat mat, uint channel, T value)
{
const uint channels = mat.channels();
if (channel + 1 > channels)
return;
uchar * data = mat.data;
const unsigned int N = mat.rows * mat.step;// byte per image
const unsigned int bpc = mat.elemSize1();// byte per channel
const unsigned int bpp = mat.elemSize(); // byte per pixel
const unsigned int bpu = CHAR_BIT * sizeof(uchar);// bits per uchar
for (uint i = channel * bpc; i < N; i += bpp)
for (uint j = 0; j < bpc; j++)
data[i + j] = value >> bpu * j;
}
I am using openimageIO to read and display an image from a JPG file, and I now need to store the RGB values in arrays so that I can manipulate and re-display them later.
I want to do something like this:
for (int i=0; i<picturesize;i++)
{
Rarray[i]=pixelredvalue;
Garray[i]=pixelgreenvalue;
Barray[i]=pixelbluevalue;
}
This is an openimageIO source that I found online: https://people.cs.clemson.edu/~dhouse/courses/404/papers/openimageio.pdf
"Section 3.2: Advanced Image Output" (pg 35) is the closest to what I'm doing, but I don't understand how I can use the channels to write pixel data to arrays. I also don't fully understand the difference between "writing" and "storing in an array". This is the piece of code in the reference that I am talking about:
int channels = 4;
ImageSpec spec (width, length, channels, TypeDesc::UINT8);
spec.channelnames.clear ();
spec.channelnames.push_back ("R");
spec.channelnames.push_back ("G");
spec.channelnames.push_back ("B");
spec.channelnames.push_back ("A");
I managed to read the image and display it using the code in the reference, but now I need to store all the pixel values in my array.
Here is another useful piece of code from the link, but again, I can't understand how to retrieve the individual RGB values and place them into an array:
#include <OpenImageIO/imageio.h>
OIIO_NAMESPACE_USING
...
const char *filename = "foo.jpg";
const int xres = 640, yres = 480;
const int channels = 3; // RGB
unsigned char pixels[xres*yres*channels];
ImageOutput *out = ImageOutput::create (filename);
if (! out)
return;
ImageSpec spec (xres, yres, channels, TypeDesc::UINT8);
out->open (filename, spec);
out->write_image (TypeDesc::UINT8, pixels);
out->close ();
ImageOutput::destroy (out);
But this is about writing to a file, and still does not solve my problem. This is on page 35.
Let's assume, that your code which reads an image, looks like this (snippet from OpenImageIO 1.7 Programmer Documentation, Chapter 4.1 Image Input Made Simple, page 55):
ImageInput *in = ImageInput::open (filename);
const ImageSpec &spec = in->spec();
int xres = spec.width;
int yres = spec.height;
int channels = spec.nchannels;
std::vector<unsigned char> pixels (xres*yres*channels);
in->read_image (TypeDesc::UINT8, &pixels[0]);
in->close();
ImageInput::destroy (in);
Now all the bytes of the image are contained in std::vector<unsigned char> pixels.
If you want to access the RGB valuse of the pixel at positon x, y, the you can do it like this:
int pixel_addr = (y * yres + x) * channels;
unsigned char red = pixels[pixel_addr];
unsigned char green = pixels[pixel_addr + 1];
unsigned char blue = pixels[pixel_addr + 2];
Since all the pixels are stored in pixels, there is no reason to store them in separate arrays for the 3 color channels.
But if you want to store the red, green and blue values in separated arrays, then you can do it like this:
std::vector<unsigned char> Rarray(x_res*yres);
std::vector<unsigned char> Garray(x_res*yres);
std::vector<unsigned char> Barray(x_res*yres);
for (int i=0; i<x_res*yres; i++)
{
Rarray[i] = pixels[i*channels];
Garray[i] = pixels[i*channels + 1];
Barray[i] = pixels[i*channels + 2];
}
Of course the pixels have to be tightly packed to pixels (line alignment of 1).
i have some problem about convert to grayscale using openCV in make the manual function.
And this is my code.
main.cpp
unsigned int height, width;
int main(int argc, char** argv)
{
IplImage* image_input = cvLoadImage("duck.jpg", CV_LOAD_IMAGE_UNCHANGED);
IplImage* image_output = cvCreateImage(cvGetSize(image_input),IPL_DEPTH_8U,1);
unsigned char *h_out = (unsigned char*)image_output->imageData;
unsigned char *h_in = (unsigned char*)image_input->imageData;
width = image_input->width;
height = image_input->height;
h_grayscale(h_in, h_out);
cvShowImage("Original", image_input);
cvShowImage("CPU", image_output);
cvReleaseImage(&image_input);
cvReleaseImage(&image_output);
waitKey(0);
}
in this my grayscale code.
void h_grayscale( unsigned char* h_in, unsigned char* h_out)
{
for(int i=0;i<height;i++){
for(int j=0;j<width;j++){
int index = (i*j)*3;
double temp = 0.3*h_in[index]+0.6*h_in[index+1]+0.1*h_in[index+2];
h_out[i*j] = (unsigned char)temp;
}
}
but the results are not performing as it should, it appears some noise in it.
I still have not found where the code that makes the error. :(
thx before.
You are calculating the input and output indices incorrectly.
First point to remember while working with OpenCV images is that they are aligned, i.e. each row is padded at the end with some random values. So while calculating the linear index of a pixel in color and grayscale images, widthStep should be used instead of width.
The generic formula to calculate index of a pixel is:
i * widthStep/sizeof(type) + (channels * j)
Where i is the row number, and j is the column number.
Translating the above formula for the current case, the indices will be calculated as follows:
Input:
int index = i * colorWidthStep + (3 * j);
Output:
h_out[i * grayWidthStep + j] = (unsigned char)temp;
You may create 2 additional global variables colorWidthStep and grayWidthStep along with width and height. Initialize the variables as follows:
width = image_input->width;
height = image_input->height;
colorWidthStep = image_input->widthStep;
grayWidthStep = image_output->widthStep;
In my application, once I load an image into an SDL_Surface object, I need to go through each RGB value in the image and replace it with another RGB value from a lookup function.
(rNew, gNew, bNew) = lookup(rCur, gCur, bCur);
It seems surface->pixels gets me the pixels. I would appreciate it if someone can explain to me how to obtain R, G, and B values from the pixel and replace it with the new RGB value.
Use built-in functions SDL_GetRGB and SDL_MapRGB
#include <stdint.h>
/*
...
*/
short int x = 200 ;
short int y = 350 ;
uint32_t pixel = *( ( uint32_t * )screen->pixels + y * screen->w + x ) ;
uint8_t r ;
uint8_t g ;
uint8_t b ;
SDL_GetRGB( pixel, screen->format , &r, &g, &b );
screen->format deals with the format so you don't have to.
You can also use SDL_Color instead of writing r,g,b variables separately.
Depending on the format of the surface, the pixels are arranged as an array in the buffer.
For typical 32 bit surfaces, it is R G B A R G B A
where each component is 8 bit, and every 4 are a pixel
First of all you need to lock the surface to safely access the data for modification. Now to manipulate the array you need to know the numbers of bit per pixels, and the alignment of the channels (A, R, G, B). As Photon said if is 32 bits per pixel the array can be RGBARGBA.... if it is 24 the array can be RGBRGB.... (can also be BGR, BGR, blue first)
//i assume the signature of lookup to be
int lookup(Uint8 r, Uint8 g, Uint8 b, Uint8 *rnew, Uint8* gnew, Uint8* bnew);
SDL_LockSurface( surface );
/* Surface is locked */
/* Direct pixel access on surface here */
Uint8 byteincrement = surface->format->BytesPerPixel;
int position;
for(position = 0; position < surface->w * surface->h* byteincrement; position += byteincrement )
{
Uint8* curpixeldata = (Uint8*)surface->data + position;
/* assuming RGB, you need to know the position of channels otherwise the code is overly complex. for instance, can be BGR */
Uint8* rdata = curpixeldata +1;
Uint8* gdata = curpixeldata +2;
Uint8* bdata = curpixeldata +3;
/* those pointers point to r, g, b, use it as you want */
lookup(*rdata, *gdata, *bdata, rdata,gdata,bdata);
}
.
SDL_LockSurface( surface );