5

I have my image with a transparent background. I want to find the edges of the image and form a polygon from the outline. There are multiple methods/ways I could do this. I want to do it in Java (its for my game, which is using JBox2d Polygons for collision detection).

I have had some thought about this and am thinking how this would work. I could try detecting all transparent pixels, then invert the selection and only select the pixels that have 1 adjacent transparent pixel. This is all very complicated and I would like some guidence.

liamzebedee
  • 12,096
  • 19
  • 65
  • 114
  • 1
    I can imagine that you would end up with some very complicated polygon shapes if you did it that way. I would suggest using simple shapes, which will also help performance and gameplay issues. – Tom Aug 15 '11 at 06:07
  • Sorry if this is a bit noobish. What are simple shapes? – liamzebedee Aug 15 '11 at 06:10
  • Circles and rectangles are the primitive shapes, but triangles or even a polygon with only a few sides are simple enough. In my applications/games, I use mainly boxes and Circles. I could tell you more but I'm at work. – Tom Aug 15 '11 at 06:17
  • E.g. implementations of [`Shape`](http://download.oracle.com/javase/6/docs/api/java/awt/Shape.html), the union of which form an [`Area`](http://download.oracle.com/javase/6/docs/api/java/awt/geom/Area.html). – trashgod Aug 15 '11 at 06:18

2 Answers2

3

There are two aspects to your question.

  1. Edge-detection. If your image has an alpha-channel, then you should be able to choose a suitable threshold and perform edge-detection to find the 'edges' of the transparent/opaque pixels. If it's just a GIF with a 'transparent' color, then it should a bit easier since you're effectively working with a black & white image.

  2. Vectorization. This is where it gets (really) tricky. The field of raster to vector conversion is fertile ground. I would look at how solutions such as Potrace (GPL) are implemented then maybe attempt to build my own off that.

However, for a game, personally, I wouldn't even try real-time edge/collision detection this way. Since I'm working with sprites, I would use bounding boxes and other raster-based techniques.

If I really want polygon-based edge/collision detection, then I would probably opt to manually trace edges beforehand and just store them along with each raster image, then perform computations on those (trade space for time). I presume that the images you work with aren't dynamically generated at run-time making pre-computation possible.

Community
  • 1
  • 1
Alistair A. Israel
  • 6,129
  • 1
  • 28
  • 40
  • Referring to the last paragraph- I am going to manually trace the edges beforehand. I'm wondering if this would be less or more efficient than having 'basic' shapes or it really wouldn't have any effect on performance? – liamzebedee Aug 15 '11 at 08:37
  • That would largely depend on the implementation and algorithm you use (or that JBox2D uses). In general, though, I would expect simpler shapes means faster collision detection (fewer edges to check). – Alistair A. Israel Aug 15 '11 at 08:58
1

This isn't really an answer to your question to make pixel-perfect collision, but I want to say that it is a bad idea to make the fixtures depending on the images.

  • Box2D doesn't support concave fixtures.
  • Box2D (the original version in C++, I don't know how this works in JBox2D) has a limit to 8 vertices per polygon.

Because of these two reason, you might think to create one square fixture per pixel, but that is going to be very expensive in processing time.

In my almost finished game, I'm defining my fixtures with a level editor.
Here is an excerpt of one of my levels (xml):

<body id="STONE" depth="13" angle="0.000000" type="static" x="7.939437" y="0.750494" tags=""  >
    <image id="stone_img" img="IMG_STONE" depth="0" x="-0.362081" y="0.526663" w="1.400000" h="1.600000" angle="0.000000" colorize="ffffffff"/>
    <fixture id="" density="1.000000" friction="0.300000" restitution="0.300000" sensor="false" shape="rect" x="-0.188671" y="0.806253" w="1.000000" h="2.200000" angle="0.545597" tags="" />
    <fixture id="" density="1.000000" friction="0.300000" restitution="0.300000" sensor="false" shape="rect" x="0.412080" y="-0.097607" w="1.000000" h="2.200000" angle="0.000000" tags="" />
</body>

I think this is the best way of working with Box2D.
Hopefully this inspires you :D

Martijn Courteaux
  • 63,780
  • 43
  • 187
  • 279