I am trying to flip a square image inside a picture with user input variables. After running the code nothing happens at all. In other attempts I was able to make a small thin rectangle appear. How do I fix this?
public void flipHorizontal (int x, int y, int size)
{
int half = size / 2;
int x1 = x - half;
int y1 = y - half;
int x2 = x + half;
int y2 = y + half;
Pixel sourcePixel = getPixel (x1,y1);
Pixel targetPixel = getPixel (x1, y1 + half);
//loop through columns
for (x = x; x < x2; x++)
{
//loop from 0 to before mirror point
for (y = y; y < y2 + half; y++)
{
Color friend = sourcePixel.getColor();
sourcePixel = getPixel (x1,y1);
targetPixel = getPixel (x1, y1 + half);
targetPixel.setColor (friend);
}
}
}
Related
I am trying to hollow out a sphere, I already achieved this however it is incredibly slow (A few seconds for a sphere with a radius of 5, a few minutes for a sphere with a radius of 100)
This is my code:
BlockPos pos = player.getBlockPos();
int startX = pos.getX();
int startY = pos.getY();
int startZ = pos.getZ();
int squaredRadius = radius * radius;
int x1;
int y1;
int z1;
int flags = 2 | 8 | 16 | 32;
BlockPos.Mutable blockPos = new BlockPos.Mutable(0, 0, 0);
BlockState state = Blocks.AIR.getDefaultState();
for (int x = startX - radius; x < startX + radius; x++) {
for (int y = Math.max(0, startY - radius), maxY2 = Math.min(255, startY + radius); y < maxY2; y++) {
for (int z = startZ - radius; z < startZ + radius; z++) {
x1 = x - startX;
y1 = y - startY;
z1 = z - startZ;
if (x1 * x1 + y1 * y1 + z1 * z1 <= squaredRadius)
world.setBlockState(blockPos.set(x, y, z), state, flags);
}
}
}
How could I speed this up? (Or is it already as fast as it can be?)
EDIT: For a 100 radius it takes roughly 8 minutes on my machine
Update: I managed to fix it! What I did was make a mixin into World#setBlockState(BlockPos, BlockState, int) and check if the flags were some number I set (999 in my case), and if it where I canceled the method execution right after the block state was set, saving huge amounts of time when placing a lot of blocks. However, it did not send the chunks to the player so what you have to do is simply send all the chunks you changed to the player, I did this by storing all the chunks I changed and for each player in the world I sent a ChunkDataS2CPacket with the new chunk to the player, which fixed my problem entirely, it works like a charm :D
EDIT: It also does not do block updates/lighting updates
I was researching bulge effect and I referenced this link below:
https://math.stackexchange.com/questions/266250/explanation-of-this-image-warping-bulge-filter-algorithm
the examples image are all nxn type, what if the image is mxn.
i tried to code but it always throws exception: row out of bounds.
my code as follows:
public static Picture positionalTransform(Picture picture) {
int w = picture.width();
int h = picture.height();
double X = 0;
double Y = 0;
Picture newPic = new Picture(w,h);
for(int x=0; x<w; x++){
for(int y=0; y<h; y++){
X = x - x/2;
Y = y - y/2;
double r = Math.hypot(X, Y);
double angle = Math.atan2(X, Y);
double rn = Math.pow(r, 2.5)/0.5;
X = (int) (rn * Math.sin(angle) + x/2);
Y = (int) (rn * Math.cos(angle) + y/2);
newPic.setColor((int)X, (int)Y, picture.getColor(x, y));
}
}
picture = newPic;
return picture;
}
I am making a tiled based game in java and I want to make a light map.
I am having some issues. I have the lightmap array that has lights placed on it that affect the array. Lights emit in a circle shape. It seems ok so far but its not exactly what I wanted.
Here is my code so far:
for(float i = 0; i < strength + 1; i++){
for(double u = 0.0f; u < 360; u += 0.5){
double angle = u * Math.PI / 180;
int x2 = (int)(x + i * Math.cos(angle));
int y2 = (int)(y + i * Math.sin(angle));
if(map[y2][x2] > 1 - 1 / i)
map[y2][x2] = 1 - 1 / i;
}
}
Result:
As you can see in the result, it seems as though the light is expanding too much on the bottom left side (red x's). How do I fix this?
Background info:
Strength:
The radius of how far the light reaches. This also
determines how bright the light will be at each tile of the array.
The Array "map" is a 2D float array. The engine I am using uses float
values for the alpha channel. The range is 0 (completely transparent)
to 1 (completely opaque).
Solution (Thanks to Gene):
for(int x2 = -strength; x2 <= strength; x2++){
for (int y2 = -strength; y2 <= strength; y2++) {
double r = Math.sqrt(x2 * x2 + y2 * y2);
double inv_rad = r <= strength + 1 ? 1 / r : 0;
if(map[y + y2][x + x2] > 1 - (float) inv_rad)
map[y + y2][x + x2] = 1 - (float) inv_rad;
}
}
Your algorithm suffers from integer truncation of the map indicies. Try it the other away around. Compute the distance from each pixel in a square surrounding the center to the center. From this distance calculate what the intensity ought to be. It will be something like this:
for (x = -R; x <= R; x++)
for (y = -R; y <= R; y++) {
double r = Math.sqrt(x * x + y * y);
double inv_rad = r <= R ? 1 / r : 0; // truncate outside radius R
map[yc + y][xc + x] = 1 - inv_rad;
}
Here xc and yc are the integer center coordinates. R is the half-size of the box around the center.
when i try to add this to my project i only get o.o back
the values i entered where 500, 500,50
private float map[][] = new float[1000][1000];
public void test(int x, int y, float strength){
public void addLight(int x,int y,int strength ){
for(int x2 = -strength; x2 <= strength; x2++){
for (int y2 = -strength; y2 <= strength; y2++) {
double r = Math.sqrt(x2 * x2 + y2 * y2);
double inv_rad = r <= strength + 1 ? 1 / r : 0;
if(map[y + y2][x + x2] > 1 - (float) inv_rad)
map[y + y2][x + x2] = 1 - (float) inv_rad;
System.out.println(map[y + y2][x + x2]);
}
}
}
I am trying to find image in an image. I do this for desktop automation. At this moment, I'm trying to be fast, not precise. As such, I have decided to match similar image solely based on the same average color.
If I pick several icons on my desktop, for example:
And I will search for the last one (I'm still wondering what this file is):
You can clearly see what is most likely to be the match:
In different situations, this may not work. However when image size is given, it should be pretty reliable and lightning fast.
I can get a screenshot as BufferedImage object:
MSWindow window = MSWindow.windowFromName("Firefox", false);
BufferedImage img = window.screenshot();
//Or, if I can estimate smaller region for searching:
BufferedImage img2 = window.screenshotCrop(20,20,50,50);
Of course, the image to search image will be loaded from template saved in a file:
BufferedImage img = ImageIO.read(...whatever goes in there, I'm still confused...);
I explained what all I know so that we can focus on the only problem:
Q: How can I get average color on buffered image? How can I get such average color on sub-rectangle of that image?
Speed wins here. In this exceptional case, I consider it more valuable than code readability.
I think that no matter what you do, you are going to have an O(wh) operation, where w is your width and h is your height.
Therefore, I'm going to post this (naive) solution to fulfil the first part of your question as I do not believe there is a faster solution.
/*
* Where bi is your image, (x0,y0) is your upper left coordinate, and (w,h)
* are your width and height respectively
*/
public static Color averageColor(BufferedImage bi, int x0, int y0, int w,
int h) {
int x1 = x0 + w;
int y1 = y0 + h;
long sumr = 0, sumg = 0, sumb = 0;
for (int x = x0; x < x1; x++) {
for (int y = y0; y < y1; y++) {
Color pixel = new Color(bi.getRGB(x, y));
sumr += pixel.getRed();
sumg += pixel.getGreen();
sumb += pixel.getBlue();
}
}
int num = w * h;
return new Color(sumr / num, sumg / num, sumb / num);
}
There is a constant time method for finding the mean colour of a rectangular section of an image but it requires a linear preprocess. This should be fine in your case. This method can also be used to find the mean value of a rectangular prism in a 3d array or any higher dimensional analog of the problem. I will be using a gray scale example but this can be easily extended to 3 or more channels simply by repeating the process.
Lets say we have a 2 dimensional array of numbers we will call "img".
The first step is to generate a new array of the same dimensions where each element contains the sum of all values in the original image that lie within the rectangle that bounds that element and the top left element of the image.
You can use the following method to construct such an image in linear time:
int width = 1920;
int height = 1080;
//source data
int[] img = GrayScaleScreenCapture();
int[] helperImg = int[width * height]
for(int y = 0; y < height; ++y)
{
for(int x = 0; x < width; ++x)
{
int total = img[y * width + x];
if(x > 0)
{
//Add value from the pixel to the left in helperImg
total += helperImg[y * width + (x - 1)];
}
if(y > 0)
{
//Add value from the pixel above in helperImg
total += helperImg[(y - 1) * width + x];
}
if(x > 0 && y > 0)
{
//Subtract value from the pixel above and to the left in helperImg
total -= helperImg[(y - 1) * width + (x - 1)];
}
helperImg[y * width + x] = total;
}
}
Now we can use helperImg to find the total of all values within a given rectangle of img in constant time:
//Some Rectangle with corners (x0, y0), (x1, y0) , (x0, y1), (x1, y1)
int x0 = 50;
int x1 = 150;
int y0 = 25;
int y1 = 200;
int totalOfRect = helperImg[y1 * width + x1];
if(x0 > 0)
{
totalOfRect -= helperImg[y1 * width + (x0 - 1)];
}
if(y0 > 0)
{
totalOfRect -= helperImg[(y0 - 1) * width + x1];
}
if(x0 > 0 && y0 > 0)
{
totalOfRect += helperImg[(y0 - 1) * width + (x0 - 1)];
}
Finally, we simply divide totalOfRect by the area of the rectangle to get the mean value:
int rWidth = x1 - x0 + 1;
int rheight = y1 - y0 + 1;
int meanOfRect = totalOfRect / (rWidth * rHeight);
Here's a version based on k_g's answer for a full BufferedImage with adjustable sample precision (step).
public static Color getAverageColor(BufferedImage bi) {
int step = 5;
int sampled = 0;
long sumr = 0, sumg = 0, sumb = 0;
for (int x = 0; x < bi.getWidth(); x++) {
for (int y = 0; y < bi.getHeight(); y++) {
if (x % step == 0 && y % step == 0) {
Color pixel = new Color(bi.getRGB(x, y));
sumr += pixel.getRed();
sumg += pixel.getGreen();
sumb += pixel.getBlue();
sampled++;
}
}
}
int dim = bi.getWidth()*bi.getHeight();
// Log.info("step=" + step + " sampled " + sampled + " out of " + dim + " pixels (" + String.format("%.1f", (float)(100*sampled/dim)) + " %)");
return new Color(Math.round(sumr / sampled), Math.round(sumg / sampled), Math.round(sumb / sampled));
}
I need to draw a line from two points and what I did so far is using drawLine(x1,y1,x2,y2). But what I want to do is draw a line that intersects with these two points (x1,y1) and (x2,y2).
I don't want to just draw a line between them, here's an image of what I have and what I want to do:
you could use some mathematik. get the increase of your line. You should know the function
f(x) = mx + b. With your two points,which you allready got, you can calculate two other Points at the Border of your frame, and draw a line between them
You'll need to calculate the coordinates at which your line meets the boundaries of your graphics context.
If you have (x1,y1) and (x2,y2), calculate the x_a and y_a such that (x_a,0) and (0,y_a) lie on the line.
If x_a = 0, the line will start from the left edge. If y_a = 0, the line will start from the top edge.
Repeat for the bottom/right coords of the line.
Bresenham's line algorithm
private int sign (int x) {
return (x > 0) ? 1 : (x < 0) ? -1 : 0;
}
public void drawBresenhamLine (int xstart, int ystart, int xend, int yend, Graphics g){
int x, y, dx, dy, incx, incy, pdx, pdy, es, el, err;
dx = xend - xstart;
dy = yend - ystart;
incx = sign(dx);
incy = sign(dy);
if (dx < 0) dx = -dx;
if (dy < 0) dy = -dy;
if (dx > dy){
pdx = incx; pdy = 0;
es = dy; el = dx;
} else {
pdx = 0; pdy = incy;
es = dx; el = dy;
}
x = xstart;
y = ystart;
err = el/2;
g.drawLine (x, y, x, y);
for (int t = 0; t < el; t++)//if I multiply el a line will be longer
{
err -= es;
if (err < 0) {
err += el;
x += incx;
y += incy;
} else {
x += pdx;
y += pdy;
}
g.drawLine (x, y, x, y);
}
}