Can't use fisheye lens effect on my image in Java - java

I want to use fisheye lens algorithm in Java, but I can't implement a main method.
At the bottom of this site, I found java code, that implements fisheye algorithm, but there wasn't any main() method. I've tried to implement a main() method by my own, but so far I just can display image, but I can't use the barrel() method on that image which should make fisheye effect on my image.
Could you please correct my main method, or implement a new one, that loads some image(bufferedImage) and then use barrel() method on that image?
My code so far is:
import java.awt.FlowLayout;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class DisplayImage {
float xscale;
float yscale;
float xshift;
float yshift;
int [] s;
public BufferedImage barrel (BufferedImage input, float k){
float centerX=input.getWidth()/2; //center of distortion
float centerY=input.getHeight()/2;
int width = input.getWidth(); //image bounds
int height = input.getHeight();
BufferedImage dst = new BufferedImage(width, height,BufferedImage.TYPE_INT_ARGB); //output pic
xshift = calc_shift(0,centerX-1,centerX,k);
float newcenterX = width-centerX;
float xshift_2 = calc_shift(0,newcenterX-1,newcenterX,k);
yshift = calc_shift(0,centerY-1,centerY,k);
float newcenterY = height-centerY;
float yshift_2 = calc_shift(0,newcenterY-1,newcenterY,k);
xscale = (width-xshift-xshift_2)/width;
yscale = (height-yshift-yshift_2)/height;
for(int j=0;j<dst.getHeight();j++){
for(int i=0;i<dst.getWidth();i++){
float x = getRadialX((float)i,(float)j,centerX,centerY,k);
float y = getRadialY((float)i,(float)j,centerX,centerY,k);
sampleImage(input,x,y);
int color = ((s[1]&0x0ff)<<16)|((s[2]&0x0ff)<<8)|(s[3]&0x0ff);
// System.out.print(i+" "+j+" \\");
dst.setRGB(i, j, color);
}
}
return dst;
}
void sampleImage(BufferedImage arr, float idx0, float idx1)
{
s = new int [4];
if(idx0<0 || idx1<0 || idx0>(arr.getHeight()-1) || idx1>(arr.getWidth()-1)){
s[0]=0;
s[1]=0;
s[2]=0;
s[3]=0;
return;
}
float idx0_fl=(float) Math.floor(idx0);
float idx0_cl=(float) Math.ceil(idx0);
float idx1_fl=(float) Math.floor(idx1);
float idx1_cl=(float) Math.ceil(idx1);
int [] s1 = getARGB(arr,(int)idx0_fl,(int)idx1_fl);
int [] s2 = getARGB(arr,(int)idx0_fl,(int)idx1_cl);
int [] s3 = getARGB(arr,(int)idx0_cl,(int)idx1_cl);
int [] s4 = getARGB(arr,(int)idx0_cl,(int)idx1_fl);
float x = idx0 - idx0_fl;
float y = idx1 - idx1_fl;
s[0]= (int) (s1[0]*(1-x)*(1-y) + s2[0]*(1-x)*y + s3[0]*x*y + s4[0]*x*(1-y));
s[1]= (int) (s1[1]*(1-x)*(1-y) + s2[1]*(1-x)*y + s3[1]*x*y + s4[1]*x*(1-y));
s[2]= (int) (s1[2]*(1-x)*(1-y) + s2[2]*(1-x)*y + s3[2]*x*y + s4[2]*x*(1-y));
s[3]= (int) (s1[3]*(1-x)*(1-y) + s2[3]*(1-x)*y + s3[3]*x*y + s4[3]*x*(1-y));
}
int [] getARGB(BufferedImage buf,int x, int y){
int rgb = buf.getRGB(x, y); // Returns by default ARGB.
int [] scalar = new int[4];
scalar[0] = (rgb >>> 24) & 0xFF;
scalar[1] = (rgb >>> 16) & 0xFF;
scalar[2] = (rgb >>> 8) & 0xFF;
scalar[3] = (rgb >>> 0) & 0xFF;
return scalar;
}
float getRadialX(float x,float y,float cx,float cy,float k){
x = (x*xscale+xshift);
y = (y*yscale+yshift);
float res = x+((x-cx)*k*((x-cx)*(x-cx)+(y-cy)*(y-cy)));
return res;
}
float getRadialY(float x,float y,float cx,float cy,float k){
x = (x*xscale+xshift);
y = (y*yscale+yshift);
float res = y+((y-cy)*k*((x-cx)*(x-cx)+(y-cy)*(y-cy)));
return res;
}
float thresh = 1;
float calc_shift(float x1,float x2,float cx,float k){
float x3 = (float)(x1+(x2-x1)*0.5);
float res1 = x1+((x1-cx)*k*((x1-cx)*(x1-cx)));
float res3 = x3+((x3-cx)*k*((x3-cx)*(x3-cx)));
if(res1>-thresh && res1 < thresh)
return x1;
if(res3<0){
return calc_shift(x3,x2,cx,k);
}
else{
return calc_shift(x1,x3,cx,k);
}
}
public static void main(String avg[]) throws IOException
{
BufferedImage img=ImageIO.read(new File("image.jpg"));
ImageIcon icon=new ImageIcon(img);
JFrame frame=new JFrame();
frame.setLayout(new FlowLayout());
frame.setSize(625,648);
JLabel lbl=new JLabel();
lbl.setIcon(icon);
frame.add(lbl);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Code is working, but it only display image. I want to use barrel() method on my image, which will do the fisheye effect. Because I am newbie to java, I can't do that, please help.

Refer to this site:
http://popscan.blogspot.in/2012/04/fisheye-lens-equation-simple-fisheye.html
It contains the concept as well as working source at the end of the article.

make your function static
public static BufferedImage barrel (BufferedImage input, float k)
and change
public static void main(String avg[]) throws IOException
{
BufferedImage img=ImageIO.read(new File("image.jpg"));
//now pass this image to your barrel method and return in new image
//note that, method can be called now without instatntiating any object, as it is static now
BufferImage barrelImage = barrel(img,2.0);
ImageIcon icon=new ImageIcon(barrelImage);
...
...
}

So I finally implemented desired fisheye! Just because of this and this site. I am giving here really messy but working code for anyone with similar problem:
package fisheye;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class DitherMain {
static String imageString = "image.bmp";
BufferedImage startImage, endImage;
int[] startPixels, endPixels, imR, imG, imB;
int width, height;
public static void main(String[] args){
new DitherMain(loadImage(imageString));
}
//this object transforms the old image and writes the new image
DitherMain(BufferedImage img){
//filing the image into startpixels
startImage = img;
width = img.getWidth();
height = img.getHeight();
startPixels = new int[width*height];
img.getRGB(0, 0, width, height, startPixels, 0, width);
endPixels = fisheye(startPixels, width, height);
transformPixels();
WritableRaster wRaster = endImage.getData().createCompatibleWritableRaster();
wRaster.setSamples(0, 0, width, height, 0, imR);
wRaster.setSamples(0, 0, width, height, 1, imG);
wRaster.setSamples(0, 0, width, height, 2, imB);
endImage.setData(wRaster);
System.out.println(endImage);
//writing the file for endImage into the harddrive
writeFile();
}
void transformPixels(){
//endPixels = startPixels;
endImage = startImage;
imR = new int[endPixels.length];
imG = new int[endPixels.length];
imB = new int[endPixels.length];
for(int i = 0; i < endPixels.length; i++){
imR[i] = (endPixels[i] >> 16) & 0x000000FF;
imG[i] = (endPixels[i] >> 8) & 0x000000FF;
imB[i] = endPixels[i] & 0x000000FF;
}
}
void writeFile(){
try {
ImageIO.write(endImage,"BMP",new File("RESULT.bmp"));
} catch (IOException e) {
e.printStackTrace();
}
}
//this method just loads a specific buffered image
public static BufferedImage loadImage(String fileName){
BufferedImage img;
try{
img=ImageIO.read(new File("image.bmp"));
//img = ImageIO.read(DitherMain.class.getResource(fileName));
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
return img;
}
public static int[] fisheye(int[] srcpixels, double w, double h) {
/*
* Fish eye effect
* tejopa, 2012-04-29
* http://popscan.blogspot.com
* http://www.eemeli.de
*/
// create the result data
int[] dstpixels = new int[(int)(w*h)];
// for each row
for (int y=0;y<h;y++) {
// normalize y coordinate to -1 ... 1
double ny = ((2*y)/h)-1;
// pre calculate ny*ny
double ny2 = ny*ny;
// for each column
for (int x=0;x<w;x++) {
// normalize x coordinate to -1 ... 1
double nx = ((2*x)/w)-1;
// pre calculate nx*nx
double nx2 = nx*nx;
// calculate distance from center (0,0)
// this will include circle or ellipse shape portion
// of the image, depending on image dimensions
// you can experiment with images with different dimensions
double r = Math.sqrt(nx2+ny2);
// discard pixels outside from circle!
if (0.0<=r&&r<=1.0) {
double nr = Math.sqrt(1.0-r*r);
// new distance is between 0 ... 1
nr = (r + (1.0-nr)) / 2.0;
// discard radius greater than 1.0
if (nr<=1.0) {
// calculate the angle for polar coordinates
double theta = Math.atan2(ny,nx);
// calculate new x position with new distance in same angle
double nxn = nr*Math.cos(theta);
// calculate new y position with new distance in same angle
double nyn = nr*Math.sin(theta);
// map from -1 ... 1 to image coordinates
int x2 = (int)(((nxn+1)*w)/2.0);
// map from -1 ... 1 to image coordinates
int y2 = (int)(((nyn+1)*h)/2.0);
// find (x2,y2) position from source pixels
int srcpos = (int)(y2*w+x2);
// make sure that position stays within arrays
if (srcpos>=0 & srcpos < w*h) {
// get new pixel (x2,y2) and put it to target array at (x,y)
dstpixels[(int)(y*w+x)] = srcpixels[srcpos];
}
}
}
}
}
//return result pixels
return dstpixels;
}
}

Related

Rotate an image by 90 180 and 270 degrees when width and height can be any size

I am having trouble writing a function that takes a BufferedImage and a Cardinal Direction and rotates the image accordingly. I have looked on many threads on stack and tried implementing myself while going over the docs for some time now and the best I'm getting is that the image seems to be rotating, however the last pixel is correct and the rest are set white or transparent not sure.
Here is where I have got so far:
private BufferedImage rotateImg(BufferedImage image, String direction){
int width = image.getWidth();
int height = image.getHeight();
BufferedImage rotated = null;
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
switch(direction){
case "SOUTH":
rotated = new BufferedImage(width, height, image.getType());
rotated.setRGB((width - 1) - x, (height - 1) - y, image.getRGB(x,y));
break;
case "WEST":
//ROTATE LEFT
rotated = new BufferedImage(height, width, image.getType());
rotated.setRGB(y, (width - 1) - x, image.getRGB(x,y));
break;
case "EAST":
//ROTATE RIGHT
rotated = new BufferedImage(height, width, image.getType());
rotated.setRGB((height - 1) - y, x, image.getRGB(x,y));
break;
default:
return image;
}
}
}
return rotated;
}
Below there are four images but as they are so small its really hard to see them. A bit of browser zoom will show them.
When you get close the cyan pixel is staying where it should for the rotation. Its just im loosing the rest of the image.
I don't know if there's a fixed requirement to rotate this image by individual pixels or not, but I'm far to simple minded to even be bothered trying.
Instead, I'd (personally) drop straight into the Graphics API itself, for example...
public static BufferedImage rotateBy(BufferedImage source, double degrees) {
// The size of the original image
int w = source.getWidth();
int h = source.getHeight();
// The angel of the rotation in radians
double rads = Math.toRadians(degrees);
// Some nice math which demonstrates I have no idea what I'm talking about
// Okay, this calculates the amount of space the image will need in
// order not be clipped when it's rotated
double sin = Math.abs(Math.sin(rads));
double cos = Math.abs(Math.cos(rads));
int newWidth = (int) Math.floor(w * cos + h * sin);
int newHeight = (int) Math.floor(h * cos + w * sin);
// A new image, into which the original can be painted
BufferedImage rotated = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = rotated.createGraphics();
// The transformation which will be used to actually rotate the image
// The translation, actually makes sure that the image is positioned onto
// the viewable area of the image
AffineTransform at = new AffineTransform();
at.translate((newWidth - w) / 2, (newHeight - h) / 2);
// And we rotate about the center of the image...
int x = w / 2;
int y = h / 2;
at.rotate(rads, x, y);
g2d.setTransform(at);
// And we paint the original image onto the new image
g2d.drawImage(source, 0, 0, null);
g2d.dispose();
return rotated;
}
This method will create a new image large enough to fit the rotated version of the source image.
You could then drop it into a helper class, add some helper methods and have a basic worker (and re-usable) solution, for example...
public class ImageUtilities {
public enum Direction {
NORTH, SOUTH, EAST, WEST
}
public static BufferedImage rotateBy(BufferedImage source, Direction direction) {
switch (direction) {
case NORTH:
return source;
case SOUTH:
return rotateBy(source, 180);
case EAST:
return rotateBy(source, 90);
case WEST:
return rotateBy(source, -90);
}
return null;
}
public static BufferedImage rotateBy(BufferedImage source, double degrees) {
// The size of the original image
int w = source.getWidth();
int h = source.getHeight();
// The angel of the rotation in radians
double rads = Math.toRadians(degrees);
// Some nice math which demonstrates I have no idea what I'm talking about
// Okay, this calculates the amount of space the image will need in
// order not be clipped when it's rotated
double sin = Math.abs(Math.sin(rads));
double cos = Math.abs(Math.cos(rads));
int newWidth = (int) Math.floor(w * cos + h * sin);
int newHeight = (int) Math.floor(h * cos + w * sin);
// A new image, into which the original can be painted
BufferedImage rotated = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = rotated.createGraphics();
// The transformation which will be used to actually rotate the image
// The translation, actually makes sure that the image is positioned onto
// the viewable area of the image
AffineTransform at = new AffineTransform();
at.translate((newWidth - w) / 2, (newHeight - h) / 2);
// And we rotate about the center of the image...
int x = w / 2;
int y = h / 2;
at.rotate(rads, x, y);
g2d.setTransform(at);
// And we paint the original image onto the new image
g2d.drawImage(source, 0, 0, null);
g2d.dispose();
return rotated;
}
}
(although I might use RIGHT, LEFT, UPSIDE or something, but that's me :P)
Runnable example...
import java.awt.EventQueue;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
public class TestPane extends JPanel {
private BufferedImage masterImage;
private BufferedImage northImage;
private BufferedImage southImage;
private BufferedImage eastImage;
private BufferedImage westImage;
public TestPane() throws IOException {
masterImage = ImageIO.read(new File("/absolute/path/to/your/image.png"));
northImage = ImageUtilities.rotateBy(masterImage, ImageUtilities.Direction.NORTH);
southImage = ImageUtilities.rotateBy(masterImage, ImageUtilities.Direction.SOUTH);
eastImage = ImageUtilities.rotateBy(masterImage, ImageUtilities.Direction.EAST);
westImage = ImageUtilities.rotateBy(masterImage, ImageUtilities.Direction.WEST);
setLayout(new GridLayout(3, 3));
add(new JLabel(""));
add(new JLabel(new ImageIcon(northImage)));
add(new JLabel(""));
add(new JLabel(new ImageIcon(westImage)));
add(new JLabel(new ImageIcon(masterImage)));
add(new JLabel(new ImageIcon(eastImage)));
add(new JLabel(""));
add(new JLabel(new ImageIcon(southImage)));
add(new JLabel(""));
}
}
public class ImageUtilities {
public enum Direction {
NORTH, SOUTH, EAST, WEST
}
public static BufferedImage rotateBy(BufferedImage source, Direction direction) {
switch (direction) {
case NORTH:
return source;
case SOUTH:
return rotateBy(source, 180);
case EAST:
return rotateBy(source, 90);
case WEST:
return rotateBy(source, -90);
}
return null;
}
public static BufferedImage rotateBy(BufferedImage source, double degrees) {
// The size of the original image
int w = source.getWidth();
int h = source.getHeight();
// The angel of the rotation in radians
double rads = Math.toRadians(degrees);
// Some nice math which demonstrates I have no idea what I'm talking about
// Okay, this calculates the amount of space the image will need in
// order not be clipped when it's rotated
double sin = Math.abs(Math.sin(rads));
double cos = Math.abs(Math.cos(rads));
int newWidth = (int) Math.floor(w * cos + h * sin);
int newHeight = (int) Math.floor(h * cos + w * sin);
// A new image, into which the original can be painted
BufferedImage rotated = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = rotated.createGraphics();
// The transformation which will be used to actually rotate the image
// The translation, actually makes sure that the image is positioned onto
// the viewable area of the image
AffineTransform at = new AffineTransform();
at.translate((newWidth - w) / 2, (newHeight - h) / 2);
// And we rotate about the center of the image...
int x = w / 2;
int y = h / 2;
at.rotate(rads, x, y);
g2d.setTransform(at);
// And we paint the original image onto the new image
g2d.drawImage(source, 0, 0, null);
g2d.dispose();
return rotated;
}
}
}
But the image is rotating in the wrong direction!
Okay, so change the angle of rotation to meet your needs!
As commented, the actual code is creating a new image for each pixel, that is, inside the inner loop. Only the image created in the last iteration is returned, containing just the last pixel.
The following code creates one single image - I tried to maintain the original code as much as possible:
private static BufferedImage rotateImg(BufferedImage image, String direction){
int width = image.getWidth();
int height = image.getHeight();
BufferedImage rotated = null;
switch(direction){
case "SOUTH":
rotated = new BufferedImage(width, height, image.getType());
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
rotated.setRGB((width - 1) - x, (height - 1) - y, image.getRGB(x,y));
}
}
break;
case "WEST":
//ROTATE LEFT
rotated = new BufferedImage(height, width, image.getType());
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
rotated.setRGB(y, (width - 1) - x, image.getRGB(x,y));
}
}
break;
case "EAST":
//ROTATE RIGHT
rotated = new BufferedImage(height, width, image.getType());
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
rotated.setRGB((height - 1) - y, x, image.getRGB(x,y));
}
}
break;
default:
return image;
}
return rotated;
}
To avoid having the loop code repeated (easier to maintain) we can use two functions - calX and calcY:
private static BufferedImage rotateImg(BufferedImage image, String direction){
int width = image.getWidth();
int height = image.getHeight();
BufferedImage rotated = null;
IntBinaryOperator calcX;
IntBinaryOperator calcY;
switch(direction){
case "SOUTH":
rotated = new BufferedImage(width, height, image.getType());
calcX = (x, y) -> (width - 1) - x;
calcY = (x, y) -> (height - 1) - y;
break;
case "WEST":
//ROTATE LEFT
rotated = new BufferedImage(height, width, image.getType());
calcX = (x, y) -> y;
calcY = (x, y) -> (width - 1) - x;
break;
case "EAST":
//ROTATE RIGHT
rotated = new BufferedImage(height, width, image.getType());
calcX = (x, y) -> (height - 1) - y;
calcY = (x, y) -> x;
break;
default:
return image;
}
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
rotated.setRGB(calcX.applyAsInt(x, y), calcY.applyAsInt(x, y), image.getRGB(x,y));
}
}
return rotated;
}

