YUV image processing - java

I'm developing an android app that for every YUV image passed from camera, it randomly pick 10 pixels from it and check if they are red or blue.
I know how to do this for RGB images, but not for YUV format.
I cannot convert it pixel by pixel into a RGB image because of the run time constrains.

I'm assuming you're using the Camera API's preview callbacks, where you get a byte[] array of data for each frame.
First, you need to select which YUV format you want to use. NV21 is required to be supported, and YV12 is required since Android 3.0. None of the other formats are guaranteed to be available. So NV21 is the safest choice, and also the default.
Both of these formats are YUV 4:2:0 formats; the color information is subsampled by 2x in both dimensions, and the layout of the image data is fairly different from the standard interleaved RGB format. FourCC.org's NV21 description, as one source, has the layout information you want - first the Y plane, then the UV data interleaved. But since the two color planes are only 1/4 of the size of the Y plane, you'll have to decide how you want to upsample them - the simplest is nearest neighbor. So if you want pixel (x,y) from the image of size (w, h), the nearest neighbor approach is:
Y = image[ y * w + x];
U = image[ w * h + floor(y/2) * (w/2) + floor(x/2) + 1]
V = image[ w * h + floor(y/2) * (w/2) + floor(x/2) + 0]
More sophisticated upsampling (bilinear, cubic, etc) for the chroma channels can be used as well, but what's suitable depends on the application.
Once you have the YUV pixel, you'll need to interpret it. If you're more comfortable operating in RGB, you can use these JPEG conversion equations at Wikipedia to get the RGB values.
Or, you can just use large positive values of V (Cr) to indicate red, especially if U (Cb) is small.

From the answer of Reuben Scratton in
Converting YUV->RGB(Image processing)->YUV during onPreviewFrame in android?
You can make the camera preview use RGB format instead of YUV.
Try this:
Camera.Parameters.setPreviewFormat(ImageFormat.RGB_565);

YUV is just another colour space. You can define red in YUV space just as you can in RGB space. A simple calculator suggests an RGB value of 255,0,0 (red) should appear as something like 76,84,255 in YUV space so just look for something close to that.

Related

why the grayscale image has 3 channels

i am performing operations on a grayscale image, and the resultant image of these operations has the same extension as the input image. for an example if the input image is .jpg or .png the output image is either .jpg or .png respectively.
and I am converting the image into grayscale as follows:
ImgProc.cvtColor(mat, grayscale, ImgProc.COLOR_BGR2GRAY),
and I am checking the channels count using:
.channels()
the problem is when I wnat to know how many channels the image contain, despit it is a grayscale image, i always receive umber of channels = 3!!
kindly please let me know why that is happening
The depth (or better color depth) is the number of bits used to represent a color value. a color depth of 8 usually means 8-bits per channel (so you have 256 color values - or better: shades of grey- per channel - from 0 to 255) and 3 channels mean then one pixel value is composed of 3*8=24 bits.
However, this also depends on nomenclature. Usually you will say
"Color depth is 8-bits per channel"
but you also could say
"The color depth of the image is 32-bits"
and then mean 8 bits per RGBA channel or
"The image has a color depth of 24-bits"
and mean 8-bits per R,G and B channels.
The grayscale image has three channels because technically it is not a grayscale image. It is a colored image with the same values for all the three channels (r, g, b) in every pixel. Therefore, visually it looks like a grayscale image.
To check the channels in the image, use-
img.getbands()

DCT implementation

