java - Drawing multiple diagonal lines on a BufferedImage - java

im trying to draw multiple diagonal lines across the whole image (leaving a space between them) i've used this code to draw horizontal and vertical lines:
for (int z = 1; z < partToCrop; z++) {
Shape hLines = new Line2D.Float(0, cropInPartWidth*z, chunkWidth, cropInPartWidth*z);
Shape vLines = new Line2D.Float(cropInPartHeight*z, 0, cropInPartHeight*z, chunkHeight);
gr.draw(hLines); //gr is a BufferedImage
gr.draw(vLines);
}
where
int partToCrop = 5;
float cropInPartWidth = imgWidth / partToCrop;
float cropInPartHeight = imgHeight / partToCrop;
and works good. Now i need to draw multiple diagonal lines (i.e 4 diagonal lines) with 45° and -45° degrees of inclination across the whole image, hope you will help me.
Thanks.

Shape firstLine = new Line2D.Float(0, imgHeight, imgWidth, 0); // this line is from bottom left to top right
Shape secondLine = new Line2D.Float(0, 0, imgWidth, imgHeight); // this line is from top left to bot right

Actually this seems easier to me.
Assuming imgDim = imgHeight = imgWidth:
int spacing = 2;
for (int z = 1; z < imgDim; z = z + spacing)
{
Shape dLines = new Line2D.Float(0, z, z, 0);
gr.draw(dLines);
}

Related

Adding thickness to a 2D sprite when turning

In my game, my entities turn like a piece of paper, as shown here at half-speed: https://imgur.com/a/u2suen6
I want to give the entities a bit of thickness when they turn, making them more cardboard-thin than paper-thin.
I thought about using a Pixmap to detect and extend the edge pixels and give the image some Three-Dimensionality. I also considered duplicating the image along the x-axis to give the same effect. Of the two ideas, the Pixmap holds out the most promise in my mind. However, I'm wondering if there's a better solution.
I'm using a GLSL shader to give the entities highlights and shadows while turning, as you saw in the gif. I think that with the right knowledge, I could achieve what I'm going for using the same shader program.
My shader looks like this:
#ifdef GL_ES
precision mediump float;
#endif
varying vec4 v_color;
varying vec2 v_texCoords;
uniform sampler2D u_texture;
uniform vec2 u_resolution;
uniform vec3 color;
void main()
{
vec4 col = vec4(color, 0.0);
gl_FragColor = texture2D(u_texture, v_texCoords) * v_color + col;
}
I think that one might be able to make calculations based on the uniform vec3 color that I pass it (with its values ranging from 0, 0, 0 to 1, 1, 1. 1's being highlight and 0's being shadow). Unfortunately, I don't have the understanding of shaders to do so.
If any of you have the know-how, could you steer me in the right direction? Or let me know if I should just stick to the Pixmap idea.
Edit: I'm trying to stay away from using a 3D model because I'm 6.4k lines of code deep using a 2d Orthographic Camera.
Edit 2: I figured that the reflection shader wouldn't look good if I tried making the sprite look 3D. I scrapped the shader, went with the Pixmap idea, and plan on implementing shadows and reflections to the pixmap without any shader. Though it looks good so far without reflections.
I ended up going with my pixmap idea. I want to share my code so that others can know how I got 2D thickness to work.
Please note that in the following code:
dir is a floating point value in the range -1.0 to 1.0. It tells the program where the sprite is in its turn. -1 means facing fully left. 1 meaning right. 0 means that it's 'facing' the camera.
right is a boolean that tells the program which direction the entity is turning. true means that the entity is turning from left to right. false means from right to left.
The Code:
private Texture getTurningImage(TextureRegion input, int thickness)
{
if(Math.abs(dir) < 0.1)
dir = (right ? 1 : -1) * 0.1f;
Texture texture = input.getTexture();
if (!texture.getTextureData().isPrepared())
{
texture.getTextureData().prepare();
}
Pixmap pixmap = texture.getTextureData().consumePixmap();
Pixmap p = new Pixmap(64, 64, Pixmap.Format.RGBA8888);
p.setFilter(Pixmap.Filter.NearestNeighbour);
Pixmap texCopy = new Pixmap(input.getRegionWidth(), input.getRegionHeight(), Pixmap.Format.RGBA8888);
// getting a texture out of the input region. I can't use input.getTexture()
// because it's an animated sprite sheet
for (int x = 0; x < input.getRegionWidth(); x++)
{
for (int y = 0; y < input.getRegionHeight(); y++)
{
int colorInt = pixmap.getPixel(input.getRegionX() + x, input.getRegionY() + y);
Color c = new Color(colorInt);
colorInt = Color.rgba8888(c);
texCopy.drawPixel(x, y, colorInt);
}
}
pixmap.dispose();
float offsetVal = Math.round(thickness/2.0) * (float) -Math.cos((dir * Math.PI)/2);
if(offsetVal > -1.23/Math.pow(10, 16))
{
offsetVal = 0;
}
// generate the pixel colors we'll use for the side view
Pixmap sideProfile = new Pixmap(1, 64, Pixmap.Format.RGBA8888);
for (int y = 0; y < texCopy.getHeight(); y++)
{
for (int x = 0; x < texCopy.getWidth(); x++)
{
int colorInt = texCopy.getPixel(x, y);
if(new Color(colorInt).a != 0 && new Color(texCopy.getPixel(x + 1, y)).a == 0)
{
Color c = new Color(colorInt);
c.mul(.8f); // darken the color
c.a = 1;
colorInt = Color.rgba8888(c);
sideProfile.drawPixel(0, y, colorInt);
continue;
}
}
}
// drawing the bottom layer
p.drawPixmap(texCopy, 0, 0, 64, 64, (int) (Math.round(-offsetVal) + (64 - texCopy.getWidth()*Math.abs(dir))/2), 0, (int)(64*Math.abs(dir)), 64);
// drawing the middle (connecting) layer
// based on the edge pixels of the bottom layer, then translated to be in the middle
for (int y = 0; y < p.getHeight(); y++)
{
int colorInt = sideProfile.getPixel(0, y);
for (int x = 0; x < p.getWidth(); x++)
{
if(new Color(p.getPixel(x, y)).a != 0 && new Color(p.getPixel(x + 1, y)).a == 0)
{
for(int i = 0; i <= 2 * Math.round(Math.abs(offsetVal)); i++) // the for the length between the top and bottom
{
p.drawPixel(x + i - 2 * (int)Math.round(Math.abs(offsetVal)), y, colorInt);
}
}
}
}
// drawing the top layer
p.drawPixmap(texCopy, 0, 0, 64, 64, (int) (Math.round(offsetVal) + (64 - texCopy.getWidth()*Math.abs(dir))/2), 0, (int)(64*Math.abs(dir)), 64);
// flip if facing left
if(dir < 0)
{
p = flipPixmap(p);
}
return new Texture(p);
}
My flipPixmap method looks like this (stolen from stack overflow):
private Pixmap flipPixmap(Pixmap src)
{
final int width = src.getWidth();
final int height = src.getHeight();
Pixmap flipped = new Pixmap(width, height, src.getFormat());
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
flipped.drawPixel(x, y, src.getPixel(width - x - 1, y));
}
}
return flipped;
}
Here's the result :D https://imgur.com/a/wGeHg9D

