I need RGBA value of image for generating height of my terrain and I'm using sdl for load image I looked around and found SDL_GetRGBA should return those value but every time I run this code my program crash...
SDL_Surface *image = IMG_Load(HightMapAddress);
SDL_LockSurface(image);
Uint32 *pixels = (Uint32 *)image->pixels;
Uint8* RED;
Uint8* GREEN;
Uint8* BLUE;
Uint8* ALPHA;
SDL_GetRGBA(pixels[0], image->format, RED, GREEN, BLUE, ALPHA);
SDL_GetRGBA gets pointers to memory where it should write resulting colours. You passed uninitialised pointers, so said function will attempt to write to unknown location. Luckly it will crash, otherwise you'll stomp some random location in memory.
Correct code would be something like
Uint8 RED;
Uint8 GREEN;
Uint8 BLUE;
Uint8 ALPHA;
SDL_GetRGBA(pixels[0], image->format, &RED, &GREEN, &BLUE, &ALPHA);
Related
I have a monochrome (black and white) image that I am trying to extract a value between 0 and 255 indicating the shade of the pixel, with 0 being black and 255 being white. I import the image as follows:
PImage img;
void setup() {
size(1000, 1000);
img = loadImage("myimage.jpg");
x_location = 50;
y_location = 230;
// add code to extract shade from img here
}
I am trying to use get() to extract the shade. Unfortunately, when I try to use img.get(x_location, y_location) it returns a very large negative number (on the order of -1000000). Is there a way to ensure that get() returns some normalized (understandable) value?
This is very interesting. Here's some skeleton code which will help you get what you want:
PImage img;
color currentColor;
void setup() {
size(656, 354);
currentColor = color(0);
img = loadImage("bean.jpeg");
}
void draw() {
background(0);
image(img, 0, 0);
fill(currentColor);
stroke(200);
strokeWeight(2);
ellipse(30, 30, 40, 40);
fill(0);
text("A " + alpha(currentColor), 10, 65);
text("R " + red(currentColor), 10, 75);
text("G " + green(currentColor), 10, 85);
text("B " + blue(currentColor), 10, 95);
}
void mouseClicked() {
currentColor = img.get(mouseX, mouseY);
}
Which looks like this:
The magic here is to know that you can extract the ARGB info which are part of the color. Yet, I also wondered why it was a negative number. Here's why (emphasis mine):
Colors, in Processing, are stored actually in simple Java ints, 32-bit
values. The color pseudo-type is actually replaced by Processing with
int when generating Java code before compilation.
This type has a width of 32 bits, which is perfect as we can put 4
channels of 8 bits each inside. 8 bits allow a range of of values from
0 to 255 (included). The 4 channels are alpha (opacity), red, green,
blue, the whole being often abbreviated as ARGB.
Low value of color channel means "low intensity", darkness. High value
means "high intensity", lightness. So if all channels are 0, we have
black; if they are all at 255, we have white. Alpha channel is
different: 0 means low opacity, fully transparent, while 255 means
high opacity, normal opaque color.
In Java, numbers are always signed. In computing, negative numbers are
marked by setting the highest bit to 1. So, opaque colors, the most
common kind, the default if no opacity is given, is 0xFF = 255, the
high bit is set to 1, the color value is negative. Hence the answer to
the first question...
The strange values are the result of combining all the values of the
channels. Let's take a simple yellowish color. Alpha is 255 (opaque),
red is 250, green is 230 and blue is, say, 20. These values are 0xFF,
0xFA, 0xE6 and 0x14. Combined to make an int, it gives 0xFFFAE614, ie.
-334316. Hence a strange number, not very easy to decipher.
You can use any part of the RGB info if your image is really in grayscale. Have fun!
Here a little code to understand how work Processing with color arguments. I hope tha's can help you.
void setup() {
colorMode(RGB,255,255,255,255);
println("colorMode",g.colorModeX,g.colorModeY,g.colorModeZ,g.colorModeA);
background(random(g.colorModeX),random(g.colorModeY),random(g.colorModeZ),random(g.colorModeA));
int color_arg = get((int)random(width),(int)random(height));
println("color_arg: ",color_arg);
println("color_arg rgb_a:",red(color_arg),green(color_arg),blue(color_arg),alpha(color_arg));
println("color_arg hsb_a:",hue(color_arg),saturation(color_arg),brightness(color_arg),alpha(color_arg));
}
Bitmap is constructed by pixel data(purely pixel data). The construction was done by properly setting the bitmap parameters like hieght,width, bitcount etc. Bitmap is actually constructed with CreateDIBsection. And the bitmap is loaded onto a CStatic object having Bitmap as property.
Image is getting displayed with proper width and content. But only difference is the content color is colored instead of scale of gray. For eg image is a white H letter on black Bground, instead of displaying it as whitish, say a blue colored H letter is displayed. Similar color changes applies for different images. Also, sometimes junk colored data appears deviating from original content of image apart from just the color change.
Bitmap is a 16 bit bitmap.
Please see below for code used for creating BitMap.
HDC is device context of CStatic variable in which the created bitmap is loaded;
I directly set the BitMap returned by below function to this variable using setbitmap function. CStatic varibale has also BitMap as one of its property. See below for function used to create bitmap.
Function parameter definitions.
PixMapHeight = number of rows in pixel matrix.
PixMapWidth = number of columns in pixel matrix.
BitsPerPixel = The bits stored for one pixel.
pPixMapBits = Void pointer to pixel array.(raw pixel data only! 16 bit per pixel).
DoBitmapFromPixels(HDC Hdc, UINT PixMapWidth, UINT PixMapHeight, UINT BitsPerPixel, LPVOID pPixMapBits)
BITMAPINFO *bmpInfo = (BITMAPINFO *)malloc(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256);
BITMAPINFOHEADER &bmpInfoHeader(bmpInfo->bmiHeader);
bmpInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
LONG lBmpSize = PixMapWidth * PixMapHeight * (BitsPerPixel / 8);
bmpInfoHeader.biWidth = PixMapWidth;
bmpInfoHeader.biHeight = -(static_cast<int>(PixMapHeight));
bmpInfoHeader.biPlanes = 1;
bmpInfoHeader.biBitCount = BitsPerPixel;
bmpInfoHeader.biCompression = BI_RGB;
bmpInfoHeader.biSizeImage = 0;
bmpInfoHeader.biClrUsed = 0;
bmpInfoHeader.biClrImportant = 0;
void *pPixelPtr = NULL;
HBITMAP hBitMap = CreateDIBSection(Hdc, bmpInfo, DIB_RGB_COLORS, &pPixelPtr, NULL, 0);
if (pPixMapBits != NULL)
{
BYTE* pbBits = (BYTE*)pPixMapBits;
BYTE *Pix = (BYTE *)pPixelPtr;
memcpy(Pix, ((BYTE*)pbBits + (lBmpSize * (CurrentFrame - 1))), lBmpSize);
}
free(bmpInfo);
return hBitMap;
The supposed output is the figure in the left of attached file. But I am getting a blue toned image as in right(never mind the scaling and exact match issue, put the image to depict the problem).
And also it will be very helpful if I know how RGB values are stored in 16 bits!
You never actually said what format pPixMapBits is in, but I'm guessing that it contains 16-bit values where 0 represents black, 32768 represents gray, and 65535 represents white.
You are creating a BITMAPINFOHEADER with bitBitCount = 16 and biCompression = BI_RGB. According to the documentation, if you set the fields that way, then:
Each WORD in the bitmap array represents a single pixel. The relative intensities of red, green, and blue are represented with five bits for each color component. The value for blue is in the least significant five bits, followed by five bits each for green and red. The most significant bit is not used.
This is not the same format as your source data, and you are doing no conversion, so you get junk. Note that the bitmap format you chose is capable of representing only 2^5 = 32 shades of gray, not 65536, so you will suffer loss of quality during the conversion.
I need to find the percentage of skintone of a person in a given image.
I have been able to count all the pixels with skin colour so far but I am having trouble ignoring the background of the person so I can count the number of pixels for the percentage.
BackgroundSubtractorMOG2 bg;
bg.nmixtures =3;
bg.bShadowDetection=false;
bg.operator ()(img,fore);
bg.getBackgroundImage(back);
img is my image. I was trying to separate the back and fore mat objects, but with the above code snippet back and fore take the same value as the img. Nothing is happening.
Can you point me in the right direction as to what changes I have to make to get it right?
I was able to run some similar code found here:
http://mateuszstankiewicz.eu/?p=189
I had to change a couple of things, but it ended up working properly (back and fore are not the same as img when displayed:
int main(int argc, char *argv[]) {
Mat frame, back, fore;
VideoCapture cap(0);
BackgroundSubtractorMOG2 bg;
vector<std::vector<Point> > contours;
namedWindow("Frame");
namedWindow("Background");
namedWindow("Foreground");
for(;;) {
cap >> frame;
bg.operator ()(frame, fore);
bg.getBackgroundImage(back);
erode(fore, fore, Mat());
dilate(fore, fore, Mat());
findContours(fore, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
drawContours(frame, contours, -1, Scalar(0, 0, 255), 2);
imshow("Frame", frame);
imshow("Background", back);
imshow("Foreground", fore);
if(waitKey(1) == 27) break;
}
return 0;
}
I am trying to use OpenCV 2.3.1 to convert a 12-bit Bayer image to an 8-bit RGB image. This seems like it should be fairly straightforward using the cvCvtColor function, but the function throws an exception when I call it with this code:
int cvType = CV_MAKETYPE(CV_16U, 1);
cv::Mat bayerSource(height, width, cvType, sourceBuffer);
cv::Mat rgbDest(height, width, CV_8UC3);
cvCvtColor(&bayerSource, &rgbDest, CV_BayerBG2RGB);
I thought that I was running past the end of sourceBuffer, since the input data is 12-bit, and I had to pass in a 16-bit type because OpenCV doesn't have a 12-bit type. So I divided the width and height by 2, but cvCvtColor still threw an exception that didn't have any helpful information in it (the error message was "Unknown exception").
There was a similar question posted a few months ago that was never answered, but since my question deals more specifically with 12-bit Bayer data, I thought it was sufficiently distinct to merit a new question.
Thanks in advance.
Edit: I must be missing something, because I can't even get the cvCvtColor function to work on 8-bit data:
cv::Mat srcMat(100, 100, CV_8UC3);
const cv::Scalar val(255,0,0);
srcMat.setTo(val);
cv::Mat destMat(100, 100, CV_8UC3);
cvCvtColor(&srcMat, &destMat, CV_RGB2BGR);
I was able to convert my data to 8-bit RGB using the following code:
// Copy the data into an OpenCV Mat structure
cv::Mat bayer16BitMat(height, width, CV_16UC1, inputBuffer);
// Convert the Bayer data from 16-bit to to 8-bit
cv::Mat bayer8BitMat = bayer16BitMat.clone();
// The 3rd parameter here scales the data by 1/16 so that it fits in 8 bits.
// Without it, convertTo() just seems to chop off the high order bits.
bayer8BitMat.convertTo(bayer8BitMat, CV_8UC1, 0.0625);
// Convert the Bayer data to 8-bit RGB
cv::Mat rgb8BitMat(height, width, CV_8UC3);
cv::cvtColor(bayer8Bit, rgb8BitMat, CV_BayerGR2RGB);
I had mistakenly assumed that the 12-bit data I was getting from the camera was tightly packed, so that two 12-bit values were contained in 3 bytes. It turns out that each value was contained in 2 bytes, so I didn't have to do any unpacking to get my data into a 16-bit array that is supported by OpenCV.
Edit: See #petr's improved answer that converts to RGB before converting to 8-bits to avoid losing any color information during the conversion.
The Gillfish's answer technically works but during the conversion it uses smaller data structure (CV_8UC1) than the input (which is CV_16UC1) and loses some color information.
I would suggest first to decode the Bayer encoding but stay in 16-bits per channel (from CV_16UC1 to CV_16UC3) and later convert to CV_8UC3.
The modified Gillfish's code (assuming the camera gives image in 16bit Bayer encoding):
// Copy the data into an OpenCV Mat structure
cv::Mat mat16uc1_bayer(height, width, CV_16UC1, inputBuffer);
// Decode the Bayer data to RGB but keep using 16 bits per channel
cv::Mat mat16uc3_rgb(width, height, CV_16UC3);
cv::cvtColor(mat16uc1_bayer, mat16uc3_rgb, cv::COLOR_BayerGR2RGB);
// Convert the 16-bit per channel RGB image to 8-bit per channel
cv::Mat mat8uc3_rgb(width, height, CV_8UC3);
mat16uc3_rgb.convertTo(mat8uc3_rgb, CV_8UC3, 1.0/256); //this could be perhaps done more effectively by cropping bits
For anyone struggling with this, the above solution only works if your image actually comes in 16bit otherwise, as already suggested by the comments you should chop-off the 4 least significant bits. I achieved that with this. It's not very clean but it works.
unsigned short * image_12bit = (unsigned short*)data;
char out[rows * cols];
for(int i = 0; i < rows * cols; i++) {
out[i] = (char)((double)(255 * image_12bit[i]) / (double)(1 << 12));
}
cv::Mat bayer_image(rows, cols, CV_8UC1, (void*)out);
cv::cvtColor(bayer_image, *res, cv::COLOR_BayerGR2BGR);
I have a piece of code here.
This is a camera capture application using OpenCV and Qt(for GUI).
void MainWindow::on_pushButton_clicked()
{
cv::VideoCapture cap(0);
if(!cap.isOpened()) return;
//namedWindow("edges",1);
QVector<QRgb> colorTable;
for (int i = 0; i < 256; i++) colorTable.push_back(qRgb(i, i, i));
QImage img;
img.setColorTable(colorTable);
for(;;)
{
cap >> image;
cvtColor(image, edges, CV_BGR2GRAY);
GaussianBlur(edges, edges, cv::Size(7,7), 1.5, 1.5);
Canny(edges, edges, 0, 30, 3);
//imshow("edges", edges);
if(cv::waitKey(30) >= 0) break;
// change color channel ordering
//cv::cvtColor(image,image,CV_BGR2RGB);
img = QImage((const unsigned char*)(edges.data),
image.cols,image.rows,QImage::Format_Indexed8);
// display on label
ui->label->setPixmap(QPixmap::fromImage(img,Qt::AutoColor));
// resize the label to fit the image
ui->label->resize(ui->label->pixmap()->size());
}
}
Initially "edges" is displayed in red with green background.Then it switches to blue background. This switching is happening randomly.
How can I display white edges in a black background in a stable manner.
In short, add the img.setColorTable(colorTable); just before the // display on labelcomment.
For more details, you create your image and affect the color table at the begining of your code:
QImage img;
img.setColorTable(colorTable);
Then in the infinite loop, you are doing the following:
img = QImage((const unsigned char*)(edges.data), image.cols, image.rows, QImage::Format_Indexed8);
What happens is that you destroy the image created at the begining of your code, the color map for this new image is not set and thus uses the default resulting in a colored output.