I'm a bit naive when it comes to bitwise logic and I have what is probably a simple question... basically if I have this (is ActionScript but can apply in many languages):
var color:uint = myObject.color;
var red:uint = color >>> 16;
var green:uint = color >>> 8 & 0xFF;
var blue:uint = color & 0xFF;
I was wondering what exactly the `& 0xFF' is doing to green and blue. I understand what an AND operation does, but why is it needed (or a good idea) here?
The source for this code was here: http://alexgblog.com/?p=680
Appreciate the tips.
Alex
In RGB you have 8 bits for Red, 8 bits for Green and 8 bits for Blue. You are storing the 3 bytes in an int, which has 4 bytes in this way:
Bits from 0-7(least significant) for Blue.
Bits from 8-15(least significant) for Green.
Bits from 16-23(least significant) for Red.
To extract them to separate values you need to right shift the correct number of bits in order to put the byte corresponding to the color you want to extract in the least significant byte of the int, and then put the rest of the int in 0 so as to let that byte value only. The last part is done by using the AND operation with mask 0xFF. The AND leaves the only byte of the int where it is applied with the same value, leaving the rest bytes in 0.
This is what happens:
var color:uint = myObject.color;
You have the color variable like this: 0x00RRGGBB
var red:uint = color >>> 16;
Right-shifting 16 bits color results in: 0x000000RR, resulting in the red value.
But for:
var green:uint = color >>> 8 & 0xFF;
After right-shifting color 8 bits it leaves this result 0x0000RRGG, but here we only need the GG bits left so we apply the AND operation with the mask 0xFF or to be more clear 0x000000FF, as you show know AND leaves the old bits values where the mask is 1 and zeros there the mask is 0, so the result of doing 0x0000RRGG & 0x000000FF = 0x000000GG which is the value for green. The same is applied to extract the blue value.
Related
Can anybody tell me the correct java code for this c++ code snippet:
output.at(x, y) = target.at(dx, dy);
I have tried this java code and they are displacing pixel but not showing image clearly :
output.put(x, y, target.get(dx, dy));
For one channel images e.g. grey-scale; 0 ~ 255
Getting a pixel value
double pixelValue = image.get(i,j)[0];
Setting a pixel value
image.put(i,j,230);
For 3 channel images e.g. RGB (3 values 0 ~ 255)
Getting a pixel (double[] array will have 3 values)
double[] pixelValue = image.get(i,j);
Setting a pixel with 3 RGB values
image.put(i,j,255,250,100); // yellow color
I am looking to analyze the most dominant color in a UIImage on iOS (color present in the most pixels) and I stumbled upon Core Image's filter based API, particularly CIAreaHistogram.
It seems like this filter could probably help me but I am struggling to understand the API. Firstly it says the output of the filter is a one-dimensional image which is the length of your input-bins and one pixel in height. How do I read this data? I basically want to figure out the color-value with the highest frequency so I am expecting the data to contain some kind of frequency count for each color, its not clear to me how this one-dimensional image would represent that because it does not really explain the data I can expect inside this 1-d image. And if its truly a histogram why would it not return a data-structure representing that like a dictionary
Second, in the API it asks for a number of bins? What should that input be? If I want an exact analysis would the input bin parameter be the color-space of my image? What does making the bin value smaller do, I would imagine it just approximates nearby colors via Euclidean distance to the nearest bin. If this is the case will that not yield exact histogram results, why would anyone want to do that?
Any input on the above two questions from an API perspective would help me greatly
Ian Ollmann's idea of calculating the histogram just for the hue is really neat and can be done with a simple color kernel. This kernel returns a monochrome image of just the hue of an image (based on this original work)
let shaderString = "kernel vec4 kernelFunc(__sample c)" +
"{" +
" vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);" +
" vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));" +
" vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));" +
" float d = q.x - min(q.w, q.y);" +
" float e = 1.0e-10;" +
" vec3 hsv = vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);" +
" return vec4(vec3(hsv.r), 1.0);" +
"}"
let colorKernel = CIColorKernel(string: shaderString)
If I get the hue of an image of a blue sky, the resulting histogram looks like this:
...while a warm sunset gives a histogram like this:
So, that looks like a good technique to get the dominant hue of an image.
Simon
CIAreaHistogram returns an image where the reg, green, blue and alpha values of each of the pixels indicates the frequency of that tone in the image. You can render that image to an array of UInt8 to look at the histogram data. There's also an undocumented outputData value:
let filter = CIFilter(
name: "CIAreaHistogram",
withInputParameters: [kCIInputImageKey: image])!
let histogramData = filter.valueForKey("outputData")
However, I've found vImage to be a better framework for working with histograms. First off, you need to create a vImage image format:
var format = vImage_CGImageFormat(
bitsPerComponent: 8,
bitsPerPixel: 32,
colorSpace: nil,
bitmapInfo: CGBitmapInfo(
rawValue: CGImageAlphaInfo.PremultipliedLast.rawValue),
version: 0,
decode: nil,
renderingIntent: .RenderingIntentDefault)
vImage works with image buffers that can be created from CGImage rather than CIImage instances (you can create one with the createCGImage method of CIContext. vImageBuffer_InitWithCGImage will create an image buffer:
var inBuffer: vImage_Buffer = vImage_Buffer()
vImageBuffer_InitWithCGImage(
&inBuffer,
&format,
nil,
imageRef,
UInt32(kvImageNoFlags))
Now to create arrays of Uint which will hold the histogram values for the four channels:
let red = [UInt](count: 256, repeatedValue: 0)
let green = [UInt](count: 256, repeatedValue: 0)
let blue = [UInt](count: 256, repeatedValue: 0)
let alpha = [UInt](count: 256, repeatedValue: 0)
let redPtr = UnsafeMutablePointer<vImagePixelCount>(red)
let greenPtr = UnsafeMutablePointer<vImagePixelCount>(green)
let bluePtr = UnsafeMutablePointer<vImagePixelCount>(blue)
let alphaPtr = UnsafeMutablePointer<vImagePixelCount>(alpha)
let rgba = [redPtr, greenPtr, bluePtr, alphaPtr]
let histogram = UnsafeMutablePointer<UnsafeMutablePointer<vImagePixelCount>>(rgba)
The final step is to perform the calculation, which will populate the four arrays, and free the buffer's data:
vImageHistogramCalculation_ARGB8888(&inBuffer, histogram, UInt32(kvImageNoFlags))
free(inBuffer.data)
A quick check of the alpha array of an opaque image should yield 255 zeros with the final value corresponding to the number of pixels in the image:
print(alpha) // [0, 0, 0, 0, 0 ... 409600]
A histogram won't give you the dominant color from a visual perspective: an image which is half yellow {1,1,0} and half black {0,0,0} will give the same results as an image which is half red {1,0,0} and held green {0,1,0}.
Hope this helps,
Simon
One problem with the histogram approach is that you lose correlation between the color channels. That is, half your image could be magenta and half yellow. You will find a red histogram that is all in the 1.0 bin, but the blue and green bins would be evenly split between 0.0 and 1.0 with nothing in between. Even though you can be quite sure that red is bright, you won't be able to say much about what the blue and green component should be for the "predominant color"
You could use a 3D histogram with 2**(8+8+8) bins, but this is quite large and you will find the signal is quite sparse. By happenstance three pixels might land in one bin and have no two the same elsewhere, even though many users could tell you that there is a predominant color and it has nothing to do with that pixel.
You could make the 3D histogram a lot lower resolution and have (for example) just 16 bins per color channel. It is much more likely that bins will have a statistically meaningful population count this way. This should give you a starting point to find a mean for a local population of pixels in that bin. If each bin had a count and a {R,G,B} sum, then you could quickly find the mean color for pixels in that bin once you had identified the most popular bins. This method is still subject to some influence from the histogram grid. You will be more likely to identify colors in the middle of a grid cell than at the edges. Populations may span multiple grid cells. Something like kmeans might be another method.
If you just want predominant hue, then conversion to a color space like HSV followed by a histogram of hue would work.
I'm not aware of any filters in vImage, CI or MetalPerformanceShaders to do these things for you. You can certainly write code in either the CPU or Metal to do it without a lot of trouble.
I got an image from a bigger image by
let partialCGImage = CGImageCreateWithImageInRect(CGImage, frame)
but sometimes I got wrong RGBA value. For example, I calculated the average red values of an image, but it turned out like a gray image.
So I checked the info as follow.
image width: 64
image height: 64
image has 5120 bytes per row
image has 8 bits per component
image color space: <CGColorSpace 0x15d68fbd0> (kCGColorSpaceICCBased; kCGColorSpaceModelRGB; sRGB IEC61966-2.1)
image is mask: false
image bitmap info: CGBitmapInfo(rawValue: 8194)
image has 32 bits per pixel
image utt type: nil
image should interpolate: true
image rendering intent: CGColorRenderingIntent
Bitamp Info: ------
Alpha info mask: Ture
Float components: False
Byte oder mask: Ture
Byte order default: False
Byte order 16 little: False
Byte order 32 little: Ture
Byte order 16 big: Ture
Byte order 32 big: False
Image Info ended---------------
Then I got a really weird problem, why the width and height are both 64 pxs, and the image has 8 bits(1 byte) per component(4 bytes per pixel), but the bytes per row is 5120?
And I notice the bitmap info of the normal image is quite different, it doesn't has any byte order infomation.
I googled the different between little endian and big endian, but I got confused when they showed up together.
I really need help since my project has already delayed for 2 days because of that. Thanks!
By the way, I used following code to get the RGBA value.
let pixelData=CGDataProviderCopyData(CGImageGetDataProvider(self.CGImage))
let data:UnsafePointer<UInt8> = CFDataGetBytePtr(pixelData)
var rs: [[Int]] = []
var gs: [[Int]] = []
var bs: [[Int]] = []
let widthMax = imageWidth
let heightMax = imageHeight
for indexX in 0...widthMax {
var tempR: [Int] = []
var tempG: [Int] = []
var tempB: [Int] = []
for indexY in 0...heightMax {
let offSet = 4 * (indexX * imageWidth + indexY)
**let r = Int(data[pixelInfo + offSet])
let g = Int(data[pixelInfo + 1 + offSet])
let b = Int(data[pixelInfo + 2 + offSet])**
tempR.append(r)
tempG.append(g)
tempB.append(b)
}
rs.append(tempR)
gs.append(tempG)
bs.append(tempB)
}
Ask me if you have problem with my code. Thank you for help.
The bytes-per-row is 5120 because you used CGImageCreateWithImageInRect on a larger image. From the CGImage reference manual:
The resulting image retains a reference to the original image, which means you may release the original image after calling this function.
The new image uses the same pixel storage as the old (larger) image. That's why the new image retains the old image, and why they have the same bytes-per-row.
As for why you're not getting the red values you expect: Rob's answer has some useful information, but if you want to explore deeper, consider that your bitmap info is 8194 = 0x2002.
print(CGBitmapInfo.ByteOrder32Little.rawValue | CGImageAlphaInfo.PremultipliedFirst.rawValue)
# Output:
8194
These bits determine the byte order of your bitmap. But those names aren't all that helpful. Let's figure out exactly what byte order we get for those bits:
let context = CGBitmapContextCreate(nil, 1, 1, 8, 4, CGColorSpaceCreateDeviceRGB(), CGBitmapInfo.ByteOrder32Little.rawValue | CGImageAlphaInfo.PremultipliedFirst.rawValue)!
UIGraphicsPushContext(context)
let d: CGFloat = 255
UIColor(red: 1/d, green: 2/d, blue: 3/d, alpha: 1).setFill()
UIRectFill(.infinite)
UIGraphicsPopContext()
let data = UnsafePointer<UInt8>(CGBitmapContextGetData(context))
for i in 0 ..< 4 {
print("\(i): \(data[i])")
}
# Output:
0: 3
1: 2
2: 1
3: 255
So we can see that a bitmap info of 8194 means that the byte order is BGRA. Your code assumes it's RGBA.
In addition to the question about pixelInfo, raised by Segmentation, the calculation of offSet seem curious:
let offSet = 4 * (indexX * imageWidth + indexY)
The x and y values are backwards. Also, you also cannot assume that the bytes per row is always equal to 4 times the width in pixels because some image formats pad bytes per row. Anyway, it theoretically it should be:
let offSet = indexY * bytesPerRow + indexX * bytesPerPixel
Also note that in addition to the x/y flip issue, you don't want 0 ... widthMax and 0 ... heightMax (as those will return widthMax + 1 and heightMax + 1 data points). Instead, you want to use 0 ..< widthMax and 0 ..< heightMax.
Also if you're dealing with random image files, there are other deeper problems here. For example, you can't make assumptions regarding RGBA vs ARGB vs CMYK, big endian vs little endian, etc., captured in the bitmap info field.
Rather than writing code that can deal with all of these variations in pixel buffers, Apple suggests alternative to take the image of some random configuration and render it to some consistent context configuration, and then you can navigate the buffer more easily. See Technical Q&A #1509.
First of all you haven't initialize pixelInfo variable. Second you aren't doing anything with the A value shifting everything 8bits to the left. Also i don't think you need pixelInfo and offset, these two variables are the same so keep one of them equal to what you wrote for offset
Hi guys,
I'm trying to reduce the number of bits per pixel to below 8, on gray scale images using Scilab
Is this possible?
If so, how can I do this?
Thank you.
I think it is not possible. The integer types available in Scilab are one or multiple bytes, see types here.
If you are looking to loose the high frequency information, you could shift out information.
Pseudo implementation
for x=1:width
for y=1:height
// Get pixel and make a 1 byte integer
pixel = int8(picture(x,y))
//Display bits
disp( dec2bin(pixel) )
// We start out with 8 bits - 4 = 4 bits info
bits_to_shift = 4
shifted_down_pixel = pixel/(2^bits_to_shift)
//Display shifted down
disp( dec2bin(shifted_down_pixel))
//Shift it back
shifted_back_pixel = pixel*(2^bits_to_shift)
disp( dec2bin(shifted_back_pixel))
// Replace old pixel with new
picture(x,y) = shifted_back_pixel
end
end
Of course you can do the above code much faster with one big matrix operation, but it is to show the concept.
Working example
rgb = imread('your_image.png')
gry = rgb2gray(rgb)
gry8bit = im2uint8(gry)
function result = reduce_bits(img, bits)
reduced = img / (2^bits);
result = reduced * (2^bits);
return result;
endfunction
gry2bit = reduce_bits(gry8bit, 6)
imshow(gry2bit)
I'm developing an aplication that loads a dynamic color from a XML file. In some ocasions, I need the aplication to get a similar but darker color from the hexadecimal I have. Each value would go down 33 in hex (51 in decimal). Something like:
0xFFFFFF would become 0xCCCCCC
0x6600CC would become 0x330099
The hex values I have are strings.
I just can't figure out how to solve it in a simple way.
Please, help!
And remember, it's AS2!
You should search for one of the many colour libraries out there. If you want to do it yourself, you need some understanding of bitwise operators. I think reducing the colours by some percent instead of subtracting could give you a nicer result.
var color:int = parseInt(colorString);
// use the shift operator to get individual colour values
var red:int = (color>> 16) & 0xFF;
var green:int = (color>> 8) & 0xFF;
var blue:int = color & 0xFF;
// change colours by subtracting. Todo: make sure colours are between 0 and 255
/*
red -= 0x33;
green -= 0x33;
blue -= 0x33; */
// make colours darker by 10%
red *= 0.9;
green *= 0.9;
blue *= 0.9;
// combine individual colours
color = (red << 16) | (green << 8) | blue;