Toggle between RGB channels - java

I need to toggle on/off RGB channels of an image, but I am stuck and my code is buggy.
Can you help me figure out how to do this the right way? This is my code:
The function channels is called when 1 of 3 checkboxes has changed its state and provides the arguments which are true == selected
public void channels(boolean red, boolean green, boolean blue) {
if (this.img != null) {// checks if the image is set
char r = 0xFF, g = 0xFF, b = 0xFF;
if (red == false) {
r = 0x00;
}
if (green == false) {
g = 0x00;
}
if (blue == false) {
b = 0x00;
}
BufferedImage tmp = new BufferedImage(
img.getWidth(),
img.getHeight(),
BufferedImage.TYPE_INT_RGB);
for (int i = 0; i < img.getWidth(); i++) {
for (int j = 0; j < img.getHeight(); j++) {
int rgb = img.getRGB(i, j);
int red = (rgb >> 16) & r;
int green = (rgb >> 8) & g;
int blue = (rgb >> 0) & b;
int gbr = (red << 16) | (green << 8) | blue;// EDITED
tmp.setRGB(i, j, gbr);
}
}
img = tmp;
repaint();
} else {
//show error
}
}
Thank you for your help!

How about this optimized version, with a lot less bit shifting?
public void channels(boolean showRed, boolean showGreen, boolean showBlue) {
if (this.origImg!= null) {// checks if the image is set
int channelMask = 0xff << 24 | (showRed ? 0xff : 0) << 16 | (showGreen ? 0xff : 0) << 8 | (showBlue ? 0xff : 0);
BufferedImage tmp = new BufferedImage(origImg.getWidth(), origImg.getHeight(), BufferedImage.TYPE_INT_RGB);
for (int i = 0; i < origImg.getWidth(); i++) {
for (int j = 0; j < origImg.getHeight(); j++) {
int rgb = origImg.getRGB(i, j);
tmp.setRGB(i, j, rgb & channelMask);
}
}
img = tmp;
repaint();
} else {
//show error
}
}
A faster approach yet, would probably be to use a channeled Raster, or at least a Raster configuration that allows band sub-sampling (see Raster.createChild(...) method, especially the last parameter).
LookupOp, as mentioned by #trashgod is also a good idea, and probably faster than the getRGB()/setRGB() approach.

It looks like you're shifting in the bits wrong. Shouldn't it be: int gbr = (red << 16) | (green << 8) | blue;? You basically want to shift back in the same order as how you shifted out to begin with.
Also, once you have cleared the corresponding colour, there's no way for you to get it back. You'll need to store a copy of the original image somewhere. When it's time to turn the channel back on, simply copy the original pixel from the original image back.
Assuming that you have the original image stored somewhere as origImg, I would modify your for loop so that if the channel is toggled on, copy from the original image.
for (int i = 0; i < img.getWidth(); i++) {
for (int j = 0; j < img.getHeight(); j++) {
int rgb = img.getRGB(i, j);
int origRGB = origImg.getRGB(i, j);
int redPixel = red ? (origRGB >> 16) & r : (rgb >> 16) & r;
int greenPixel = green ? (origRGB >> 8) & g : (rgb >> 8) & g;
int bluePixel = blue ? origRGB & b : rgb & b;
int gbr = (redPixel << 16) | (greenPixel << 8) | bluePixel;
tmp.setRGB(i, j, gbr);
}
}

Related

Count red pixel in a given image

I am new to Java and want to count red pixels in a given image. I have below code so far but not sure of what condition to add to check if pixel is red. I have below code so far. Thanks in advance.
public static int countRedPixels(Picture v){
BufferedImage image = (v.getBufferedImage());
int width = image.getWidth();
int height = image.getHeight();
int redCount = 0;
int pixelCount = 0;
for (int x = 0; x < width; x++) {
for (int y = 0; y < height ; y++) {
int rgb = image.getRGB(x, y);
//get rgbs
//int alpha = (rgb >>> 24) & 0xFF;
int red = (rgb >>> 16) & 0xFF;
int green = (rgb >>> 8) & 0xFF;
int blue = (rgb >>> 0) & 0xFF;
if (red == 255 && green == 0 && blue == 0 || image.getRGB(x, y) == 0xFFFF0000) {
redCount++;
}
pixelCount++;
}
}
System.out.println("Red Pixel Count:" + redCount);
System.out.println("Pixel Count:" + pixelCount);
return redCount;
}
Not sure if I'm missing something or you're really not seeing the forest for the trees. Anyway, comment turned answer:
Given that red means (255, 0, 0), you could do:
if (image.getRGB(x, y) == 0xFFFF0000) {
++redCount;
}
Or alternatively, if you don't care about alpha:
if (red == 255 && green == 0 && blue == 0) {
++redCount;
}

Sobel Operator MaskX

