I am trying to zoom an image twice using bilinear interpolation, but it's not working.It is giving errors like division by 0 , out of range value(the output color has exceeded 255). Here is my code :
int red1,green1,blue1;
int red2,green2,blue2;
int red3,green3,blue3;
int red4,green4,blue4;
int redf,greenf,bluef;
int x1,y1,x2,y2,x,y;
int a,b,c,d;
int var[][]=new int[4][4];
int inv[][]=new int[4][4];
//int cons[][]=new int[1][4];
//int col[][]=new int[1][4];
for(int i=0;i<height*2;i++)
{
//l=0;
for(int j=0;j<width*2;j++)
{
Color color=new Color(img.getRGB((int)(j/2),(int)(i/2)));
red=color.getRed();
green=color.getGreen();
blue=color.getBlue();
x=(int)(j/2);
y=(int)(i/2);
x1=(int)(j/2)+1;
y1=(int)(i/2)+1;
x2=(int)(j/2)-1;
y2=(int)(i/2)-1;
if(x1<0 || x1>=width || y1<0 || y1>=height)
{
//System.out.println("Yes");
red1=0;
green1=0;
blue1=0;
}
else
{
Color c1=new Color(img.getRGB(x1,y1));
red1=c1.getRed();
green1=c1.getGreen();
blue1=c1.getBlue();
}
if(x2<0 || x2>=width || y2<0 || y2>=height)
{
//System.out.println("Yes2");
red2=0;
green2=0;
blue2=0;
}
else
{
Color c2=new Color(img.getRGB(x2,y2));
red2=c2.getRed();
green2=c2.getGreen();
blue2=c2.getBlue();
}
if(x1<0 || x1>=width || y2<0 || y2>=height)
{
red3=0;
green3=0;
blue3=0;
}
else
{
Color c3=new Color(img.getRGB(x1,y2));
red3=c3.getRed();
green3=c3.getGreen();
blue3=c3.getBlue();
}
if(x2<0 || x2>=width || y1<0 || y1>=height)
{
red4=0;
green4=0;
blue4=0;
}
else
{
Color c4=new Color(img.getRGB(x2,y1));
red4=c4.getRed();
green4=c4.getGreen();
blue4=c4.getBlue();
}
if(x1<=0 || x1>width)
x1=0;
if(x2<=0 || x2>width)
x2=0;
if(y1<=0 || y1>height)
y1=0;
if(y2<=0 || y2>height)
y2=0;
var[0][0]=x1;
var[0][1]=y1;
var[0][2]=x1*y1;
var[0][3]=1;
var[1][0]=x2;
var[1][1]=y2;
var[1][2]=x2*y2;
var[1][3]=1;
var[2][0]=x1;
var[2][1]=y2;
var[2][2]=x1*y2;
var[2][3]=1;
var[3][0]=x2;
var[3][1]=y1;
var[3][2]=x2*y1;
var[3][3]=1;
inv=invert(var);
a=inv[0][0]*red1+inv[0][1]*red2+inv[0][2]*red3+inv[0][3]*red4;
b=inv[1][0]*red1+inv[1][1]*red2+inv[1][2]*red3+inv[1][3]*red4;
c=inv[2][0]*red1+inv[2][1]*red2+inv[2][2]*red3+inv[2][3]*red4;
d=inv[3][0]*red1+inv[3][1]*red2+inv[3][2]*red3+inv[3][3]*red4;
redf=a*x+b*y+c*x*y+d;
a=inv[0][0]*green1+inv[0][1]*green2+inv[0][2]*green3+inv[0][3]*green4;
b=inv[1][0]*green1+inv[1][1]*green2+inv[1][2]*green3+inv[1][3]*green4;
c=inv[2][0]*green1+inv[2][1]*green2+inv[2][2]*green3+inv[2][3]*green4;
d=inv[3][0]*green1+inv[3][1]*green2+inv[3][2]*green3+inv[3][3]*green4;
greenf=a*x+b*y+c*x*y+d;
a=inv[0][0]*blue1+inv[0][1]*blue2+inv[0][2]*blue3+inv[0][3]*blue4;
b=inv[1][0]*blue1+inv[1][1]*blue2+inv[1][2]*blue3+inv[1][3]*blue4;
c=inv[2][0]*blue1+inv[2][1]*blue2+inv[2][2]*blue3+inv[2][3]*blue4;
d=inv[3][0]*blue1+inv[3][1]*blue2+inv[3][2]*blue3+inv[3][3]*blue4;
bluef=a*x+b*y+c*x*y+d;
System.out.println(redf+" "+greenf+" "+bluef);//prints the value
Color nc=new Color(redf,greenf,bluef);
img1.setRGB(j, i, nc.getRGB());
}
}
Kindly help . I am trying to zoom by 2 , and using 4 neighbours(bilinear approach)
Sorry for being a bit late but for Bilinear Interpolation what you need to do is interpolation the results of two different interpolations. Basically it would look something like:
newX = x - 0.5
a1 = newX - (int) (newX)
newY = y - 0.5
a2 = newY - (int) (newY)
Red1 = getRed((int) (x - 0.5), (int) (y - 0.5))
Red2 = getRed((int) (x + 0.5), (int) (y - 0.5))
Red3 = getRed((int) (x - 0.5), (int) (y + 0.5))
Red4 = getRed((int) (x + 0.5), (int) (y + 0.5))
newRed = lerp(lerp(Red1, Red2, a1), lerp(Red3, Red4, a1), a2)
This could, of course be repeated for green and blue.
X and Y in this are source coords, so if you wanted to find the color at (3, 5) of your new image you would run this on (1.5, 2.5) aka your original coords divided by your scaling factor (2).
In case you don't know lerp() is generaly just
lerp(x, y, a)
return x * (1 - a) + y * a;
but if cycles really matter to you or you have a primitive FPU or any number of other special case the less precise
return a + f * (b - a);
can work.
*
Edit:
Since we're in java I've just used
(int)
to signify rounding down but it doesn't actually have to be an int there.
Related
I'm trying to make a function which separates a pictures into areas by taking each pixel and search recursively
if any of it's 8 nighbors are similar (by comparing their hue value) and then painting over them with the same color.
I started simple in (0,0) and tried to "travel" recursivley to any similar pixel and painting them all in red until i get stuck.
It worked fine on a 55x55 picture but when i tried 300x55 i got the famous StackOverflow exception.
Travel function (after some edits, addad boolean matrix to flag visited pixels):
private static void area( int x, int y){
//img and visited[][] are global variables
int height = img.getHeight();
int width = img.getWidth();
visited[x][y] = true;
int color = img.getRGB(x,y); // store before painting
// if(img.getRGB(x,y) != Color.RED.getRGB())
img.setRGB(x, y, Color.RED.getRGB());
// else
// return;
//spread to 8 directions clockwise
//top
if ((y - 1) >= 0)
if(!visited[x][y-1] && hsbSimilarity(color,img.getRGB(x,y - 1)))
area( x, y - 1);
//top right
if ((x + 1) < width && (y - 1) >= 0)
if(!visited[x+1][y-1] && hsbSimilarity(color, img.getRGB(x + 1,y - 1)))
area( x + 1, y - 1);
//right
if((x + 1) < width)
if(!visited[x+1][y] && hsbSimilarity(color, img.getRGB(x + 1,y)))
area( x + 1, y);
//bot right
if((x + 1) < width && (y + 1) < height)
if(!visited[x+1][y+1] && hsbSimilarity(color, img.getRGB(x + 1,y + 1)))
area(x + 1, y + 1);
//bot
if((y + 1) < height)
if(!visited[x][y+1] && hsbSimilarity(color, img.getRGB(x,y + 1)))
area(x, y + 1);
//bot left
if((x - 1) >= 0 && (y + 1) < height)
if(!visited[x-1][y+1] && hsbSimilarity(color, img.getRGB(x - 1,y + 1)))
area(x - 1, y + 1);
//left
if((x - 1) >= 0)
if(!visited[x-1][y] && hsbSimilarity(color, img.getRGB(x - 1,y)))
area( x - 1, y);
//top left
if((x - 1) >= 0 && (y - 1) >= 0)
if(!visited[x-1][y-1] && hsbSimilarity(color, img.getRGB(x - 1,y - 1)))
area(x - 1, y - 1);
}
Comparison function:
private static boolean hsbSimilarity( int rgb1, int rgb2){
Color color1 = new Color(rgb1);
Color color2 = new Color(rgb2);
float[] hsb1 = new float[3];
float[] hsb2 = new float[3];
color1.RGBtoHSB(color1.getRed(), color1.getGreen(), color1.getBlue(), hsb1);
color2.RGBtoHSB(color2.getRed(), color2.getGreen(), color2.getBlue(), hsb2);
int hue1 = (int)(hsb1[0] * 360);
int hue2 = (int)(hsb2[0] * 360);
int hueDistance = Math.abs(hue1 - hue2);
return hueDistance < 5 || hueDistance > 355 ; //circle concept where 0 equals to 360
}
It seems that you have a cycle problem. This means your code may literally be running in circles (eg. 0|0 0|1 0|0 etc., or sth. alike). Also this is not size related, so I'm pretty sure that everything would be fine for a massive noise picture as how everything would be horibble for a completly red one. To avoid this issue I'd suggest not going back to pixels you already checked on, so maby try populating a list containing the pixels you already visited and then check if the one you are going to travel to is already inside there, and if it is don't go there.
I am making a game and I noticed whenever I use the graphics.translate function and after the translate this happens to the images.
Before Translation
After Translation
I was wondering if there is anyway to fix that or anyone else has the same issue. All these sprites are rendered from a spritesheet
EDIT: Translate code
public void translate(Graphics g, GameContainer container, int delta) {
g.translate(((container.getWidth() / 2) - this.x), ((container.getHeight() / 2) - this.y));
}
public void update(GameContainer container, int type){
if (type == 0) {
x = p.getX(); //p is the player
y = p.getY();
} else if (type == 1) {
x = player.x;
y = player.y;
}
if (offset) {
if (this.x - container.getWidth() / 2 < offsetMin[0]) {
x = offsetMin[0] + container.getWidth() / 2;
} else if (this.x + container.getWidth() / 2 > offsetMax[0]) {
x = offsetMax[0] - container.getWidth() / 2;
}
if (this.y - container.getHeight() / 2 < offsetMin[1]) {
y = offsetMin[1] + container.getHeight() / 2;
} else if (this.y + container.getHeight() > offsetMax[1]) {
y = offsetMax[1] - container.getHeight() / 2;
}
}
}
Try casting the x and y parameters for g.translate() to ints. That would eliminate any rounding errors where tiles don't end up on perfect pixel coords (IE 4, not 4.2).
Moved answer from comments to answer so it can be marked as accepted by OP
So I have a project for class I am working on in which you have to create a GUI box filled with circles, except the middle 50% of the screen cannot be filled with circles. Also, the red color value of each circle scales linearly from top to bottom of the screen, 0 at the top, 255 at the bottom. Here is what it should look like:
Here's what I have. I tried doing 255/500 (500 is the height) in order to get a scaling factor which I would then use to multiply all my y coordinates by in order to get the specified red value and it worked. The answer to 255 / 500 is 0.51 and when I used 0.51 instead of y * (255 / getHeight()); it worked. I need it to work with any dimensions of the frame, however, so the 0.51 doesn't work. For some reason the y * (255 / getHeight()) does not work, it appears to be returning 0 as the circles are various shades of blue and green. What can i do to fix this?
The code I have:
public class NewJComponent1 extends JComponent {
public void paintComponent(Graphics g) {
int count = 0;
int diameter = 0;
Random rand = new Random();
while (count < 5000) {
int x = rand.nextInt(getWidth() + 1);
int y = rand.nextInt(getHeight() + 1);
int greenValue = rand.nextInt(256);
int blueValue = rand.nextInt(256);
diameter = rand.nextInt(21) + 10;
int redValue = y * (255 / getHeight());
Color random = new Color (redValue, greenValue, blueValue);
if ((x < (getWidth() / 4) && y <= (getHeight() - diameter))
|| ((x > (getWidth() * .75) && (x < getWidth() - diameter)) && y <= (getHeight() - diameter))
|| (x <= (getWidth() - diameter) && y < (getHeight() / 4))
|| (x <= (getWidth() - diameter) && ((y > (getHeight() * .75)) && (y <= getHeight() - diameter)))){
g.setColor(random);
g.fillOval(x, y, diameter, diameter);
count++;
}
}
System.out.println(getHeight());
System.out.println(getWidth());
}
}
I tried various iterations of the redValue code, swapping order, making a double and typecasting to int, and various other things but I couldn't get it to work. I'm sure its a small mistake that is messing everything up, but anyways thank you for the help regardless. I am using Android Studio, not sure if that really would impact anything.
Replace this line
int redValue = y * (255 / getHeight());
with
int redValue = (int) Math.round(y * (255.0 / (double) getHeight()));
Just changing redValue to an double wouldn't change the fact that 255/getHeight() is integer division.
I'm building a game and I have a system for loading images into the game, but returning them to the screen as blocks.
The two main colors I use in the map as of now are: 0x000000 (Black) and 0x9EEDFF (Light Blue). I have this system in which I return a certain block to the screen with a certain color.
if (blocks[x + (y * width] == 0x000000) return VoidBlock.block;
if (blocks[x + (y * width] == 0x9EEDFF) return IceBlock.block;
When I first ran it, it didn't work. All I got was an empty abyss. :/
But, what I did was I managed to output the colors of the blocks and I got these very strange numbers: -6361601 for black and -16777216 for light blue. I attempted to decode them via online with decimal to hexadecimal converters, but nothing seemed to give me my color. It gave me like, 134861234 or something, and it didn't really help a lot.
So, my question is, how does Java get that number and how I can ensure that my above code will match it? Right now, the only code that's running my program is:
if (blocks[x + (y * width] == -6361601) return VoidBlock.block;
if (blocks[x + (y * width] == -16777216) return IceBlock.block;
Thanks in advance.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public void loadLevel(String pathway) {
try {
BufferedImage image = ImageIO.read(Level.class.getResource(pathway));
int image_width = image.getWidth();
int image_height = image.getHeight();
pixels = new int[image_width * image_height];
image.getRGB(0, 0, width, height, pixels, 0, width);
} catch (IOException exc) {
exc.printStackTrace();
}
}
That was my loadImage() method for taking the image and converting it to that. Now, here's my generateLevel() method:
public void generateLevel() {
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
blocks[x + (y * width)] = pixels[x + (y * width)];
System.out.println(blocks[x + (y * width)]);
}
}
}
It all comes together in this method:
public Block getBlock(int xPos, int yPos) {
if (xPos < 0 || xPos >= width || yPos < 0 || yPos >= height) return EmptyBlock.block;
if (blocks[xPos + (yPos * width)] == -6361601) return StoneBrickBlock.block;
//if (blocks[xPos + (yPos * width)] == 0x9EEDFF) return StoneBlock.block;
//if (blocks[xPos + (yPos * width)] == 2) return LavaBlock.block;
if (blocks[xPos + (yPos * width)] == -16777216) return IceStoneBrickBlock.block;
return EmptyBlock.block;
}
OK, -16777216 corresponds to alpha = 255, red = 0, green = 0, blue = 0. You almost certainly don't care about the alpha, so you should ignore it when you do your comparison.
So you could write
if (blocks[x + (y * width)] & 0xFFFFFF == 0x000000)
which checks whether the value is "black plus some alpha".
Likewise, -6361601 corresponds to alpha = 255, plus your "light blue" (9EEDFF). So the same trick will work there too.
if (blocks[x + (y * width)] & 0xFFFFFF == 0x9EEDFF)
It seems your only issue was your need to ignore the alpha value.
I posted something similar yesterday, but got nothing. I spent a few hours today problem-solving, but didn't progress any.
I'm using Processing (the language) and trying to implement a method that draws a line between two points. (I don't want to use the library's line() method.)
My lineCreate method works great for positive slopes, but fails with negative slopes. Can you help figure out why?
Here's the lineCreate() code:
void createLine(int x0, int y0, int x1, int y1){
//...
// Handle slanted lines...
double tempDX = x1 - x0;
double tempDY = y1 - y0; // Had to create dx and dy as doubles because typecasting dy/dx to a double data type wasn't working.
double m = (-tempDY / tempDX); // m = line slope. (Note - The dy value is negative
int deltaN = (2 * -dx); // deltaX is the amount to increment d after choosing the next pixel on the line.
int deltaNE = (2 * (-dy - dx)); // ...where X is the direction moved for that next pixel.
int deltaE = (2 * -dy); // deltaX variables are used below to plot line.
int deltaSE = (2 * (dy + dx));
int deltaS = (2 * dx);
int x = x0;
int y = y0;
int d = 0; // d = Amount d-value changes from pixel to pixel. Depends on slope.
int region = 0; // region = Variable to store slope region. Different regions require different formulas.
if(m > 1){ // if-statement: Initializes d, depending on the slope of the line.
d = -dy - (2 * dx); // If slope is 1-Infiniti. -> Use NE/N initialization for d.
region = 1;
}
else if(m == 1)
region = 2;
else if(m > 0 && m < 1){
d = (2 * -dy) - dx; // If slope is 0-1 -> Use NE/E initialization for d.
region = 3;
}
else if(m < 0 && m > -1){
d = (2 * dy) + dx; // If slope is 0-(-1) -> Use E/SE initliazation for d.
region = 4;
}
else if(m == -1)
region = 5;
else if(m < -1){
d = dy + (2 * dx); // If slope is (-1)-(-Infiniti) -> Use SE/S initialization for d.
region = 6;
}
while(x < x1){ // Until points are connected...
if(region == 1){ // If in region one...
if(d <= 0){ // and d<=0...
d += deltaNE; // Add deltaNE to d, and increment x and y.
x = x + 1;
y = y - 1;
}
else{
d += deltaN; // If d > 0 -> Add deltaN, and increment y.
y = y - 1;
}
}
else if(region == 2){
x = x + 1;
y = y - 1;
}
else if(region == 3){ // If region two...
if(d <= 0){
d += deltaE;
x = x + 1;
}
else{
d += deltaNE;
x = x + 1;
y = y - 1;
}
}
else if(region == 4){ // If region three...
if(d <= 0){
d += deltaSE;
x = x + 1;
y = y + 1;
}
else{
d += deltaE;
x = x + 1;
}
}
else if(region == 5){
x = x + 1;
y = y + 1;
}
else if(region == 6){ // If region four...
if(d <= 0){
d += deltaSE;
x = x + 1;
y = y + 1;
}
else{
d += deltaS;
y = y + 1;
}
}
point(x, y); // Paints new pixel on line going towards (x1,y1).
}
return;
}
Have a look at this page. It explains the whole theory behind line drawing with code examples.
There are a number of known algorithm for line drawing. Read about them here.