Converting grayscale image pixels to defined scale - java

I'm looking to use a very crude heightmap I've created in Photoshop to define a tiled isometric grid for me:
Map:
http://i.imgur.com/jKM7AgI.png
I'm aiming to loop through every pixel in the image and convert the colour of that pixel to a scale of my choosing, for example 0-100.
At the moment I'm using the following code:
try
{
final File file = new File("D:\\clouds.png");
final BufferedImage image = ImageIO.read(file);
for (int x = 0; x < image.getWidth(); x++)
{
for (int y = 0; y < image.getHeight(); y++)
{
int clr = image.getRGB(x, y) / 99999;
if (clr <= 0)
clr = -clr;
System.out.println(clr);
}
}
}
catch (IOException ex)
{
// Deal with exception
}
This works to an extent; the black pixel at position 0 is 167 and the white pixel at position 999 is 0. However when I insert certain pixels into the image I get slightly odd results, for example a gray pixel that's very close to white returns over 100 when I would expect it to be in single digits.
Is there an alternate solution I could use that would yield more reliable results?
Many thanks.

Since it's a grayscale map, the RGB parts will all be the same value (with range 0 - 255), so just take one out of the packed integer and find out what percent of 255 it is:
int clr = (int) ((image.getRGB(x, y) & 0xFF) / 255.0 * 100);
System.out.println(clr);

getRGB returns all channels packed into one int so you shouldn't do arithmetic with it. Maybe use the norm of the RGB-vector instead?
for (int x = 0; x < image.getWidth(); ++x) {
for (int y = 0; y < image.getHeight(); ++y) {
final int rgb = image.getRGB(x, y);
final int red = ((rgb & 0xFF0000) >> 16);
final int green = ((rgb & 0x00FF00) >> 8);
final int blue = ((rgb & 0x0000FF) >> 0);
// Norm of RGB vector mapped to the unit interval.
final double intensity =
Math.sqrt(red * red + green * green + blue * blue)
/ Math.sqrt(3 * 255 * 255);
}
}
Note that there is also the java.awt.Color class that can be instantiated with the int returned by getRGB and provides getRed, getGreen and getBlue methods if you don't want to do the bit manipulations yourself.

Related

How to match a webcam captured image with another image in Java Swing?