Want to reduce bit size for RGB levels of an image

I want to reduce the image color quantization from 16 to 8 bit. This is my code so far. It only makes the image transparent. From what I've learnt, I'm supposed to take each individual pixel and divide by factor of bit size reduction. What am I doing wrong here?
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import java.util.Scanner;
public class ConvertImage{
public static void main(String args[])throws IOException{
BufferedImage image = null;
File f = null;
try {
f = new File("lennapng.png");
image = ImageIO.read(f);
}catch(IOException e){
System.out.println(e);
}
//get width and height
int width = image.getWidth();
int height = image.getHeight();
width = image.getWidth();
height = image.getHeight();
for(int y = 0; y < height; y++) {
for(int x = 0; x <height; x++) {
int p = image.getRGB(x, y);
// System.out.println("rgb "+ rgb);
int a = (p>>24) & 0xff;
int r = (p>>16) & 0xff;
int g = (p>>8) & 0xff;
int b = p&0xff;
r= r*16/256;
g= g*16/256;
b = b*16/256;
//set new RGB
p = (a<<12) | (r<<8) | (g<<4) | b;
image.setRGB(x, y, p);
}
}
try{
f = new File("output.png");
ImageIO.write(image, "png", f);
}catch(IOException e){
System.out.println(e);
}
}
}

