Skip to main content
GameDev.net gamedev.net
🔒 Locked

silhouette from an image

Started by broady Jul 24, 2008 at 4:21 AM 12 replies 1.4k views
Original Post
broady
broady
Hello guys, i have to solve this problem: given a raster image (without holes) retrieve a collection of vertices approximating the contour of the image. Think about the image in this way: a rectangular box whit a shape in the middle. The pixels wich dont stay inside the shape are trasparent. Pixel data inside the shape have rgb values of course. The goal is to build a "struct" containing the vertices of the shape. Reading here and there i found the marching squares algorithm. Do you think i can code it or should i find some resource? If you think there is a better/simpler algorithm speak please :D Thanks bro
Portmanteau
Portmanteau
Well if you know that every pixel outside of the shape will be transparent you can do something simple like, if the pixel is not transparent and their is a transparent pixel touching it, then add it to the list of edge pixels.
broady
broady
This night i'lltry to do that.

Thanks mate
broady
broady
It's not a good idea i think. In that way u can't control how many vertices u are going to take. Basically in that way u have a vertex for every pixel of the shape contour.

I'd like to have an implementation where i specify the number of vertex i want and an eventually function returns back vertex data.

Any tip?
OrangyTang
OrangyTang
You could convert the silluette into a distance map, and then run marching squares over the distance map to generate a polygon mesh from it. This would me nice as you can just change the resolution of your marching squares grid to adjust how many vertices the final poly has and how much you trade off speed for accuracy.
broady
broady
Quote:
Original post by OrangyTang
You could convert the silluette into a distance map, and then run marching squares over the distance map to generate a polygon mesh from it. This would me nice as you can just change the resolution of your marching squares grid to adjust how many vertices the final poly has and how much you trade off speed for accuracy.


Thanks for the tip but it's too hard for me. I am at the start.
Basiror
Basiror
You can just use the marching squares if transparency information is available, this will result in a unsorted list of edges.
Then find the edges' neighbours and finally merge edges pointing into the same direction.

You can merge as many edges as you need until you reach your desired vertex count.
http://www.8ung.at/basiror/theironcross.html
broady
broady
Quote:
Original post by OrangyTang
It's a hard problem. If you're looking for some magic process which doesn't require effort on your part you're out of luck.


OrangyTang, i am not looking for magic. I am just looking for an other way to accomplish that stuff. I am moving back to the first approach now.

Thanks guys
Bro
broady
broady
Hello guys, i have soptted one of my many problems. I am doing an example to show it.
suppose i have a 256*256 pixel image. In this image, starting at x=y=100px there is a square of some size. As always the image is transparent outside of the square and opaque inside the square. My pixel data is stored in a dinamically allocated GLubyte 1d array of 256*256*4 (4 since it's rgba). Given this array, for the i-th pixel the alpha value is given by this index [i+3+(i*3)]. Once loaded the image, i went to check this alpha values and they are not all 0 or 255.

The transparency is shaded. For example i'd like to have a value of 0 for the (100,99) pixel ans 255 for the (100,100) where the image starts. Instead i have 0 for the (100,97), 255 for the (100,100) and alpha values between 0 and 255 for the the pixel in the middle of em.

Clearly with this kind of image i can't work properly. Is there a way to create a "perfect" image with ps or gimp?

thanks guys
Bro
superpig
superpig
Well, the obvious suggestion would be to use a threshold value - to treat any pixel with an alpha > 127 as 'opaque', and any pixel with alpha <= 127 as transparent.
Richard "Superpig" Fine - saving pigs from untimely fates - Microsoft DirectX MVP 2006/2007/2008/2009
"Shaders are not meant to do everything. Of course you can try to use it for everything, but it's like playing football using cabbage." - MickeyMouse
broady
broady
hey superpig,

just now i am working on it. I will need your help soon i think.

Have a nice day
Bro
broady
broady
Hello.

I have almost solved my problem. Or better it's solved, since i have vertex data (correctly ordered) of the silhouette stored in a STL vector.

The problem now is an other. I have a class image. Here the interface:

#ifndef IMAGE_H#define IMAGE_H#include <string>#include <GL/gl.h>class image{    public:        image();        ~image();        void CreateImage(const std::string);        int  GetWidth() const;        int  GetHeight() const;        GLubyte* GetData() const;        void ReverseData();        void ReverseRows();        void Draw();        void keyInput(unsigned char key, int x, int y);        void MouseInput(int button, int state, int x, int y);    private:        GLubyte* img;        GLint w,h;};#endif // IMAGE_H


img points to the first pixel data. Depending on the format uploaded img can point to the first or the last pixel datas(i used dataS since when i say pixel i mean r,g,b and a channel values for that pixel).

My function prototype to get the contour is
void GetContour(const image ℑ)  


I coded this function such that it works properly only if the image object has its GLubyte *img pointing to the first pixel.

All this stuff to say i need a method to switch the rows (we can say it has to rotate the image by 180 degrees). This method is called ReverseRows() and here it is:

void image::ReverseRows(){    int i = 0;    int index;    GLubyte *bottom = new GLubyte[w*4];    GLubyte *up = new GLubyte[w*4];    while(i < (h/2)-1) //till the middle height    {        index = 0;        for (int k = i*w*4; k < i*w*4 + w*4; k++ )        {            bottom[index] = img[k];            index += 1;        }        index = 0;        for (int k = (h-i)*w*4; k < (h-i)*w*4 + w*4; k++)        {            up[index] = img[k];            index += 1;        }        index = 0;        for (int k = i*w*4; k < i*w*4 + w*4; k++ )        {            img[k] = up[index];            index += 1;        }        index = 0;        for (int k = (h-i)*w*4; k < (h-i)*w*4 + w*4; k++)        {            img[k] = bottom[index];            index += 1;        }        i += 1;    }    delete[] bottom;    delete[] up;}


It's pretty easy. This method copies the ith row in the bottom array and the (h-i)th row in the up array. After this the up array is copied in the the ith row and the bottom array in the (h-i)th row.

The problem is that this method sometime makes me crash. On the same image the first time it works, the second time i go to "run build" and my program crash. Might be it's a memory lack? debugging nothing comes out. Have u some idea on the reason?

Thanks
Bro
broady
broady
Was an index problem: the index for the up row is h-i-1 not h-1.

Solved i'd say :D

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.