I am trying to make a hand sign converter in java for my university project . For that i have to match hand sign image and find out the meaning of that particular hand sign .
i have already tired this way to find out the difference percentage between two image .But this way doesn't get me the perfect result .
imgA = ImageIO.read(fileA);
imgB = ImageIO.read(fileB);
}
catch (IOException e)
{
System.out.println(e);
}
int width1 = imgA.getWidth();
int width2 = imgB.getWidth();
int height1 = imgA.getHeight();
int height2 = imgB.getHeight();
if ((width1 != width2) || (height1 != height2))
System.out.println("Error: Images dimensions"+
" mismatch");
else
{
long difference = 0;
for (int y = 0; y < height1; y++)
{
for (int x = 0; x < width1; x++)
{
int rgbA = imgA.getRGB(x, y);
int rgbB = imgB.getRGB(x, y);
int redA = (rgbA >> 16) & 0xff;
int greenA = (rgbA >> 8) & 0xff;
int blueA = (rgbA) & 0xff;
int redB = (rgbB >> 16) & 0xff;
int greenB = (rgbB >> 8) & 0xff;
int blueB = (rgbB) & 0xff;
difference += Math.abs(redA - redB);
difference += Math.abs(greenA - greenB);
difference += Math.abs(blueA - blueB);
}
}
// Total number of red pixels = width * height
// Total number of blue pixels = width * height
// Total number of green pixels = width * height
// So total number of pixels = width * height * 3
double total_pixels = width1 * height1 * 3;
// Normalizing the value of different pixels
// for accuracy(average pixels per color
// component)
double avg_different_pixels = difference /
total_pixels;
// There are 255 values of pixels in total
double percentage = (avg_different_pixels /
255) * 100;
I expect the output to be that much accurate ,it can distinguish different hand sign and find me the correct match
for image manipulation using java you should use javacv which is wrapper over opencv . Though javacv is not an official release from opencv still you can find many useful functionalities in javacv.
The official site for javacv is
http://bytedeco.org/
To get started with javacv you can follow articles from the below site
Basic image manipulation using javacv
Capturing image from webcam using javacv
Hand and finger detection using javacv

Detect & remove a range of colors from Java BufferedImage

I'm building an application that uses OCR to read text from an image (using Tess4J for Google's Tesseract), but I want to ignore the tan-colored text and only read the grey.
In the image below, for instance, I only want to read "Ricki" and ignore "AOA".
http://i.imgur.com/daCuTbB.png
To accomplish this, I figured removing the tan color from the image before performing OCR was my best option.
/* Remove RGB Value for Group Tag */
int width = image.getWidth();
int height = image.getHeight();
int[] pixels = new int[width * height];
image.getRGB(0, 0, width, height, pixels, 0, width);
for (int i = 0; i < pixels.length; i++) {
//If pixel is between dark-tan value and light-tan value
if (pixels[i] > 0xFF57513b && pixels[i] < 0xFF6b6145) {
// Set pixel to black
System.out.println("pixel found");
pixels[i] = 0xFF000000;
}
}
image.setRGB(0, 0, width, height, pixels, 0, width);
But this code removes almost all of the grey text as well. You aren't able to simply compare hex color values for a range of values the way I have. Is there another way to approach detecting a range of colors? Or a better different approach to this problem?
haraldK pointed me in the right direction by mentioning converting RGB. Bit shifting to get individual r, g, and b int values from the hex value allowed me to compare the color within a range and black out a range of colors from the image.
int baser = 108; //base red
int baseg = 96; //base green
int baseb = 68; //base blue
int range = 10; //threshold + and - from base values
/* Set all pixels within +- range of base RGB to black */
for (int i = 0; i < pixels.length; i++) {
int a = (pixels[i]>>24) &0xFF; //alpha
int r = (pixels[i]>>16) &0xFF; //red
int g = (pixels[i]>>8) &0xFF; //green
int b = (pixels[i]>>0) &0xFF; //blue
if ( (r > baser-range && r < baser+range) &&
(g > baseg-range && g < baseg+range) &&
(b > baseb-range && b < baseb+range) ) {
pixels[i] = 0xFF000000; //Set to black
}
}

java.lang.IllegalArgumentException: More than one component per pixel

I'm new to image processing in Java. I'm trying to compare two images with the code below and getting the message following the code. Any help is greatly appreciated. Thanks.
BufferedImage imgOrig = ImageIO.read(new URL(imgOrigUrl));
BufferedImage imgComp = ImageIO.read(new URL(imgCompUrl));
byte[] pixelsOrig = ((DataBufferByte) imgOrig.getRaster().getDataBuffer()).getData();
byte[] pixelsComp = ((DataBufferByte) imgComp.getRaster().getDataBuffer()).getData();
//System.out.println("Number of pixels orig:"+pixelsOrig.length);
//System.out.println("Number of pixels comp:"+pixelsComp.length);
ColorModel cmImgOrig = imgOrig.getColorModel();
ColorModel cmImgComp = imgComp.getColorModel();
int sum1 = 0;
int sum2 = 0;
for(int i:pixelsOrig){
System.out.println(cmImgOrig.getGreen(i)); //ERROR OCCURS HERE
//System.out.println(i);
}
ERROR:
Testcase: testCompareImages(com.myapp.img.compare.service.CompareServiceTest): Caused an ERROR
More than one component per pixel
java.lang.IllegalArgumentException: More than one component per pixel
at java.awt.image.ComponentColorModel.getRGBComponent(ComponentColorModel.java:594)
at java.awt.image.ComponentColorModel.getGreen(ComponentColorModel.java:675)
at com.scottmacri.img.compare.service.CompareService.compareImages(CompareService.java:42)
at com.scottmacri.img.compare.service.CompareServiceTest.testCompareImages(CompareServiceTest.java:45)
Like #Nathan Villaescusa said, the method you are using is expecting a single channel. Do you need the byte array or the color channel? If you only need color components you can do the following:
BufferedImage imgOrig = ImageIO.read(new URL(imgOrigUrl));
BufferedImage imgComp = ImageIO.read(new URL(imgCompUrl));
for (int y = 0; y < imgOrig.getHeight(); y++)
{
for (int x = 0; x < imgOrig.getWidth(); x++)
{
System.out.println(imgOrig.getRGB(x, y) >> 8 & 0xff);
}
}
where the int returned by getRGB(x, y) can be shifted to get the RGB and alpha components like so:
int a = rgb >> 32 & 0xff;
int r = rgb >> 16 & 0xff;
int g = rgb >> 8 & 0xff;
int b = rgb & 0xff;
It looks like that error is being thrown because your ColorSpace has more than 1 component, yet you are only passing in a single value to check.
You want to use the getGreen() method of ColorComponentModel that accepts a Object, not the one that accepts an int. I think the method one that accepts an int is for use with gray scale.
According to this answer, here is how to get pixel data using this method:
Raster r = imgOrig.getData();
SampleModel sm = r.getSampleModel();
int width = sm.getWidth();
int height = sm.getHeight();
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
Object pixel = sm.getPixel(x, u, (int[])null, r.getDataBuffer());
System.out.println(cmImgOrig.getGreen(pixel));
}
}