Java OpenCV Layer small image onto larger image with transparency

I am trying to write a function that overlays an image at a rectangle with transparency over top of another image, However it doesn't layer the images it just erases the section that I overlay and the transparency cuts through the entire image. Here is my code.
public static void overlayImage(String imagePath, String overlayPath, int x, int y, int width, int height) {
Mat overlay = Imgcodecs.imread(overlayPath, Imgcodecs.IMREAD_UNCHANGED);
Mat image = Imgcodecs.imread(imagePath, Imgcodecs.IMREAD_UNCHANGED);
Rectangle rect = new Rectangle(x, y, width, height);
Imgproc.resize(overlay, overlay, rect.size());
Mat submat = image.submat(new Rect(rect.x, rect.y, overlay.cols(), overlay.rows()));
overlay.copyTo(submat);
Imgcodecs.imwrite(imagePath, image);
}
EDIT: Here are some example pictures:
Before:
After:
Found this function that does exactly what I needed.
public static void overlayImage(Mat background,Mat foreground,Mat output, Point location){
background.copyTo(output);
for(int y = (int) Math.max(location.y , 0); y < background.rows(); ++y){
int fY = (int) (y - location.y);
if(fY >= foreground.rows())
break;
for(int x = (int) Math.max(location.x, 0); x < background.cols(); ++x){
int fX = (int) (x - location.x);
if(fX >= foreground.cols()){
break;
}
double opacity;
double[] finalPixelValue = new double[4];
opacity = foreground.get(fY , fX)[3];
finalPixelValue[0] = background.get(y, x)[0];
finalPixelValue[1] = background.get(y, x)[1];
finalPixelValue[2] = background.get(y, x)[2];
finalPixelValue[3] = background.get(y, x)[3];
for(int c = 0; c < output.channels(); ++c){
if(opacity > 0){
double foregroundPx = foreground.get(fY, fX)[c];
double backgroundPx = background.get(y, x)[c];
float fOpacity = (float) (opacity / 255);
finalPixelValue[c] = ((backgroundPx * ( 1.0 - fOpacity)) + (foregroundPx * fOpacity));
if(c==3){
finalPixelValue[c] = foreground.get(fY,fX)[3];
}
}
}
output.put(y, x,finalPixelValue);
}
}
}

