I have been working on this method in Picture.java for a programming course. The code is supposed to take an original image with a target image, x and y coordinates, and return a merged image with the original image pasted on these coordinates on the target image. A precondition is that the target image must have bigger dimensions than the original image. Here's the code I wrote:
public Picture copyPicture (Picture target, int startx, int starty)
{
Picture merged = new Picture(target);
for (int x = 0, mergx = startx; x < getWidth(); x++, mergx++)
{
for (int y = 0, mergy = starty; y < getHeight(); y++, mergy++)
{
Pixel orig = getPixel(x,y);
Pixel mergedPix = merged.getPixel(mergx, mergy);
mergedPix.setColor(orig.getColor());
}
}
return merged;
}
However, the method doesn't seem to work for me. I'm not sure what I did wrong, but nothing happens to either of the images. Can someone give me a tip?
Related
Hi I am in need of some help. I need to write a convolution method from scratch that takes in the following inputs: int[][] and BufferedImage inputImage. I can assume that the kernel has size 3x3.
My approach is to do the follow:
convolve inner pixels
convolve corner pixels
convolve outer pixels
In the program that I will post below I believe I convolve the inner pixels but I am a bit lost at how to convolve the corner and outer pixels. I am aware that corner pixels are at (0,0), (width-1,0), (0, height-1) and (width-1,height-1). I think I know to how approach the problem but not sure how to execute that in writing though. Please to aware that I am very new to programming :/ Any assistance will be very helpful to me.
import java.awt.*;
import java.awt.image.BufferedImage;
import com.programwithjava.basic.DrawingKit;
import java.util.Scanner;
public class Problem28 {
// maximum value of a sample
private static final int MAX_VALUE = 255;
//minimum value of a sample
private static final int MIN_VALUE = 0;
public BufferedImage convolve(int[][] kernel, BufferedImage inputImage) {
}
public BufferedImage convolveInner(double center, BufferedImage inputImage) {
int width = inputImage.getWidth();
int height = inputImage.getHeight();
BufferedImage inputImage1 = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
//inner pixels
for (int x = 1; x < width - 1; x++) {
for (int y = 1; y < height - 1; y ++) {
//get pixels at x, y
int colorValue = inputImage.getRGB(x, y);
Color pixelColor = new Color(colorValue);
int red = pixelColor.getRed() ;
int green = pixelColor.getGreen() ;
int blue = pixelColor.getBlue();
int innerred = (int) center*red;
int innergreen = (int) center*green;
int innerblue = (int) center*blue;
Color newPixelColor = new Color(innerred, innergreen, innerblue);
int newRgbvalue = newPixelColor.getRGB();
inputImage1.setRGB(x, y, newRgbvalue);
}
}
return inputImage1;
}
public BufferedImage convolveEdge(double edge, BufferedImage inputImage) {
int width = inputImage.getWidth();
int height = inputImage.getHeight();
BufferedImage inputImage2 = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
//inner pixels
for (int x = 0; x < width - 1; x++) {
for (int y = 0; y < height - 1; y ++) {
//get pixels at x, y
int colorValue = inputImage.getRGB(x, y);
Color pixelColor = new Color(colorValue);
int red = pixelColor.getRed() ;
int green = pixelColor.getGreen() ;
int blue = pixelColor.getBlue();
int innerred = (int) edge*red;
int innergreen = (int) edge*green;
int innerblue = (int) edge*blue;
Color newPixelColor = new Color(innerred, innergreen, innerblue);
int newRgbvalue = newPixelColor.getRGB();
inputImage2.setRGB(x, y, newRgbvalue);
}
}
return inputImage2;
}
public BufferedImage convolveCorner(double corner, BufferedImage inputImage) {
int width = inputImage.getWidth();
int height = inputImage.getHeight();
BufferedImage inputImage3 = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
//inner pixels
for (int x = 0; x < width - 1; x++) {
for (int y = 0; y < height - 1; y ++) {
//get pixels at x, y
int colorValue = inputImage.getRGB(x, y);
Color pixelColor = new Color(colorValue);
int red = pixelColor.getRed() ;
int green = pixelColor.getGreen() ;
int blue = pixelColor.getBlue();
int innerred = (int) corner*red;
int innergreen = (int) corner*green;
int innerblue = (int) corner*blue;
Color newPixelColor = new Color(innerred, innergreen, innerblue);
int newRgbvalue = newPixelColor.getRGB();
inputImage3.setRGB(x, y, newRgbvalue);
}
}
return inputImage3;
}
public static void main(String[] args) {
DrawingKit dk = new DrawingKit("Compositor", 1000, 1000);
BufferedImage p1 = dk.loadPicture("image/pattern1.jpg");
Problem28 c = new Problem28();
BufferedImage p5 = c.convolve();
dk.drawPicture(p5, 0, 100);
}
}
I changed the code a bit but the output comes out as black. What did I do wrong:
import java.awt.*;
import java.awt.image.BufferedImage;
import com.programwithjava.basic.DrawingKit;
import java.util.Scanner;
public class Problem28 {
// maximum value of a sample
private static final int MAX_VALUE = 255;
//minimum value of a sample
private static final int MIN_VALUE = 0;
public BufferedImage convolve(int[][] kernel, BufferedImage inputImage) {
int width = inputImage.getWidth();
int height = inputImage.getHeight();
BufferedImage inputImage1 = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
//for every pixel
for (int x = 0; x < width; x ++) {
for (int y = 0; y < height; y ++) {
int colorValue = inputImage.getRGB(x,y);
Color pixelColor = new Color(colorValue);
int red = pixelColor.getRed();
int green = pixelColor.getGreen();
int blue = pixelColor.getBlue();
double gray = 0;
//multiply every value of kernel with corresponding image pixel
for (int i = 0; i < 3; i ++) {
for (int j = 0; j < 3; j ++) {
int imageX = (x - 3/2 + i + width) % width;
int imageY = (x -3/2 + j + height) % height;
int RGB = inputImage.getRGB(imageX, imageY);
int GRAY = (RGB) & 0xff;
gray += (GRAY*kernel[i][j]);
}
}
int out;
out = (int) Math.min(Math.max(gray * 1, 0), 255);
inputImage1.setRGB(x, y, new Color(out,out,out).getRGB());
}
}
return inputImage1;
}
public static void main(String[] args) {
int[][] newArray = {{1/9, 1/9, 1/9}, {1/9, 1/9, 1/9}, {1/9, 1/9, 1/9}};
DrawingKit dk = new DrawingKit("Problem28", 1000, 1000);
BufferedImage p1 = dk.loadPicture("image/pattern1.jpg");
Problem28 c = new Problem28();
BufferedImage p2 = c.convolve(newArray, p1);
dk.drawPicture(p2, 0, 100);
}
}
Welcome ewuzz! I wrote a convolution using CUDA about a week ago, and the majority of my experience is with Java, so I feel qualified to provide advice for this problem.
Rather than writing all of the code for you, the best way to solve this large program is to discuss individual elements. You mentioned you are very new to programming. As the programs you write become more complex, it's essential to write small working snippets before combining them into a large successful program (or iteratively add snippets). With this being said, it's already apparent you're trying to debug a ~100 line program, and this approach will cost you time in most cases.
The first point to discuss is the general approach you mentioned. If you think about the program, what is the simplest and most repeated step? Obviously this is the kernel/mask step, so we can start from here. When you convolute each pixel, you are performing a similar option, regardless of the position (corner, edge, inside). While there are special steps necessary for these edge cases, they share similar underlying steps. If you try to write code for each of these cases separately, you will have to update the code in multiple (three) places with each adjustment and it will make the whole program more difficult to grasp.
To support my point above, here's what happened when I pasted your code into IntelliJ. This illustrates the (yellow) red flag of using the same code in multiple places:
The concrete way to fix this problem is to combine the three convolve methods into a single one and use if statements for edge-cases as necessary.
Our pseudocode with this change:
convolve(kernel, inputImage)
for each pixel in the image
convolve the single pixel and check edge cases
endfor
end
That seems pretty basic right? If we are able to successfully check edge cases, then this extremely simple logic will work. The reason I left it so general above to show how convolve the single pixel and check edge cases is logically grouped. This means it's a good candidate for extracting a method, which could look like:
private void convolvePixel(int x, int y, int[][] kernel, BufferedImage input, BufferedImage output)
Now to implement our method above, we will need to break it into a few steps, which we may then break into more steps if necessary. We'll need to look at the input image, if possible for each pixel accumulate the values using the kernel, and then set this in the output image. For brevity I will only write pseudocode from here.
convolvePixel(x, y, kernel, input, output)
accumulation = 0
for each row of kernel applicable pixels
for each column of kernel applicable pixels
if this neighboring pixel location is within the image boundaries then
input color = get the color at this neighboring pixel
adjusted value = input color * relative kernel mask value
accumulation += adjusted value
else
//handle this somehow, mentioned below
endif
endfor
endfor
set output pixel as accumulation, assuming this convolution method does not require normalization
end
The pseudocode above is already relatively long. When implementing you could write methods for the if and the else cases, but it you should be fine with this structure.
There are a few ways to handle the edge case of the else above. Your assignment probably specifies a requirement, but the fancy way is to tile around, and pretend like there's another instance of the same image next to this input image. Wikipedia explains three possibilities:
Extend - The nearest border pixels are conceptually extended as far as necessary to provide values for the convolution. Corner pixels are extended in 90° wedges. Other edge pixels are extended in lines.
Wrap - (The method I mentioned) The image is conceptually wrapped (or tiled) and values are taken from the opposite edge or corner.
Crop - Any pixel in the output image which would require values from beyond the edge is skipped. This method can result in the output image being slightly smaller, with the edges having been cropped.
A huge part of becoming a successful programmer is researching on your own. If you read about these methods, work through them on paper, run your convolvePixel method on single pixels, and compare the output to your results by hand, you will find success.
Summary:
Start by cleaning-up your code before anything.
Group the same code into one place.
Hammer out a small chunk (convolving a single pixel). Print out the result and the input values and verify they are correct.
Draw out edge/corner cases.
Read about ways to solve edge cases and decide what fits your needs.
Try implementing the else case through the same form of testing.
Call your convolveImage method with the loop, using the convolvePixel method you know works. Done!
You can look up pseudocode and even specific code to solve the exact problem, so I focused on providing general insight and strategies I have developed through my degree and personal experience. Good luck and please let me know if you want to discuss anything else in the comments below.
Java code for multiple blurs via convolution.
I have an int[] representing a small bitmap that I want to copy into another int[] representing a larger bitmap. My code thus far looks like this:
private int[] copyToOffsetCentered(int[] src,
Rectangle srcDim, int[] dest, Rectangle destDim, int dx, int dy)
{
int startx = dx - srcDim.width / 2;
int endx = startx + srcDim.width;
int starty = dy - srcDim.height / 2;
int endy = starty + srcDim.height;
for (int x = Math.max(startx, 0); x < Math.min(endx, destDim.width); x++)
{
for (int y = Math.max(starty, 0); y < Math.min(endy, destDim.height); y++)
{
dest[y*destDim.width + x] = src[???];
}
}
return dest;
}
The idea is that the source image array could be clipped when copied to the target array if the offset is close enough to the edge of the image. As an example, if I passed in a 2x2 source image
src=[1,2,3,4]
and a 4x4 dest image
dest=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
with dx=0 and dy=1, I would expect the return array to be
dest=[2,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0]
This is due to the "edges" of the source being clipped based on the target center point.
I know that the solution is most likely pretty simple, but I am having a hard time wrapping my brain around what the math should look like to figure out the proper index I should be using for the source array inside the loops. Any help is much appreciated.
dx and dy are the destination coordinates of the src image at the center. The row of the image is index/Dimension.width and the column of the image is index%Dimension.width.
While you're iterating the starting coordinate in the source image will be.
int xSrc = x - start_x;
int ySrc = y - start_y;
int srcIndex = ySrc*srcDim.getWidth() + xSrc;
So I have to use java.awt.color to flip some imported images.
Here is my primary method to achieve flipping an image over the vertical axis:
public void execute (Pixmap target)
{
Dimension bounds = target.getSize();
// TODO: mirror target image along vertical middle line by swapping
// each color on right with one on left
for (int x = 0; x < bounds.width; x++) {
for (int y = 0; y < bounds.height; y++) {
// new x position
int newX = bounds.width - x - 1;
// flip along vertical
Color mirrorVert = target.getColor(newX, y);
target.setColor(x, y, new Color (mirrorVert.getRed(),
mirrorVert.getGreen(),
mirrorVert.getBlue()));
}
}
}
However, when this executes, instead of the image, flipping, I get something like this:
Original:
"Flipped":
Thank y'all for the help
// flip along vertical
Color mirrorVert = target.getColor(newX, y);
target.setColor(x, y, new Color (mirrorVert.getRed(),
mirrorVert.getGreen(),
mirrorVert.getBlue()));
target.setColor(newX, y , new Color(255,255,255));
}
This should work in theory. Basically the idea is to set the Colors on the right side to white, while copying it over to the left side.
Actually this will not work... So what you could do is to save the new colors in an array. Then you can make everything white and put the swapped colors back.
for (int i=0;i<image.getWidth();i++)
for (int j=0;j<image.getHeight();j++)
{
int tmp = image.getRGB(i, j);
image.setRGB(i, j, image.getRGB(i, image.getHeight()-j-1));
image.setRGB(i, image.getHeight()-j-1, tmp);
}
That one looks promising.
I'm looking for a way to find the dimensions of the visible part of an image is. The image I'm displaying in my ImageView is .png format, it has a portion that is "visible" and the rest is an invisible background.
Example Image:
←that box isn't visible on the real image, it's just to illustrate my point
So in this image there is only a small red wedge shape which is visible, but the full .png is really a rectangle of larger dimensions, thus I can't use something like bitmap.getWidth();
So:
How can I find out if a particular pixel in an image is "invisible" or not? Note: I know I can use bitmap.getPixel(x, y); to get a pixel, but I don't know what to do with it once I have it; is a test for 0 sufficient?
Is there a better way of finding the max width/height of the "visible" portion other than iterating through every pixel looking for the visible "end points"?
How can I find out if a particular pixel in an image is "invisible" or not? Note: I know I can use bitmap.getPixel(x, y); to get a pixel, but I don't know what to do with it once I have it; is a test for 0 sufficient?
Use image.getPixel(x, y) != Color.TRANSPARENT to check whether the pixel is visible or not.
Is there a better way of finding the max width/height of the "visible" portion other than iterating through every pixel looking for the visible "end points"?
There is no built in functions. You can use the below function to get the image in square shape leaving the transparent pixels out.
public static Bitmap removeTransparentPixels(Bitmap image) {
int x1 = image.getWidth();
int y1 = image.getHeight();
int width = 0, height = 0;
for (int x = 0; x < image.getWidth(); x++) {
for (int y = 0; y < image.getHeight(); y++) {
if (image.getPixel(x, y) != Color.TRANSPARENT) {
if (x < x1) {
x1 = x;
} else if (x > width) {
width = x;
}
if (y < y1) {
y1 = y;
} else if (y > height) {
height = y;
}
}
}
}
width = width - x1;
height = height - y1;
return Bitmap.createBitmap(image, x1, y1, width, height);
}
Make sure that your image doesn't contain only the transparent pixels. If the image has only transparent pixels then the statement Bitmap.createBitmap(image, x1, y1, width, height); will through exception.
There are probably some form of image processing libraries that you would need to take advantage of in order to achieve what you are requesting in order to keep the processing down if that is a concern such as OpenCV or ImageMagick that would probably get that information back to you in a quick manner via specific function calls.
As far as I know, there wouldn't be a built in way to determine that through a standard call into the image libraries that exist within Android. You would probably need to do some sort of heuristic check for transparent pixels as you mentioned with your original thought.
I'm using LWJGL and Slick2D for a game I'm making. I can't seem to get it to draw the way I want it to be draw so I came up with an idea just to make my own drawing method. Basically it takes a image, a x, and a y and it goes through each pixel in the image, gets the color, then draws the image with the parameter x plus the x pixel it's on to get the position that the pixel is suppost to be drawn on. Same idea with the y. Although if the alpha channel isn't 255 for the pixel it doesn't draw it, although I'll fix that later. The problem is that whenever I run my code I get "Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -2044". I'm really confused. I'm hoping someone can figure out why this is happening.
private void DrawImage(Image image, int xP, int yP)
{
//xP And yP Are The Position Parameters
//Begin Drawing Individual Pixels
glBegin(GL_POINTS);
//Going Across The X And The Y Coords Of The Image
for (int x = 1; x <= image.getWidth(); x++)
{
for (int y = 1; y <= image.getHeight(); y++)
{
//Define A Color Object
Color color = null;
//Set The Color Object And Check If The Color Is Completly Solid Before Rendering
if ((color = image.getColor(x, y)).a == 255)
{
//Bind The Color
color.bind();
//Draw The Color At The Coord Parameters And The X/Y Coord Of The Individual Pixel
glVertex2i(xP + x - 1, yP + y - 1);
}
}
}
glEnd();
}
My answer is assuming that the texture is an array of data.
I have a feeling it is the getColor() method. Your for loop runs through and will use the height and width values. An array usually starts off with 0 and width and height are just array counts typically. So I can see when you reach HEIGHT, that the texture array will throw an exception.
Try removing the <= part and replace it with <
EXAMPLE:
for (int x = 1; x < image.getWidth(); x++)
It may also help you to start off with zero so you can get the entire image.
EXAMPLE
for (int x = 0; x < image.getWidth(); x++)
Here is a link on arrays.
This way, when you ask for the color at whatever position, it will never ask for a color reaching beyond what is in the texture array. Hopefully I made sense.