How to get pixel value of Black and White Image?

I making App in netbeans platform using java Swing and JAI. In this i want to do image processing. I capture .tiff black and white image using X-Ray gun. after that i want to plot histogram of that Black and White image. so, for plot to histogram , first we have to get gray or black and white image pixel value. then we can plot histogram using this pixel value.so, how can i get this pixel value of black and white image?
This should work if you use java.awt.image.BufferedImage.
Since you want to create a histogram, I suppose you will loop through all the pixels. There is the method for returning a single pixel value.
int getRGB(int x, int y)
However, since looping will take place I suppose you'd want to use this one:
int[] getRGB(int startX, int startY, int w, int h, int[] rgbArray, int offset, int scansize)
When you get the array, use:
int alpha = (pixels[i] >> 24) & 0x000000FF;
int red = (pixels[i] >> 16) & 0x000000FF;
int green = (pixels[i] >>8 ) & 0x000000FF;
int blue = pixels[i] & 0x000000FF;
To extract the channel data. Not sure if the variables can be declared as byte (we are using only one byte of the integer in the array, although byte is signed and different arithmetic takes place - two's complement form), but you can declare them as short.
Then preform some maths on these values, for example:
int average = (red + green + blue) / 3;
This will return the average for the pixel, giving you a point you can use in a simple luminosity histogram.
EDIT:
Regarding histogram creation, I have used this class. It takes the image you want the histogram of as an argument to its setImage(BufferedImage image) method. Use updateHistogram() for array populating. The drawing data is in paintComponent(Graphics g). I must admit, it is sloppy, especially when calculating the offsets, but it can be easily simplified.
Here is the whole class:
class HistogramCtrl extends JComponent
{
BufferedImage m_image;
int[] m_histogramArray = new int[256]; //What drives our histogram
int m_maximumPixels;
public HistogramCtrl(){
m_maximumPixels = 0;
for(short i = 0; i<256; i++){
m_histogramArray[i] = 0;
}
}
void setImage(BufferedImage image){
m_image = image;
updateHistogram();
repaint();
}
void updateHistogram(){
if(m_image == null) return;
int[] pixels = m_image.getRGB(0, 0, m_image.getWidth(), m_image.getHeight(), null, 0, m_image.getWidth());
short currentValue = 0;
int red,green,blue;
for(int i = 0; i<pixels.length; i++){
red = (pixels[i] >> 16) & 0x000000FF;
green = (pixels[i] >>8 ) & 0x000000FF;
blue = pixels[i] & 0x000000FF;
currentValue = (short)((red + green + blue) / 3); //Current value gives the average //Disregard the alpha
assert(currentValue >= 0 && currentValue <= 255); //Something is awfully wrong if this goes off...
m_histogramArray[currentValue] += 1; //Increment the specific value of the array
}
m_maximumPixels = 0; //We need to have their number in order to scale the histogram properly
for(int i = 0; i < m_histogramArray.length;i++){ //Loop through the elements
if(m_histogramArray[i] > m_maximumPixels){ //And find the bigges value
m_maximumPixels = m_histogramArray[i];
}
}
}
protected void paintComponent(Graphics g){
assert(m_maximumPixels != 0);
Rectangle rect = g.getClipBounds();
Color oldColor = g.getColor();
g.setColor(new Color(210,210,210));
g.fillRect((int)rect.getX(), (int)rect.getY(), (int)rect.getWidth(), (int)rect.getHeight());
g.setColor(oldColor);
String zero = "0";
String thff = "255";
final short ctrlWidth = (short)rect.getWidth();
final short ctrlHeight = (short)rect.getHeight();
final short activeWidth = 256;
final short activeHeight = 200;
final short widthSpacing = (short)((ctrlWidth - activeWidth)/2);
final short heightSpacing = (short)((ctrlHeight - activeHeight)/2);
Point startingPoint = new Point();
final int substraction = -1;
startingPoint.x = widthSpacing-substraction;
startingPoint.y = heightSpacing+activeHeight-substraction;
g.drawString(zero,widthSpacing-substraction - 2,heightSpacing+activeHeight-substraction + 15);
g.drawString(thff,widthSpacing+activeWidth-substraction-12,heightSpacing+activeHeight-substraction + 15);
g.drawLine(startingPoint.x, startingPoint.y, widthSpacing+activeWidth-substraction, heightSpacing+activeHeight-substraction);
g.drawLine(startingPoint.x,startingPoint.y,startingPoint.x,heightSpacing-substraction);
double factorHeight = (double)activeHeight / m_maximumPixels; //The height divided by the number of pixels is the factor of multiplication for the other dots
Point usingPoint = new Point(startingPoint.x,startingPoint.y);
usingPoint.x+=2; //I want to move this two points in order to be able to draw the pixels with value 0 a bit away from the limit
Point tempPoint = new Point();
for(short i = 0; i<256; i++){
tempPoint.x = usingPoint.x;
tempPoint.y = (int)((heightSpacing+activeHeight-substraction) - (m_histogramArray[i] * factorHeight));
if((i!=0 && (i % 20 == 0)) || i == 255){
oldColor = g.getColor();
g.setColor(oldColor.brighter());
//Draw horizontal ruler sections
tempPoint.x = widthSpacing + i;
tempPoint.y = heightSpacing+activeHeight-substraction+4;
g.drawLine(tempPoint.x,tempPoint.y,widthSpacing + i,heightSpacing+activeHeight-substraction-4);
if(i <= 200){
//Draw vertical ruler sections
tempPoint.x = widthSpacing - substraction - 3;
tempPoint.y = heightSpacing+activeHeight-substraction-i;
g.drawLine(tempPoint.x,tempPoint.y,widthSpacing - substraction + 4, heightSpacing+activeHeight-substraction-i);
}
tempPoint.x = usingPoint.x;
tempPoint.y = usingPoint.y;
g.setColor(oldColor);
}
g.drawLine(usingPoint.x, usingPoint.y, tempPoint.x, tempPoint.y);
usingPoint.x++; //Set this to the next point
}
}
}

Gradient color lookup in Java

I have a list of values from 0-1. I want to convert this list to an image by using a gradient that converts these floating point values to RGB values. Are there any tools in Java that provide you with this functionality?
0 should be mapped 0
1 should be mapped 255
keep in mind that you need 3 of them to make a color
so multiply by 255 the floating number and cast it to int.
Perhaps GradientPaint can do what you want. It's unclear how you want a list of floating point values to be converted into a gradient. Normally a gradient consists of two colors and some mechanism that interpolates between those colors. GradientPaint implements a linear gradient.
Say you have an array made of 64 000 triples corresponding to RGB values, like this:
final Random rand = new Random();
final float[] f = new float[320*200*3];
for (int i = 0; i < f.length; i++) {
f[i] = rand.nextFloat(); // <-- generates a float between [0...1.0[
}
And say you have a BufferedImage that has a size of 320x200 (64 000 pixels) of type INT_ARGB (8 bits per value + 8 bits for the alpha level):
final BufferedImage bi = new BufferedImage( 320, 200, BufferedImage.TYPE_INT_ARGB );
Then you can convert you float array to RGB value and fill the image doing this:
for (int x = 0; x < 320; x++) {
for (int y = 0; y < 200; y++) {
final int r = (int) (f[x+y*200*3] * 255.0);
final int g = (int) (f[x+y*200*3+1] * 255.0);
final int b = (int) (f[x+y*200*3+2] * 255.0);
bi.setRGB( x, y, 0xFF000000 | (r << 16) | (g << 8) | b );
}
}
Note that would you display this image it would appear gray but if you zoom in it you'll see it's actually made of perfectly random colorful pixels. It's just that the random number generator is so good that it all looks gray on screen :)

Categories