How to calculate intersection points based on corners and number of cells

I am trying to find all intersection points (their x and y values) based on 4 corner points that I always have and number of cells (in my case 9, so 9x9 matrix, sudoku puzzle).
My 4 corners are marked with green cross, and taged P1 to P4.
I tried to calculate it, and only managed to do it precisely for the first row.
double xDis = p2.x - p1.x;
double yDis = p2.y - p1.y;
double xW = xDis / 9;
double yH = yDis / 9;
for (int i = 0; i < 10; i++) {
Point point = new Point(p1.x + (i * xW), p1.y + (i * yH));
}
This code would work exactly as I expected it but only for the first row.
What am I missing here ? Is there some kind of algoritmh that already does this ? Any hints are welcome.
Note that I am using android with OpenCV library.
As written above in the comments, I ended up warping the image and then cutting it. It looks something like this
if (points != null) {
Point p1 = points[0];
Point p2 = points[1];
Point p3 = points[2];
Point p4 = points[3];
MatOfPoint2f src = new MatOfPoint2f(
p1,
p2,
p3,
p4);
drawMarker(frame, p1, new Scalar(255,0,0), 0, 20, 1);
drawMarker(frame, p2, new Scalar(255,0,0), 0, 20, 1);
drawMarker(frame, p3, new Scalar(255,0,0), 0, 20, 1);
drawMarker(frame, p4, new Scalar(255,0,0), 0, 20, 1);
double x = p2.x - p1.x;
double y = p3.y - p2.y;
MatOfPoint2f dst = new MatOfPoint2f(
new Point(0, 0),
new Point(x,0),
new Point(0,y),
new Point(x,y)
);
Mat warpMat = Imgproc.getPerspectiveTransform(src, dst);
//This is you new image as Mat
Mat destImage = new Mat();
Imgproc.warpPerspective(bw2, destImage, warpMat, new Size(x, y));
List<Mat> cells = getCells(destImage, destImage.width() / 9, destImage.height / 9);
}
private List<Mat> getCells(Mat m, int width, int height) {
Size cellSize = new Size(width, height);
List<Mat> cells = new ArrayList<>();
for (int row = 0; row < 9; row++) {
for (int col = 0; col < 9; col++) {
Rect rect = new Rect(new Point(col * width, row * height), cellSize);
Mat digit = new Mat(m, rect).clone();
cells.add(digit);
}
}
return cells;
}
You only do your calculation once, on the first row.
Put your for loop inside of another for loop and run it 10 times, and you should be good (Adding in whatever x,y translation happens as you traverse downwards in y).
As for if there is any automated way to do this, yes. I could suggest using Harris Corner Detection. I suspect using the right thresholds could get you only the thicker line corners. You could also try doing line detection and looking for intersections.
Also, this article may be helpful if you find you aren't finding good lines/corners. You can correct the shading from the lighting and get a good clean image to analyze.

