Opencv resizing rect whilst maintaining centroid - java

I am having a bit of an issue, I have a rectangle from contour detection but I want to re-size the rectangle whilst maintaining the centroid I noticed when I resize it, its obtaining a new centroid, this is because I want it to be at the center of my object not but when re-sized its moving to the sizes here is an image before resize, my centroid is marked by the red and blue markers
Before resize:
After resize:
Here is how I am resizing:
private static Rect rotateRect(Rect rect, int heightPercentage, int widthPercetange)
{
int originalX = 0;
int originalY = 0;
originalX = rect.x;
originalY = rect.y;
rect.height = resizeObject(rect.height, heightPercentage);
rect.width = resizeObject(rect.width, widthPercetange);
rect.x = originalX;
rect.y = originalY;
return rect;
}
private static int resizeObject(int resize, int percentage)
{
return (int)(resize *(percentage/100.0f));
}

You simply need to add to x and y coordinates half the amount you remove from width and height.
private static Rect rotateRect(Rect rect, int heightPercentage, int widthPercetange)
{
int rwidth = rect.width;
int rheight = rect.height;
rect.width = Math.round((rect.width * widthPercetange) / 100.0f);
rect.height = Math.round((rect.height * heightPercentage) / 100.0f);
rect.x += (rwidth - rect.width) / 2;
rect.y += (rheight - rect.height) / 2;
return rect;
}

Related

loadpixels from jpg / png incorrect processing

I am trying to draw a grid over an image using the underlaying colours of the image to fill the circles. But some pixels are not getting the correct colour.
In this case the circles are drawn white but they should not be drawn white...
See my code below:
import processing.pdf.*;
PImage img;
color background = color(255);
void setup() {
size(1038, 525);
ellipseMode(CORNER);
noStroke();
//img = loadImage("noise2.jpg");
//img = loadImage("air.png");
img = loadImage("accidents.png");
image(img, 0, 0, width, height);
visualGrid(20, 0.4, false);
}
//void draw() {
// fill(noise.get(mouseX, mouseY));
// rect(width - 100, height - 100, 100, 100);
//}
void visualGrid(int circleSize, float fillSmoothing, boolean debug) {
float halfCircle = circleSize / 2.0;
int amountX = floor(width / circleSize);
int amountY = floor(height / circleSize);
amountY += floor(amountY * 0.1);
float offsetX = (width - (amountX * circleSize + halfCircle)) / 2 + halfCircle;
float offsetY = (height - amountY * circleSize + amountY * circleSize * 0.1) / 2;
for (int x = 0; x < amountX; x++) {
for (int y = 0; y < amountY; y++) {
float styledOffsetX = (y % 2 == 0) ? offsetX - halfCircle : offsetX;
float xpos = x * circleSize + styledOffsetX;
float ypos = circleSize * 0.9 * y + offsetY;
int sectionSize = round(circleSize * fillSmoothing);
float sectionOffset = (circleSize - sectionSize) / 2;
color c = getAvgImgColor(img.get(round(xpos + sectionOffset), round(ypos + sectionOffset), sectionSize, sectionSize));
//fill(noise.get(round(xpos), round(ypos)));
if(debug) {
stroke(255, 0, 255);
strokeWeight(1);
}
fill(c);
ellipse(xpos, ypos, circleSize, circleSize);
if(debug) {
noStroke();
fill(255, 0, 255);
rect(round(xpos + sectionOffset), round(ypos + sectionOffset), sectionSize, sectionSize);
}
}
}
}
color getAvgImgColor(PImage section) {
section.loadPixels();
int avgR = 0, avgG = 0, avgB = 0;
int totalPixels = section.pixels.length;
for (int i = 0; i < totalPixels; i++) {
color pixel = section.pixels[i];
//if(pixel == background) continue;
avgR += red(pixel);
avgG += green(pixel);
avgB += blue(pixel);
}
return color(
round(avgR / totalPixels),
round(avgG / totalPixels),
round(avgB / totalPixels)
);
}
This is what i get when drawing my grid on the image in question:
As you can see in the circled area not all circles should be filled with white... This happens in more places than just the circled are just compare this image with the one below.
I will upload the original image below, so you can use it to debug.
There's a mismatch between the dimensions of your sketch (1038 x 525) and the image you're sampling (2076 x 1048) which might explain the misalignment.
If size(2076, 1048) isn't an option try resizing the image once it's loaded in setup():
...
img = loadImage("accidents.png");
img.resize(width, height);
...