How to extract Y, Cb and Cr color components?

I need to decompose a given colored picture in three separate pictures, so that each color component (Y, Cb, Cr) is stored in one picture like here.
Maybe has an idea how I could get these three pictures with
separately Y, Cb or Cr color components? With following peace of code I can just read out the file and convert the color model from RGB to YCbCr.
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class SpaceConverter {
static int [] colorComponentsYCbCr = new int[3];
static int [] colorComponentsRGB = new int[3];
public static void getRGBComponents (int color)
{
colorComponentsRGB [0] = (color & 0xff);
colorComponentsRGB [1] = (color & 0x00ff) >> 8;
colorComponentsRGB [2] = (color & 0x0000ff) >> 16;
}
public static void convertYCbCr2RGB(int [] componentsYCbCrToConvert)
{
int Y = componentsYCbCrToConvert [0];
int Cb = componentsYCbCrToConvert [1];
int Cr = componentsYCbCrToConvert [2];
colorComponentsRGB = new int [3];
colorComponentsRGB [0] = (int) (Y + 1.402 * (Cr - 128));
colorComponentsRGB [1] = (int) (Y - 0.34414 * (Cb - 128) - 0.71414 * (Cr - 128));
colorComponentsRGB [2] = (int) (Y + 1.772 * (Cb - 128));
}
public static void convertRGB2YCbCr(int [] componentsRGB)
{
int blue = componentsRGB [0];
int green = componentsRGB [1];
int red = componentsRGB [2];
colorComponentsYCbCr [0] = (int) (0.299 * red + 0.587 * green + 0.114 * blue);
colorComponentsYCbCr [1] = (int) (128-0.169 * red-0.331 * green + 0.500 * blue);
colorComponentsYCbCr [2] = (int) (128+0.500 * red - 0.419 * green - 0.081 * blue);
}
public static void getColoredCrPicture(BufferedImage image)
{
File f = null;
// get width and height
int width = image.getWidth();
int height = image.getHeight();
for (int y = 0; y<height; y++)
{
for (int x = 0; x<width; x++)
{
int color = image.getRGB(x, y);
getRGBComponents(color);
convertRGB2YCbCr(colorComponentsRGB);
int Y = colorComponentsYCbCr[0];
int Cb = colorComponentsYCbCr[1];
int Cr = colorComponentsYCbCr[2];
Y = 0;
Cb = 0;
int p = (Y << 24) | (Cb << 16) | (Cr<<8);
image.setRGB(x, y, p);
}
}
try
{
f = new File("/Users/MAC/Documents/workspace/ColorConverter/src/outputX.jpg");
ImageIO.write(image, "jpg", f);
}
catch(IOException e)
{
System.out.println(e);
}
}
public static void getColoredCbPicture(BufferedImage image)
{
File f = null;
// get width and height
int width = image.getWidth();
int height = image.getHeight();
for (int y = 0; y<height; y++)
{
for (int x = 0; x<width; x++)
{
int color = image.getRGB(x, y);
getRGBComponents(color);
convertRGB2YCbCr(colorComponentsRGB);
int Y = colorComponentsYCbCr[0];
int Cb = colorComponentsYCbCr[1];
int Cr = colorComponentsYCbCr[2];
Y = 0;
Cr = 0;
int p = (Y << 24) | (Cb<< 16) | (Cr <<8);
image.setRGB(x, y, p);
}
}
try
{
f = new File("/Users/MAC/Documents/workspace/ColorConverter/src/outputCb.jpg");
ImageIO.write(image, "jpg", f);
System.out.println("WRITE Status: OK");
}
catch(IOException e)
{
System.out.println(e);
}
}
public static BufferedImage loadPicture()
{
File f = null;
BufferedImage img = null;
// read Image
try
{
f = new File("/Users/MAC/Documents/workspace/ColorConverter/src/VILLA.JPG");
img = ImageIO.read(f);
System.out.println("READ Status: OK");
getColoredCbPicture(img);
}
catch(IOException e)
{
System.out.println(e);
}
return img;
}
public static void main(String[] args)
{
BufferedImage image = null;
loadPicture();
getColoredCbPicture(image);
}
}
It sounds like what you are looking to do is take an RGB image, convert it to YCbCr and display each of the three channels in YCbCr as a separate RGB image.
You already have code that converts from RGB to YCbCr . You will also need code that will do the reverse conversion so you can go from YCbCr to RGB.
You will want to use this same logic, but actually create three Y'CrCb images: (Y, 0, 0), (0, Cb, 0) and (0, 0, Cr). Then convert each of these three images to RGB. These three images will be an RGB representation of each of the three YCbCr channels.