I'm trying to implement image compression algorithm based on DCT for color JPEG. I'm newbie in image processing so I need some help. What I need is clarification of an algorithm.
I'm using DCT implementation from here
So, here is the algorithm as I understood it:
Load an image using ImageIO into BufferedImage.
Create 3 matrices (1 for each channel: red, green, blue):
int rgb = bufferedImage.getRGB(i, j);
int red = (rgb >> 16) & 0xFF;
int green = (rgb >> 8) & 0xFF;
int blue = rgb & 0xFF;
Increase matrices to the size so they can be split in chunks 8x8 (where 8 is the size of DCT matrix, N)
For each matrix, split it into chunks of the size 8x8 (result: splittedImage)
Perform forwardDCT on matrices from splittedImage (result: dctImage).
Perform quantization on matrices from dctImage (result: quantizedImage)
Here I don't know what to do. I can:
merge quantizedImage matrices into one matrix margedImage, convert it into Vector and perform compressImage method.
or convert small matrices from quantizedImage into Vector and perform compressImage method on them, and then marge them into one matrix
So, here I got 3 matrices for red, green and blue colors. Than I convert those matrices into one RGB matrix and create new BufferedImage and using method setRGB to set pixel values. Then perform saving image to file.
Extra questions:
Is it better to convert RGB into YCbCr and perform DCT on Y, Cb and Cr?
Javadoc of compressImage method says that it's not Huffman Encoding, but Run-Length encoding. So will the compressed image be opened by image viewer? Or I should use Huffman Encoding according to JPEG specification, and is there any open source Huffman Encoding implementation in Java?
If you want to follow the implementation steps, I suggest reading:
http://www.amazon.com/Compressed-Image-File-Formats-JPEG/dp/0201604434/ref=sr_1_1?ie=UTF8&qid=1399765722&sr=8-1&keywords=compressed+image+file+formats
In regard your questions:
1) The JPEG standard knows nothing about color spaces and does not care whether you use RGB or YCbCr, or CMYK. There are several JPEG file format (e.g., JFIF, EXIF, ADOBE) that specify the color spaces--usually YCbCr.
The reason for using YCbCr is that if follows the JPEG trend of concentrating information. There tends to be more useful information in the Y component than the Cb or Cr components. Using YCbCr, you can sample 4 Ys for ever Cb and Cr (or even 16) for every Y. That reduces the amount of data to be compressed by 1/2.
Note that the JPEG file formats specify limits on sampling (JPEG allows 2:3 sampling while most implementations do not).
2) The DCT coefficients are Runlength encoded then huffman (or arithmetic) encoded. You have to use both.

Libary/method for loading a HDR/high-bittage image and accessing its pixel values?

Short;
I need to get the value of a specific pixel from a supplied high color depth image.
Details:
I am currently using Processing to make a Slit-scanning program.
Essentially, I am using a greyscale image to pick frames from an animation, and using pixels from those frames to make a new image.
For example if the greyscale image has a black pixel, it takes the same pixel in the first frame, and adds it to an image.
If its a white pixel, it does the same with the last frame.
Anything inbetween, naturally, picks the frames inbetween.
The gist is, if supplied a horizontal gradient, and a video of a sunset, then youd have the start of the sunset on the left, slowly transitioning to the end on the right.
My problem is, when using Processing, I seem to be only able to get greyscale values of
0-255 using the default library.
Black = 0
White = 255
This limits me to using only 256 frames for the source animation, or to put up with a pixaly, unsmooth end image.
I really need to be able to supply, and thus get, pixel values in a much bigger range.
Say,
Black = 0
White = 65025
Is there any Java lib that can do this? That I can supply, say, a HDR Tiff or TGA image file, and be able to read the full range of color out of it?
Thanks,
Ok, found a great library for this;
https://code.google.com/p/pngj/
Supports the full PNG feature set - including 16 bit greyscale or full color images.
Allows me to retrieve rows from a image, then pixels from those rows.
PngReader pngr = new PngReader(new File(filename));
tmrows = pngr.readRows();
ImageLineInt neededline = (ImageLineInt)tmrows.getImageLine(y);
if (neededline.imgInfo.greyscale==true){
//get the right pixel for greyscale
value = neededline.getScanline()[x];
} else {
//get the right pixel for RGB
value = neededline.getScanline()[x*3];
}
You simply multiply by 3 as the scanline consists of RGBRGBRGB (etc) for a full color image without alpha.

make a lightness histogram with luminance, Lab and sRGB space in Java