Libgdx - Parallax background set horizontally, can't implement scrolling up and down

I found a tutorial online to create a horizontally scrolling parallax background with this custom class:
public class ParallaxBackground extends Actor {
private float scroll;
private Array<Texture> layers;
private final int LAYER_SPEED_DIFFERENCE = 2;
float x, y, width, height, scaleX, scaleY;
float originX, originY, rotation;
float srcX, srcY;
boolean flipX, flipY;
private float speed;
public ParallaxBackground(Array<Texture> textures, HeroKnight player) {
layers = textures;
for(int i = 0; i <textures.size;i++){
layers.get(i).setWrap(Texture.TextureWrap.MirroredRepeat, Texture.TextureWrap.MirroredRepeat);
}
scroll = 0;
speed = 0;
x = y = originX = originY = rotation = 0;
srcY = 0;
width = Gdx.graphics.getWidth();
height = Gdx.graphics.getHeight();
scaleX = scaleY = 1;
flipX = flipY = false;
}
public void setSpeed(float newSpeed){
this.speed = newSpeed;
}
public void update(float deltaTime) {
}
#Override
public void draw(Batch batch, float parentAlpha) {
batch.setColor(getColor().r, getColor().g, getColor().b, getColor().a * parentAlpha);
scroll+=speed;
srcX = scroll;
batch.draw(layers.get(0), x, y, originX, originY, width, height, scaleX, scaleY, rotation, (int)srcX, (int) srcY, layers.get(0).getWidth(), layers.get(0).getHeight(), flipX, flipY);
for(int i = 1;i<layers.size;i++) {
srcX = scroll + i*this.LAYER_SPEED_DIFFERENCE *scroll;
batch.draw(layers.get(i), x, y, originX, originY, width, height,scaleX,scaleY,rotation,(int)srcX,(int)srcY,layers.get(i).getWidth(),layers.get(i).getHeight(),flipX,flipY);
}
}
.
backgroundViewport = new ScreenViewport();
stage = new Stage(backgroundViewport);
Array<Texture> textures = new Array<Texture>();
for(int i = 1; i <= 5;i++){
textures.add(new Texture(Gdx.files.internal("images/"+ i+".png")));
textures.get(textures.size-1).setWrap(Texture.TextureWrap.MirroredRepeat, Texture.TextureWrap.MirroredRepeat);
}
parallaxBackground = new ParallaxBackground(textures, player);
parallaxBackground.setSize(Gdx.graphics.getWidth(),Gdx.graphics.getHeight());
parallaxBackground.setSpeed(0);
stage.addActor(parallaxBackground);
In the render method:
stage.act();
stage.draw();
Eveything works well when you are moving left to right. However, on my background image there is water down, so logically I want the screen to show it when the player is on the lower platforms, and make it scroll higher so that the water disappears when you go up.
So the question is: how do I make the blue part visible when the player is lower, and scroll it to the red part when you go higher?

How to place the ball position properly in Wheel game?

I have a static number of slots for the number in the wheel game. Start from number 00 to number 1 (clockwise). The position count is 0 to 37 in my Collection array. Currently, I successful place the ball position in the middle of the number with 1 degree. But I unable to calculate a correct value for each of the position when I tried to pass in the number position.
I already tried messing with the calculation, it either the ball sit in the middle between the number or out of range!
public class WheelDisplay extends JPanel implements ConstantVariable {
private Image image;
private ImageObserver imageObserver;
private float degrees = 1;
private int post = 0;
public WheelDisplay() {
ImageIcon icon = new ImageIcon(IMAGE_LOCATION);
image = icon.getImage();
imageObserver = icon.getImageObserver();
}
/** Credit to stackoverflow forum : https://stackoverflow.com/questions/25923480/simple-circle-rotation-simulate-motion **/
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int circleDiameter = Math.min(getWidth(), getHeight());
double circleRadius = circleDiameter / 2;
int offSetX = (getWidth() - circleDiameter) / 2;
int offSetY = (getHeight() - circleDiameter) / 2;
g2d.drawImage(image, offSetX, offSetY, circleDiameter, circleDiameter, imageObserver);
g2d.setColor(Color.BLUE);
int ballDiameter = (int) (circleDiameter * 0.02);
int ballRadius = ballDiameter / 2;
Point p = getPointOnCircle(this.degrees, circleRadius * 0.9, circleRadius);
int valueX = offSetX + p.x - ballRadius;
int valueY = offSetY + p.y - ballRadius;
g2d.fillOval(valueX, valueY, ballDiameter, ballDiameter);
g2d.dispose();
}
private Point getPointOnCircle(float degress, double circleRadius, double innerCircleRadius) {
//The calculation that allow ball sit in the middle of each number when spin
double rads = ((Math.PI * degress) / 38);
// Calculate the outter point of the line
int xCordinate = Math.round((float) (innerCircleRadius + Math.cos(rads) * circleRadius));
int yCordinate = Math.round((float) (innerCircleRadius + Math.sin(rads) * circleRadius));
return new Point(xCordinate, yCordinate);
}
public void setDegree(int x) {
this.degrees += 2;
this.post = x; // The number of position coming from Collection (0-37)
}
}
The ball supposes to sit in the middle of each 38 numbers in the wheel image.
Hope that someone can point out which part I'm doing wrong!
The image that I'm using is this.