How to clear pixel of BufferedImage in java?

In java, I read an image and then go through the pixels and if its color distance is < 30, then I want to clear the image by changing its alpha to 0. This is my code:
But this is not working. It is having no effect...
Does anyone see the problem?
Thanks
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import javax.imageio.ImageIO;
public class Recognize {
public static void main(String args[]) throws IOException {
Path path = Paths.get("images/fish.png");
File file = path.toFile();
if (file.exists()) {
InputStream stream = Files.newInputStream(path);
BufferedImage bufferedImage = ImageIO.read(stream);
int width = bufferedImage.getWidth();
int height = bufferedImage.getHeight();
if (width > 0 && height > 0) {
int TLpixel = bufferedImage.getRGB(0, 0);
Color TLcolor = new Color(TLpixel);
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
int pixel = bufferedImage.getRGB(i, j);
Color color = new Color(pixel);
double distance = ColourDistance(TLcolor, color);
//System.out.println(distance);
if (distance < 30) {
int mc = (0 << 24) | 0x00ffffff;
int newcolor = pixel & mc;
bufferedImage.setRGB(i, j, newcolor);
}
}
}
File outputfile = new File("images/fish_new.png");
ImageIO.write(bufferedImage, "png", outputfile);
}
}
}
public static int[] printPixelARGB(int pixel) {
int alpha = (pixel >> 24) & 0xff;
int red = (pixel >> 16) & 0xff;
int green = (pixel >> 8) & 0xff;
int blue = (pixel) & 0xff;
return new int[] {red, green, blue, alpha};
}
public static double ColourDistance(Color c1, Color c2) {
double rmean = ( c1.getRed() + c2.getRed() )/2;
int r = c1.getRed() - c2.getRed();
int g = c1.getGreen() - c2.getGreen();
int b = c1.getBlue() - c2.getBlue();
double weightR = 2 + rmean/256;
double weightG = 4.0;
double weightB = 2 + (255-rmean)/256;
return Math.sqrt(weightR*r*r + weightG*g*g + weightB*b*b);
}
}
By "clearing" the pixel you obviously meant "to make the pixel transparent".
In order to be able to make a pixel transparent, the image has to support transparent pixels. Whether or not a BufferedImage supports transparent pixels depends on the type of the BufferedImage. After loading a BufferedImage with ImageIO, you hardly know the type of the image. But you can easily convert the image into an image with a known type (that supports transparency) by passing it to a method like this:
public static BufferedImage convertToARGB(BufferedImage image)
{
BufferedImage newImage = new BufferedImage(
image.getWidth(), image.getHeight(),
BufferedImage.TYPE_INT_ARGB);
Graphics2D g = newImage.createGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
return newImage;
}

Categories