Wrong center of screen coordinates

I'm coding an Android game and I'm trying to put the character in the middle of the screen (X axis).
In order to get the middle of the screen I get the screen width withe the following command:
int phoneWidth = Resources.getSystem().getDisplayMetrics().widthPixels;
Then I divide phoneWidth by two and hoped that the character would appear in the middle of the screen but it appears slightly to the right.
This is the code that I use:
public void drawCharacter() {
charImg = new Texture("pika.PNG");
charSprite = new Sprite(charImg);
float ahaha = Gdx.graphics.getWidth();
charPosX = (float)phoneWidth/ 2;
}
#Override
public void render() {
ch.stop();
double elapsedSeconds = ch.getSeconds();
checkLevel();
handleObstacles();
scrollTimer = scrollTimer + Gdx.graphics.getDeltaTime() / 2;
if (scrollTimer > 1.0f)
scrollTimer = 0.0f;
sprite.setV(scrollTimer);
sprite.setV2(scrollTimer + 2);
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
charSprite.setPosition(charPosX, charPosY);
for (int i = 0; i < obstacles.size(); i++) {
obstacleSprites.get(i).setPosition(obstacles.get(i).getPosX(), obstacles.get(i).getPosY());
}
spriteBatch.begin();
sprite.draw(spriteBatch);
charSprite.draw(spriteBatch);
for (int i = 0; i < obstacleSprites.size(); i++) {
obstacleSprites.get(i).draw(spriteBatch);
}
spriteBatch.end();
moveCharacter();
moveObstacle();
}
Does anyone know where this error come from?
The left-hand edge of your sprite will be in the middle of the screen.
Subtract half the sprite width from half the screen width to draw the sprite centered horizontally.

Trouble flipping images in Java

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.

Detecting Hough circles android

I am trying to detect circles using android. I succeeded to implement the detect lines algorithm but nothing gets displayed when trying the draw hough circles algoritm.
Here is my code:
Mat thresholdImage = new Mat(getFrameHeight() + getFrameHeight() / 2, getFrameWidth(), CvType.CV_8UC1);
mYuv.put(0, 0, data);
Imgproc.cvtColor(mYuv, destination, Imgproc.COLOR_YUV420sp2RGB, 4);
Imgproc.cvtColor(destination, thresholdImage, Imgproc.COLOR_RGB2GRAY, 4);
Imgproc.GaussianBlur(thresholdImage, thresholdImage, new Size(9, 9), 2, 2 );
Mat circles = new Mat();
Imgproc.HoughCircles(thresholdImage, circles, Imgproc.CV_HOUGH_GRADIENT, 1d, (double)thresholdImage.height()/70, 200d, 100d);
Log.w("circles", circles.cols()+"");
for (int x = 0; x < circles.cols(); x++)
{
double vCircle[]=circles.get(0,x);
Point center=new Point(Math.round(vCircle[0]), Math.round(vCircle[1]));
int radius = (int)Math.round(vCircle[2]);
// draw the circle center
Core.circle(destination, center, 3,new Scalar(0,255,0), -1, 8, 0 );
// draw the circle outline
Core.circle( destination, center, radius, new Scalar(0,0,255), 3, 8, 0 );
}
You may have got this sorted by now, but a few things. I'd check your circles mat actually has some results; sometimes vCircle seems to come back null; try one of the other versions of HoughCircles:
iCannyUpperThreshold = 100;
iMinRadius = 20;
iMaxRadius = 400;
iAccumulator = 300;
Imgproc.HoughCircles(thresholdImage, circles, Imgproc.CV_HOUGH_GRADIENT,
2.0, thresholdImage.rows() / 8, iCannyUpperThreshold, iAccumulator,
iMinRadius, iMaxRadius);
if (circles.cols() > 0)
for (int x = 0; x < circles.cols(); x++)
{
double vCircle[] = circles.get(0,x);
if (vCircle == null)
break;
Point pt = new Point(Math.round(vCircle[0]), Math.round(vCircle[1]));
int radius = (int)Math.round(vCircle[2]);
// draw the found circle
Core.circle(destination, pt, radius, new Scalar(0,255,0), iLineThickness);
Core.circle(destination, pt, 3, new Scalar(0,0,255), iLineThickness);
}
(I swapped your code into mine, renamed some stuff and swapped it back, I think I've got it back so it works...)
B.

Categories