Why my image quality after masking x get worse?
public void doMaskX() {
int[][] maskX = { { -1, -2, -1 }, { 0, 0, 0 }, { 1, 2, 1 } };
int rgb, alpha = 0;
int[][] square = new int[3][3];
for (int y = 0; y < width - 3; y++) {
for (int x = 0; x < height - 3; x++) {
int sum = 0;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
rgb = imgx.getRGB(y + i, x + j);
alpha = (rgb >> 24) & 0xff;
int red = (rgb >> 16) & 0xff;
int green = (rgb >> 8) & 0xff;
int blue = rgb & 0xff;
square[i][j] = (red + green + blue)/3;
sum += square[i][j] * maskX[i][j];
}
}
rgb = (alpha << 24) | (sum << 16) | (sum << 8) | sum;
imgx.setRGB(y, x, rgb);
}
}
writeImg();
}
the quality should be better of second image and why is yellow color appears?
It is important to realize that you are computing the intensity of the gradient here and that is what you are displaying. Therefore the intensity (or magnitude) is a positive number. You have to take the absolute value:
sum=Math.abs(sum);
If you take the y derivative also then you can combine:
sum=Math.sqrt(sumx*sumx+sumy*sumy);

Converting 8 bit to 4 bit image

Can anyone see what the issue is when I try to convert my 8 bit image into an 4 bit image?
I am testing using the 8 bit image found here: http://laurashoe.com/2011/08/09/8-versus-16-bit-what-does-it-really-mean/
You can tell how the 4 bit image should look like but mine is almost purely black.
// get color of the image and convert to grayscale
for(int x = 0; x <img.getWidth(); x++) {
for(int y = 0; y < img.getHeight(); y++) {
int rgb = img.getRGB(x, y);
int r = (rgb >> 16) & 0xF;
int g = (rgb >> 8) & 0xF;
int b = (rgb & 0xF);
int grayLevel = (int) (0.299*r+0.587*g+0.114*b);
int gray = (grayLevel << 16) + (grayLevel << 8) + grayLevel;
img.setRGB(x,y,gray);
}
}
You should use 0xFF not 0xF,as 0xF means only last four bits, wchich will tell you almost nothing about the color, since in RGB an color is 8 bit.
try if this work:
// get color of the image and convert to grayscale
for(int x = 0; x <img.getWidth(); x++) {
for(int y = 0; y < img.getHeight(); y++) {
int rgb = img.getRGB(x, y);
int r = (rgb >> 16) & 0xFF;
int g = (rgb >> 8) & 0xFF;
int b = (rgb & 0xFF);
int grayLevel = (int) (0.299*r+0.587*g+0.114*b);
int gray = (grayLevel << 16) + (grayLevel << 8) + grayLevel;
img.setRGB(x,y,gray);
}
}
Since the code has been edited out from the question, here it is with the confirmed solution from the comments:
// get color of the image and convert to grayscale
for(int x = 0; x <img.getWidth(); x++) {
for(int y = 0; y < img.getHeight(); y++) {
int rgb = img.getRGB(x, y);
// get the upper 4 bits from each color component
int r = (rgb >> 20) & 0xF;
int g = (rgb >> 12) & 0xF;
int b = (rgb >> 4) & 0xF;
int grayLevel = (int) (0.299*r+0.587*g+0.114*b);
// use grayLevel value as the upper 4 bits of each color component of the new color
int gray = (grayLevel << 20) + (grayLevel << 12) + (grayLevel << 4);
img.setRGB(x,y,gray);
}
}
Note that the resulting image only looks like 4-bit grayscale, but still uses int as the RGB value.
8 bit image values are in range [0, 255] because pow(2, 8) = 256
To get 4 bit image values which will be in range [0, 15] as pow(2, 4) = 16,
we need to divide each pixel value by 16 -> range [0, 255] / 16 = range [0, 15].
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread("crowd.jpeg")
#Convert the image to grayscale
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
plt.imshow(gray_img, cmap='gray')
Grayscale image
bit_4 = np.divide(gray_img, 16).astype('uint8')
plt.imshow(bit_4, cmap='gray')
Bit4 image

Image to byte[] to Image

