I'm using C++ and Magick++. I need to get red, green and blue values from pixel but anything I do keeps getting me values over 255 or decimal values. Next code gives me decimal values
ColorRGB rgb(someImage.pixelColor(x, y));
cout << rgb.red();
cout << rgb.green();
cout << rgb.blue();
Also I don't know if I can use Quantum values like this
image.pixelColor(x, y).redQuantum();
to get red value between 0 and 255 and not decimal. Does anyone know how to get this or calculate (I understand there's probably no function for this so I need to calculate it myself)
If you look at the Magick++ documentation, it appears that when using ColorRGB the color values are represented as a decimal value between zero and one.
This actually makes a lot of sense since it also appears that you have a choice of which depth of color you would like to use. Rather than locking you into values from zero through 255, the decimal 0.0-1.0 can be easily scaled to any color depth.
If you are sure that you want to see it from 0-255 even if the underlying color depth is, say, 32 bit, you can easily write a transformation function.
Update
Here's an example of how you can scale the value:
uint8_t red = (uint8_t)(rgb.red() * 255);
This will scale it to an 8 but integer between zero and 255.
Related
Matlab offers the ability to set colour limits for the current axis using CAXIS. OpenCV has applyColorMap which can be used to highlight differences in pixel intensity in a greyscale image which I believe maps pixel from 0 - 255.
I am new to Matlab/Image-processing and have been asked to port a simple program from MatLab which uses the CAXIS function to change the "brightness" of a colour map. I have no experience in Matlab but it appears that they use this function to "lower" the intensity requirements needed for pixels to be mapped to a more intense colour on the map
i.e. Colour map using "JET"
When brightness = 1, red = 255
When brightness = 10, red >= 25
The matlab program allows 16bit images to be read in and displayed which obviouly gives higher pixel values whereas everything i've read and done indicates OpenCV only supports 8 bit images (for colour maps)
Therefore my question is, is it possible to provide similar functionality in OpenCV? How do you set the axis limit for a colourmap/how do you scale the colour map lookup table so that "less" intense pixels are scaled to the more intense regions?
A similar question was asked with a reply stating the array needs to be "normalised" but unfortunately I don't quite know how to achieve this and can't reply to the answer as i don't have enough rep!
I have gone ahead and used cv::normalize to set the max value in the array to be maxPixelValue/brightness but that doesn't work at all.
I have also experimented and tried converting my 16bit image into a CV_8UC1 with a scale factor to no avail. Any help would be greatly appreciated!
In my opinion you can use cv::normalize to "crop" values in the source picture to the corresponding ones in color map you are interested in. Say you want your image to be mapped to the blue-ish region of Jet colormap then you should do something like:
int minVal = 0, maxVal = 80;
cv::normalize(src,dst, minVal, maxVal, cv::NORM_MINMAX);
If you plan to apply some kind of custom map it's fairly easy for 1-or3-channel 8-bit image, you only need to create LUT with 255 values (with proper number of channels) and apply it using cv::LUT, more about it in this blog, also see the dosc about LUT
If the image you are working is of different depth, 16-bit or even floating point data I guess all you need to do is write a function like:
template<class T>
T customColorMapper(T input_pixel)
{
T output_pixel = 0;
// do something with output_pixel basing on intput_pixel
return output_pixel;
}
and apply it to each source image pixel like:
cv::Mat dst_image = src_image.clone(); //copy data
dst_image.forEach<TYPE>([](TYPE& input_pixel, const int* pos_row_col) -> void {
input_pixel = customColorMapper<TYPE>(input_pixel);
});
of course TYPE need to be a valid type. Maybe specialized version of this function taking cv::Scalar or cv::Vec3-something would be nice if you need to work with multiple channels.
Hope this helps!
I managed to replicate the MATLAB behaviour but had to resort to manually iterating over each pixel and setting the value to the maximum value for the image depth or scaling the value where needed.
my code looked something like this
cv::minMaxLoc(dst, &min, &max);
double axisThreshold = floor(max / contrastLevel);
for (int i = 0; i < dst.rows; i++)
{
for (int j = 0; j < dst.cols; j++)
{
short pixel = dst.at<short>(i, j);
if (pixel >= axisThreshold)
{
pixel = USHRT_MAX;
}
else
{
pixel *= (USHRT_MAX / axisThreshold);
}
dst.at<short>(i, j) = cv::saturate_cast<short>(pixel);
}
}
In my example I had a slider which adjusted the contrast/brightness (we called it contrast, the original implementation called it brightness).
When the contrast/brightness was changed, the program would retrieve the maximum pixel value and then compute the axis limit by doing
calculatedThreshold = Max pixel value / contrast
Each pixel more than the threshold gets set to MAX, each pixel lower than the threshold gets multiplied by a scale factor calculated by
scale = MAX Pixel Value / calculatedThreshold.
TBH i can't say I fully understand the maths behind it. I just used trial and error until it worked; any help in that department would be appreciated HOWEVER it seems to do what i want to!
My understanding of the initial matlab implementation and the terminology "brightness" is in fact their attempt to scale the colourmap so that the "brighter" the image, the less intense each pixel had to be to map to a particular colour in the colourmap.
Since applycolourmap only works on 8 bit images, when the brightness increases and the colourmap axis values decrease, we need to ensure the values of the pixels scale accordingly so that they now match up with the "higher" intensity values in the map.
I have seen numerous OPENCV tutorials which use this approach to changing the contrast/brightness but they often promote the use of optimised convertTo (especially if you're trying to use the GPU). However as far as I can see, convertTo applies the aplha/beta values uniformly and not on a pixel by pixel basis therefore I can't use that approach.
I will update this question If i found more suitable OPENCV functions to achieve what I want.
I have a QColor value and I need to break it down into its RGB components between 0 and 1 with only one value after decimal point.
For example: Orange color is
QColor color = QColor(255,128,0)
qreal green = color.greenF();
qDebug() << green; //0.501960784
Whereas the green component must be 0.6. That is, it's rgb value is (255,128,0) or (1,0.6,0).
How to get 0.6 instead of 0.501960784?
But Orange color is 255,128,0
There is no such thing as "the" orange color. Everyone calls something else using the same word. Orange isn't a color, it's a range of hues. Those hues become colors once you assign them some saturation and brightness. There's a whole lot of colors that can be represented using an 8-bit-per-componet R,G,B triple that all have a hue that is orange, and that thus qualify as an orange. There's no the orange,
Whereas the green component must be 0.6. That is, it's rgb value is (255,128,0) or (1,0.6,0).
It's not. QColor tells you so, and basic math tells you so. The color clearly is 1/0.6/0, or 1*255, 6/10*255, 0*255, or 255, 1530/10, 0 or 255, 153, 0 exactly. It won't ever be 255,128,0 and I have no idea who told you that, but they were wrong.
So it's really simple: forget it all. Just use QColor::redF, greenF and blueF. They work the way they should.
Oh, and you didn't even mention the elephants in the room that are color spaces. An RGB triple has no physical meaning - it's entirely abstract - until you map it to a physical color space. And you better use calibrated output devices to interface your color choice with the user, otherwise it'll be endless silliness all around.
I'm attempting to convert 12-bit RGGB color values into 8-bit RGGB color values, but with my current method it gives strange results.
Logically, I thought that simply dividing the 12-bit RGGB into 8-bit RGGB would work and be pretty simple:
// raw_color_array contains R,G1,G2,B in a bayer pattern with each element
// ranging from 0 to 4096
for(int i = 0; i < array_size; i++)
{
raw_color_array[i] /= 16; // 4096 becomes 256 and so on
}
However, in practice this actually does not work. Given, for example, a small image with water and a piece of ice in it you can see what actually happens in the conversion (right most image).
Why does this happen? and how can I get the same (or close to) image on the left, but as 8-bit values instead? Thanks!
EDIT: going off of #MSalters answer, I get a better quality image but the colors are still drasticaly skewed. What resources can I look into for converting 12-bit data to 8-bit data without a steep loss in quality?
It appears that your raw 12 bits data isn't on a linear scale. That is quite common for images. For a non-linear scale, you can't use a linear transformation like dividing by 16.
A non-linear transform like sqrt(x*16) would also give you an 8 bits value. So would std::pow(x, 12.0/8.0)
A known problem with low-gradient images is that you get banding. If your images has an area where the original value varies from say 100 to 200, the 12-to-8 bit reduction will shrink that to less than 100 different values. You get rounding , and with naive (local) rounding you get bands. Linear or non-linear, there will then be some inputs x that all map to y, and some that map to y+1. This can be mitigated by doing the transformation in floating point, and then adding a random value between -1.0 and +1.0 before rounding. This effectively breaks up the band structure.
After you clarified that this 12bit data is only for one color, here is my simple answer:
Since you want to convert its value to its 8 bit equivalent, it obviously means you lost some of the data (4bits). This is the reason why you are not getting the same output.
After clarification:
If you want to retain the actual colour values!
Apply de-mosaicking in the 12 Bit image and then scale the resultant data to 8 - Bit. So that the colour loss due to de-mosaicking will be less compared to the previous approach.
You say that your 12-bits represent 2^12 bits of one colour. That is incorrect. There are reds, greens and blues in your image. Look at the histogram. I made this with ImageMagick at the command line:
convert cells.jpg histogram:png:h.png
If you want 8-bits per pixel, rather than trying to blindly/statically apportion 3 bits to Green, 2 bits to Red and 3 bits to Blue, you would probably be better off going with an 8-bit palette so you can have 250+ colours of all variations rather than restricting yourself to just 8 blue shades, 4 reds an 8 green. So, like this:
convert cells.jpg -colors 254 PNG8:result.png
Here is the result of that beside the original:
The process above is called "quantisation" and if you want to implement it in C/C++, there is a writeup here.
I have a mat of this type
Mat port(M.size(),CV_8UC1);
and inside I have the 2 values: 0 and 1.
If I try to do imshow ( " p " , port) ;
img by a black .
How can I distinguish all 0 and 1 with two different colors ?
I tried and tried to use line() but you must already know the two closest points while I do not know what the values 1 distanced from each other .
someone can help me ?
It seems a trivial problem
Try scaling your data for display: imshow(" p ", port*255);
A gray value of 1 is almost indistinguishable from full black and will not be discernible on any normal monitor/screen. Scaling by 255 will make these pixels appear white.
Note that the scaling is done only for the display and do not affect the image itself.
Please see the imshow() docs for what scaling is done and the values for display:
The function may scale the image, depending on its depth:
If the image is 8-bit unsigned, it is displayed as is.
If the image is 16-bit unsigned or 32-bit integer, the pixels are divided by 256. That is, the value range [0,255*256] is mapped to [0,255].
If the image is 32-bit floating-point, the pixel values are multiplied by 255. That is, the value range [0,1] is mapped to [0,255].
I'm trying to draw an 8-bit style games character (link from Zelda) as i'm practicing OpenGL.
I've started with his face, which is the big square to the right, and have drawn his eye which is two blocks to the right of the start of his face... (6 blocks, the 2 left most is an eye)
The top of the eye (the block above the green block) should be dark green (see code) but it keeps adopting the colour of the first larger block (the face).
I hope this makes sense...
Please see this picture:
What am i doing wrong for it to keep changing its colour?
I'm assuming i need to do something more for it to accept RGB colours? glColor3f(29, 137, 59);...
glColor3f accepts a floating point argument. By doing this, the large numbers will be cast to floats, and therefore become 29.0f, 137.0f and 59.0f. Given colours are represented in the range of 0-1, these get clamped to the range 0-1 and of course, appear white (1.0, 1.0, 1.0).
Use glColor3ub instead. It accepts an unsigned byte as its argument, which is in the range of 0-255, which is probably what you're most used to. There's other forms such as glColor3i, glColor3s, glColor3ui, glColor3us etc which accept integers and shorts (and their unsigned variants) which are defined over the range of integers and shorts. These simply get converted to the decimal variant internally (e.g. decimal = int / INT_MAX).