Interpolate between pixels on an image

I'm trying to implement a way to sample a texture in Java. I want this to work the same way it would by using GLSL's "texture" function. I want the neighboring pixels to be taken into account when the color is calcuated.
For example, say I use a float to get the image color at a certain pixel, and the number falls between two pixels. How can I calculate a mix of the neighboring pixels? Here's an image showing my goal.
Is there an easy way to do this using java's BufferedImage class?
Here's the code I have so far, it only works for the x position at the moment.
public static final java.awt.Color getColor(final BufferedImage image, final float x, final int y) {
final float imageX = x * image.getWidth();
final float decimal = imageX % 1f;
final java.awt.Color left = new java.awt.Color(image.getRGB(Maths.clamp((int) imageX - 1, 0, image.getWidth() - 1), y));
final java.awt.Color center = new java.awt.Color(image.getRGB(Maths.clamp((int) imageX, 0, image.getWidth() - 1), y));
final java.awt.Color right = new java.awt.Color(image.getRGB(Maths.clamp((int) imageX + 1, 0, image.getWidth() - 1), y));
if (decimal == 0.5f) return center;
if (decimal < 0.5f) {
final float distanceFromCenter = 0.5f - decimal;
final float distanceFromLeft = decimal + 0.5f;
final Vector3f leftColor = new Vector3f(left.getRed() / 255f, left.getGreen() / 255f, left.getBlue() / 255f);
final Vector3f centerColor = new Vector3f(center.getRed() / 255f, center.getGreen() / 255f, center.getBlue() / 255f);
leftColor.scale(1f - distanceFromLeft);
centerColor.scale(1f - distanceFromCenter);
final Vector3f color = Vector3f.add(leftColor, centerColor, null);
return new java.awt.Color(color.getX(), color.getY(), color.getZ());
} else {
final float distanceFromCenter = decimal - 0.5f;
final float distanceFromRight = 1f - decimal + 0.5f;
final Vector3f rightColor = new Vector3f(right.getRed() / 255f, right.getGreen() / 255f, right.getBlue() / 255f);
final Vector3f centerColor = new Vector3f(center.getRed() / 255f, center.getGreen() / 255f, center.getBlue() / 255f);
rightColor.scale(1f - distanceFromRight);
centerColor.scale(1f - distanceFromCenter);
final Vector3f color = Vector3f.add(rightColor, centerColor, null);
return new java.awt.Color(color.getX(), color.getY(), color.getZ());
}
}
hope this code help, if you use this appropriately. This function extract pixels from buffered image and we can replace it what ever we want:
private BufferedImage changeColor(BufferedImage image, int srcColor, int replaceColor)
{
BufferedImage destImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g = destImage.createGraphics();
g.drawImage(image, null, 0, 0);
g.dispose();
for (int width = 0; width < image.getWidth(); width++)
{
for (int height = 0; height < image.getHeight(); height++)
{
if (destImage.getRGB(width, height) == srcColor)
{
destImage.setRGB(width, height, replaceColor);
}
}
}
return destImage;
}