I'm trying to do some image processing using with Java.
As a start, before doing any filters or anything, I'm doing a convert process on my image to a byte array, then convert it back to an image and save it to see how that goes.
I'm not getting the output image as the input one, there is some lost information/data, which causing the output to look different in colors.
Please tell me what is the problem; what I am missing.
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Ola {
BufferedImage img = null;
public void loadImage() {
try {
img = ImageIO.read(new File("/home/a/Pictures/Tux-vegeta.png"));
} catch (IOException e) {
System.out.println("image(s) could not load correctly, try changing the path");
}
}
public byte[] convertToArray() {
int w = img.getWidth();
int h = img.getHeight();
int bands = img.getSampleModel().getNumBands();
System.out.print(bands);
if (bands != 4) {
System.out.println("The image does not have 4 color bands");
}
byte bytes[] = new byte[4 * w * h];
int index = 0;
for(int y = 0; y < h; y++) {
for(int x = 0; x < w; x++) {
int pixel = img.getRGB(x, y);
int alpha = (pixel >> 24) & 0xFF;
int red = (pixel >> 16) & 0xFF;
int green = (pixel >> 8) & 0xFF;
int blue = pixel & 0xFF;
bytes[index++] = (byte) alpha;
bytes[index++] = (byte) red;
bytes[index++] = (byte) green;
bytes[index++] = (byte) blue;
}
}
return bytes;
}
public void convertToImage(byte[] bytes) {
try {
int w = 300;
int h = 300;
int index = 0;
BufferedImage resultPNG = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j ++) {
int pixel = (bytes[index] << 24) | (bytes[index + 1] << 16) | (bytes[index + 2] << 8) | (bytes[index + 3]);
resultPNG.setRGB(j, i, pixel);
index += 4;
}
}
File outputImage = new File("/home/a![enter image description here][1]/Pictures/test.png");
ImageIO.write(resultPNG, "png", outputImage);
} catch (IOException e) {
System.out.println("image write error");
}
}
public static void main(String[] args) {
Ola ola = new Ola();
ola.loadImage();
ola.convertToImage(ola.convertToArray());
}
}
what you are missing is turning your signed byte back to unsigned:
change your line
int pixel = (bytes[index] << 24) | (bytes[index + 1] << 16) | (bytes[index + 2] << 8) | (bytes[index + 3]);
to the following:
int pixel = ((bytes[index] & 0xFF) << 24) | ((bytes[index + 1] & 0xFF) << 16) | ((bytes[index + 2] & 0xFF) << 8) | (bytes[index + 3] & 0xFF);
Since you are wanting the alpha channel your destination should be using TYPE_INT_ARGB instead of TYPE_INT_RGB, using RGB will cause the buffered image to ignore the alpha byte.
Since PNGs do not load into the TYPE_INT_ARGB color model you can use a graphics object to draw the loaded bufferedimage into a bufferedimage object created with TYPE_INT_ARGB.
public void loadImage() {
try {
BufferedImage tempimg = ImageIO.read(new File("/home/a/Pictures/Tux-vegeta.png"));
img = new BufferedImage(300, 300, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
g2.drawImage(tempimg,null,0,0);
} catch (IOException e) {
System.out.println("image(s) could not load correctly, try changing the path");
}
}

Java BufferedImage Not Registering Transparent Pixels?

I have used the method ImageIO.read(File file); to read a PNG image file. However, when I use the getRGB(int x, int y) method on it to extract the alpha it always returns 255 whether the pixel is transparent or not. How do I remedy this inconvenience?
When converting packed int colors to Color objects, you need to tell it if it should calculate the alpha value or not.
new Color(image.getRGB(x, y), true).getAlpha();
See Color(int, boolean) for more details
Just wanted to point out that using the method getRGB(x,y) is extremely inefficient. If you want to get the pixels of an image you could extract the colours from each individual pixel and then store the pixel in an int array. Credit also to mota for explaining why this is inefficient see his post . Example below:
/**===============================================================================================
* Method that extracts pixel data from an image
* #return a 2d array representing the pixels of the image
=================================================================================================*/
public static int[][] getImageData(BufferedImage img) {
int height = img.getHeight();
int width = img.getWidth();
final byte[] imgPixels = ((DataBufferByte) img.getRaster().getDataBuffer()).getData();
final boolean is_Alpha_Present = img.getAlphaRaster() != null;
int[][] imgArr = new int[height][width];
if (is_Alpha_Present) {
final int pixelLength = 4; //number of bytes used to represent a pixel if alpha value present
for (int pixel = 0, row = 0, col = 0; pixel < imgPixels.length; pixel = pixel + pixelLength) {
int argb = 0;
argb += (((int) imgPixels[pixel] & 0xff) << 24); //getting the alpha for the pixel
argb += ((int) imgPixels[pixel + 1] & 0xff); //getting the blue colour
argb += (((int) imgPixels[pixel + 2] & 0xff) << 8); //getting the green colour
argb += (((int) imgPixels[pixel + 3] & 0xff) << 16); //getting the red colour
imgArr[row][col] = argb;
col++;
if (col == width) {
col = 0;
row++;
}
}
}
else {
final int pixelLength = 3;
for (int pixel = 0, row = 0, col = 0; pixel < imgPixels.length; pixel = pixel + pixelLength) {
int argb = 0;
argb += Integer.MIN_VALUE;
argb += ((int) imgPixels[pixel] & 0xff); //getting the blue colour
argb += (((int) imgPixels[pixel+1] & 0xff) << 8); //getting the green colour
argb += (((int) imgPixels[pixel+2] & 0xff) << 16); //getting the red colour
imgArr[row][col] = argb;
col++;
if (col == width) {
col = 0;
row++;
}
}
}
return imgArr;
}

Categories

Resources