First, let me explain what an "edge" is.
An edge is the virtual line between two contiguous pixels.
+---+---+
| A | B | // The middle line is the edge between pixel A and pixel B
+---+---+
Edges have a starting point and an end point, and so are oriented upward, downward, "left going" or "right going".
In order to handle polygons crossing image boundaries, we gonna add a 1 pixel white border around our image.
Here is the algorithm:
For each row of our image {
For each pixel of the row except the last one {
If current pixel is white and next pixel is black {
Create a new upward edge between the two pixels and add it to
the global edge list.
}
Else if current pixel is black and next pixel is white {
Create a new downward edge between the two pixels and add it to
the global edge list.
}
}
}
For each column of our image {
For each pixel of the column except the last one {
If current pixel is white and next pixel is black {
Create a new "left going" edge between the two pixels and add it to
the global edge list.
}
Else if current pixel is black and next pixel is white {
Create a new "right going" edge between the two pixels and add it to
the global edge list.
}
}
}
For each edge of the global edge list {
Find the edge starting from the point where your current edge ends
(for now on, we gonna call it next_edge).
Connect the two edges to form a linked list
(edge->next = next_edge; next_edge->previous = edge;)
}
While there is edges in the global edge list {
Create a new polygon and add it to the polygon list
Take the first edge of the list (for now on, we gonna call it first_edge)
For each edge in the linked list starting at first_edge {
Remove edge from global edge list
Add edge to polygon's edge list
}
}
Done, you have a list of polygons.
EDIT
Of course, you have to optimize it a little before using it, but it's really easy : consecutive edges with the same orientation can be replaced with a single, longer edge.