How to smoothly zoom a canvas?

How could I smoothly create a zoom animation for a canvas?
GWT provides a onMouseWheel(MouseWheelEvent evt) method and a evt.getDeltaY() to get the amount of scroll wheel.
Problem here is, that every wheel movement executes this method, and if I call a canvas redraw in the method itself, things get very laggy.
So I thought of somehow making an animation for the zooming. But how?
I thought about creating a Timer, but have no real idea, as there is only the mousewheelevent as starting point, but no end point that the user finished zooming with the wheel...
Here is my scalable image class that I use to zoom into images, it is very quick and responsive. I found an example somewhere and made some minor modifications to make it more responsive. I don't remember the original source or I would give them credit here.
public class ScalableImage extends Composite implements MouseWheelHandler, MouseDownHandler, MouseMoveHandler, MouseUpHandler {
Canvas canvas = Canvas.createIfSupported();
Context2d context = canvas.getContext2d();
Canvas backCanvas = Canvas.createIfSupported();
Context2d backContext = backCanvas.getContext2d();
int width;
int height;
Image image;
ImageElement imageElement;
double zoom = 1;
double totalZoom = 1;
double offsetX = 0;
double offsetY = 0;
boolean mouseDown = false;
double mouseDownXPos = 0;
double mouseDownYPos = 0;
public ScalableImage(Image image) {
initWidget(canvas);
//width = Window.getClientWidth() - 50;
width = image.getWidth() + 200;
height = image.getHeight() + 200;
//canvas.setWidth(width + "px");
//canvas.setHeight(height + "px");
canvas.setCoordinateSpaceWidth(width);
canvas.setCoordinateSpaceHeight(height);
//backCanvas.setWidth(width + "px");
//backCanvas.setHeight(height + "px");
backCanvas.setCoordinateSpaceWidth(width);
backCanvas.setCoordinateSpaceHeight(height);
canvas.addMouseWheelHandler(this);
canvas.addMouseMoveHandler(this);
canvas.addMouseDownHandler(this);
canvas.addMouseUpHandler(this);
this.image = image;
this.imageElement = (ImageElement) image.getElement().cast();
mainDraw();
}
public void onMouseWheel(MouseWheelEvent event) {
int move = event.getDeltaY();
double xPos = (event.getRelativeX(canvas.getElement()));
double yPos = (event.getRelativeY(canvas.getElement()));
if (move < 0) {
zoom = 1.1;
} else {
zoom = 1 / 1.1;
}
double newX = (xPos - offsetX) / totalZoom;
double newY = (yPos - offsetY) / totalZoom;
double xPosition = (-newX * zoom) + newX;
double yPosition = (-newY * zoom) + newY;
backContext.clearRect(0, 0, width, height);
backContext.translate(xPosition, yPosition);
backContext.scale(zoom, zoom);
mainDraw();
offsetX += (xPosition * totalZoom);
offsetY += (yPosition * totalZoom);
totalZoom = totalZoom * zoom;
buffer(backContext, context);
}
public void onMouseDown(MouseDownEvent event) {
this.mouseDown = true;
mouseDownXPos = event.getRelativeX(image.getElement());
mouseDownYPos = event.getRelativeY(image.getElement());
}
public void onMouseMove(MouseMoveEvent event) {
if (mouseDown) {
backContext.setFillStyle("white");
backContext.fillRect(-5, -5, width + 5, height + 5);
backContext.setFillStyle("black");
double xPos = event.getRelativeX(image.getElement());
double yPos = event.getRelativeY(image.getElement());
backContext.translate((xPos - mouseDownXPos) / totalZoom, (yPos - mouseDownYPos) / totalZoom);
offsetX += (xPos - mouseDownXPos);
offsetY += (yPos - mouseDownYPos);
mainDraw();
mouseDownXPos = xPos;
mouseDownYPos = yPos;
}
}
public void onMouseUp(MouseUpEvent event) {
this.mouseDown = false;
}
public void mainDraw() {
backContext.drawImage(imageElement, 100, 100);
buffer(backContext, context);
}
public void buffer(Context2d back, Context2d front) {
front.beginPath();
front.clearRect(0, 0, width, height);
front.drawImage(back.getCanvas(), 0, 0);
}
}

Categories

Resources