I have to create a lightness histogram of an image. I have already maked a RGB Histogram
On Internet i found these values:
Luminance (standard, objective): (0.2126*R) + (0.7152*G) + (0.0722*B)
Luminance (perceived option 1): (0.299*R + 0.587*G + 0.114*B)
Luminance (perceived option 2, slower to calculate): sqrt( 0.241*R^2 + 0.691*G^2 + 0.068*B^2 )
I make lightness histogram throught these values or luminance is a different stuff?
Or maybe i use java libraries with methods to take L value (lightness) from a Lab space, converting the sRGB space?
As far as I know, the Luminance formula you listed are used to describe Perceived brightness. Luminance is also used in the video industry to characterize the brightness of displays.
Since you have hist(R), hist(G), hist(B) already, it's easy to do a linear transform into Luminance using the first two formulas. Try to plot the resulting Luminance chart for some images you have. The best way is always to try and see the difference.

Dynamically creating colors with different brightness

I have a color, which I only know at runtime. Using this color i want to create two new colors, one very bright and one none bright version of the color.
So to clarify, say i have the color Red; I want to create the hex-value for a "Light red" color, and a "Dark red" color.
How would i go about doing this? My code is written in Java using GWT.
Convert the colours to the HSB/HSV (Hue-Saturation-Brightness/Value ) space and adjust the Brightness up for lighter and down for darker. Then convert back again. In Java:
import java.awt.Color;
float hsbVals[] = Color.RGBtoHSB( originalColour.getRed(),
originalColour.getGreen(),
originalColour.getBlue(), null );
Color highlight = Color.getHSBColor( hsbVals[0], hsbVals[1], 0.5f * ( 1f + hsbVals[2] ));
Color shadow = Color.getHSBColor( hsbVals[0], hsbVals[1], 0.5f * hsbVals[2] );
The HSB space is designed for this kind of operation.
The essential point is that you only need to vary the Brightness term to get the lightening/darkening effect you want. You'll have to experiment with how much you lighten/darken.
The above code shifts the Brightness to half-way towards white for the highlight and half-way to black for the shadow. (I used this code to create a highlighted border effect on a button.)
See: http://en.wikipedia.org/wiki/HSL_and_HSV and http://www.acasystems.com/en/color-picker/faq-hsb-hsv-color.htm
Edit: According to the comments, the java.awt.Color class can't be used in GWT. Since the only part of theColor class we're using are the HSV to RGB and the RGB to HSV conversions, as you're using GWT you could instead google for an implementation of those algorithms: Google HSV RGB conversion algorithm. For example:
javascripter.net
cs.rit.edu/~ncs
rapidtables.com (RGB to HSV)
rapidtables.com (HSV to RGB)
StackOverflow: Algorithm to convert RGB to HSV and HSV to RGB?
There are at least two decent solutions to this, one better (more 'proper', anyway) than the other. It depends on what you want to use the colour for, or a tradeoff against short and simple code.
Using a colour space that models brightness
The problem is your colours are probably specified as RGB (ie, amounts of red, green and blue, reflecting your monitor.) The best way to change a colour's brightness is to specify your colours in a different colour space where brightness is one component, such as HSB - hue (the 'colour'), saturation ('amount' of the colour) and brightness (self-explanatory, I think!)
This Wikipedia article on HSL and HSV color models explains far more than you probably want to know :)
Have a look at this HSB demo.
The point is, once your colours are specified in a different space where one component is brightness, changing the brightness is easy because you can increase or decrease that component as you wish, in the same way you might increase or decrease the amount of blue in a RGB colour. Java, I think, has some colour conversion functions built in - some googling found this page with a handy example of Color.RGBtoHSB() and going back again with Color.HSBtoRGB.
Blending with white or black
This is hackier, but effective in most situations, and most code I've written that needs to get two versions of a colour (for a gradient, for example) for something unimportant like a UI background uses this sort of method. The logic is that a colour will be brighter as it gets closer to white (RGB 255,255,255) and darker as it gets closer to black (RGB 0,0,0). So to brighten something, blend with white by, say, 25%. You can blend between two colours by taking a proportion of one colour, and the inverse of that proportion of the other, for each channel / component.
The following is untested, and is a conversion of Delphi code I have used to do the same thing (the code is taken from memory, and on top of that I haven't used Java for years and don't remember the syntax and classes well, so I don't expect this to compile but you should be able to get an idea):
Color Blend(Color clOne, Color clTwo, float fAmount) {
float fInverse = 1.0 - fAmount;
// I had to look up getting colour components in java. Google is good :)
float afOne[] = new float[3];
clOne.getColorComponents(afOne);
float afTwo[] = new float[3];
clTwo.getColorComponents(afTwo);
float afResult[] = new float[3];
afResult[0] = afOne[0] * fAmount + afTwo[0] * fInverse;
afResult[1] = afOne[1] * fAmount + afTwo[1] * fInverse;
afResult[2] = afOne[2] * fAmount + afTwo[2] * fInverse;
return new Color (afResult[0], afResult[1], afResult[2]);
}
And you'd probably use it like:
Color clBrighter = Blend(Color.red, Color.white, 0.25);
You might want to add some safety code, such as ensuring a clamp between 0..255 for each component, or checking that dAmount is truly in the range 0..1.
The Java Color documentation looks like the Color class has all sorts of useful methods. (Edit: I just noticed you said you're using gwt not awt - I haven't used it and have no idea what classes from standard Java are included. This should point you in the right direction anyway.) It's possible this is not the cleanest way in Java - that'll be due to my lack of knowledge of the classes and methods these days - but it should be enough to get you well down the track. Hope that helps!
I don't know in wich format you have the color (I tried to see if GWT uses colors... but they rely heavily on CSS so they don't have specific properties).
Anyway, if you have one value for each component (Red, green, Blue), and each value ranges between 0 and 255 -this is standard- then apply this algorithm:
for each component
multiply the original value by a factor (let's say 1.1, 10% more bright)
convert the float/double value to int
if this value surpass 255, cut it to 255
Then you'll have a new color (a new three component tuple).
Hexa colors
If you have colors in the web format:
RRGGBB
RR - two hexa digits for red
GG - two hexa digits for green
BB - two hexa digits for blue
you'll need to convert them to int and back to hexa:
Hexa string to int
Integer.parseInt("AB", 16"); // returns 171
int to Hexa string
Integer.toHexaString(171); // returns "AB"
Since you are using GWT, you should do your color calculations using HSL rather then RGB, as it's more intuitive, and can be applied as a style color directly to your components.
Your initial color is "red" is defined as "color: hsl(0,100%, 50%)", see http://www.w3.org/TR/css3-color/#hsl-color for more on style colors.
To get a light red, all you need is to increase the L (lightness) component, so a light red would be "color: hsl(0,100%, 75%)". To get a dark red, decrease the L component, "color: hsl(0,100%, 25%)"
To apply your color, just set the color using
component.getElement().getStyle().setColor("hsl(0,100%, 25%)")
Just Add the following function to your code. It will return the hash value for lighter and darker color as per your requirement.
pass two arguments.
(1) the hash value of your selected color.
(2) how much lighter or darker you want (Ex. if you want 10% lighter shade then pass 0.1 as the second argument and if you want 40% darker then pass -0.4(negative value for darker) as the second argument)
So if you want to find 20% lighter shade of red then call as below
String lightred=convert("ff0000",0.2);
public static String convert(String hex, double num) {
String rgb = "#",temp;
int i;
double c,cd;
for (i = 0; i < 3; i++) {
c = Integer.parseInt(hex.substring(i * 2,(i*2)+2), 16);
c = Math.min(Math.max(0, c+(255*num)), 255);
cd=c-(int)c;
if(cd>0){c=(int)c+1;}
temp = Integer.toHexString((int)c);
if(temp.length()<2)
{
temp=temp+temp;
}
rgb += temp;
}
return rgb;
}

Categories

Resources