рдмрд╛рд╣рд░реА рдЖрдХреГрддрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЫрд╡рд┐рдпреЛрдВ рдХреЛ рддреБрд░рдВрдд рдЪрд┐рд╣реНрдирд┐рдд рдХрд░реЗрдВ

рд▓реЗрдЦ рдореЗрдВ рдореИрдВ рдЖрдкрдХреЛ рдмрддрд╛рдКрдВрдЧрд╛ рдХрд┐ рдмрд╛рдЗрдирд░реА рд░рд╛рд╕реНрдЯрд░ рдкрд░ рдХрдиреЗрдХреНрдЯ рдХреА рдЧрдИ рд╡рд╕реНрддреБрдУрдВ рдХреЛ рдХреИрд╕реЗ рдЬрд▓реНрджреА рд╕реЗ рд╕реВрдЪреАрдмрджреНрдз рдХрд┐рдпрд╛ рдЬрд╛рдПред рд╣рдордиреЗ рдЫрд╡рд┐рдпреЛрдВ рдФрд░ рдЧреНрд░рдВрдереЛрдВ рдХреА рдорд╛рдиреНрдпрддрд╛ рдХреЗ рд▓рд┐рдП рдЗрд╕ рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛; рдпрд╣ рдЙрдЪреНрдЪ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдЧрддрд┐ (3200x2400 рддрдХ рдХреА рддрд╕реНрд╡реАрд░реЛрдВ рдореЗрдВ, рдХреБрдЫ рдЖрд░рдХреНрд╖рдгреЛрдВ рдХреЗ рд╕рд╛рде, рдорд┐рд▓реАрд╕реЗрдХрдВрдб рдореЗрдВ рдмрд╛рд╣рд░ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ) рдФрд░ рд╕рдордЭрдиреЗ рдореЗрдВ рдЖрд╕рд╛рди (рдХреБрдЫ C ++ рдЬреНрдЮрд╛рди рдХреЗ рд╕рд╛рде) рдореЗрдВ рд╕рдорд╛рди рд╣реИред рдореИрдВ рдзреНрдпрд╛рди рджреЗрддрд╛ рд╣реВрдВ рдХрд┐ рдореВрд▓ рдЫрд╡рд┐ рдХреЛ рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рджреНрд╡рд╛рд░рд╛ "рд░реАрдб-рдУрдирд▓реА" рдХреЗ рд░реВрдк рдореЗрдВ рд╡реНрдпрд╛рдЦреНрдпрд╛ рдХреА рдЬрд╛рдПрдЧреА (рдХреНрдпреЛрдВ рдЕрдиреНрдп рддрд░реАрдХреЛрдВ рд╕реЗ рдХрд╛рдо рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ) рдХреЛ рдмрд┐рдЧрд╛рдбрд╝реЗрдВ, рдФрд░ рдЗрд╕ рд╕рдВрдмрдВрдз рдореЗрдВ, рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рдХреЛ рдереЛрдбрд╝реА рдорд╛рддреНрд░рд╛ рдореЗрдВ рдЕрддрд┐рд░рд┐рдХреНрдд рдореЗрдореЛрд░реА рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреАред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдмрд╛рд╣рд░реА рдЖрдХреГрддрд┐ рдЫрд╡рд┐рдпреЛрдВ рдХреЗ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдФрд░ рд╡реИрд╢реНрд╡реАрдХрд░рдг рдХреЗ рд▓рд┐рдП рдПрдХ рдЙрдкрдпреЛрдЧреА рд╡рд╕реНрддреБ рд╣реИред


рддреЛ, рдХрд╛рд░реНрдп: рдореВрд▓ рдЫрд╡рд┐ (рдЫрд╡рд┐ рдмрд┐рдВрджреБрдУрдВ рдХреА рдПрдХ рд╕рд░рдгреА) рдХреЛ рд░реВрдкрд░реЗрдЦрд╛ рдХреА рд╕реВрдЪреА рдореЗрдВ рдмрджрд▓рдиреЗ рдХреЗ рд▓рд┐рдПред рдПрдХ рдкрде рдПрдХ рдЫрд╡рд┐ рдХреЗ рдЬреБрдбрд╝реЗ рд╣рд┐рд╕реНрд╕реЗ рдХреЗ рд▓рд┐рдП рдмрд╕ рдмрд╛рд╣рд░реА рдмрд┐рдВрджреБрдУрдВ рдХрд╛ рдПрдХ рд╕реЗрдЯ рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдПрдХ рднрд░реЗ рд╣реБрдП рд╕рд░реНрдХрд▓ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рдореЛрдЪреНрдЪ рд╕рднреА рдмрд╛рд╣рд░реА рдмрд┐рдВрджреБрдУрдВ рд╕реЗ рдкреНрд░рд╛рдкреНрдд рдПрдХ рд╕рд░реНрдХрд▓ рд╣реИред

рдЖрда-рдЬреБрдбрд╝рд╛рд╡ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЕрд░реНрдерд╛рдд, рджреЛ рдмрд┐рдВрджреБ рдЬреБрдбрд╝реЗ рд╣реБрдП рд╣реИрдВ рдпрджрд┐ рд╡реЗ рджрд┐рд╢рд╛рдУрдВ рдХреЗ рд╕рдВрдмрдВрдз рдореЗрдВ рдкрдбрд╝реЛрд╕реА рд╣реИрдВ, рдмрд╛рдПрдВ-рджрд╛рдПрдВ-рдиреАрдЪреЗ рдФрд░ рддрд┐рд░рдЫреЗред рдЗрд╕ рдкреНрд░рдХрд╛рд░, рдкреНрд░рддреНрдпреЗрдХ рдмрд┐рдВрджреБ рдореЗрдВ рдЕрдзрд┐рдХрддрдо рдЖрда рдкрдбрд╝реЛрд╕реА рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВред

рдЫреЛрдЯреА рддреИрдпрд╛рд░реА


рд╣рдо рдПрдХ рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рдХрд╛ рдирд┐рд░реНрдорд╛рдг рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВ рдЬреЛ рдирд┐рдореНрди рд╕рдВрд░рдЪрдирд╛ рдХреЗ рд╕рд╛рде рдХрд┐рд╕реА рд╡рд╕реНрддреБ рдХреЗ рджрд┐рдП рдЧрдП рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдмрд╛рд╣рд░реА рдмрд┐рдВрджреБ рд╕реЗ рдХрд╛рдлреА рдХреБрд╢рд▓рддрд╛ рд╕реЗ рдПрдХ рд╕рдореЛрдЪреНрдЪ рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИ:
class Contour : public Points
{
// references to the constructor params
const Image& SourceImage;
ImageMap& CurrentImageMap;

public :
/* here we assume that image is coherent in any of 8 ways,
* so if the pixel will not have neighbor in any of 4 diagonal and 4 straight directions
* then it will be considered as separate image part */

// extract contour and mark all coherent points on image map
Contour( const Image& img, ImageMap& map, const Point& start);

private :
// private methods for contour pass implementation only
void passDownLeft(Point& p, bool InvertedAxis = false );
Point movePoint( const Point& src, int x, int y, bool InvertedAxis = false );
Point commitPoint( const Point& p);
};

рдпрд╣рд╛рдВ рд╕рднреА рдЖрд╡рд╢реНрдпрдХ рд╡рд╕реНрддреБрдПрдВ рдФрд░ рд╡рд┐рдзрд┐рдпрд╛рдВ рд╣реИрдВ рдЬрд┐рди рдкрд░ рд╣рдо рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВрдЧреЗред рдХрдВрд╕реНрдЯреНрд░рдХреНрдЯрд░ рд╕рдВрджреЗрд╣ рд╕реЗ рдкрд░реЗ рд╣реИ, SourceImage рднреАред

ImageMap рдХреНрдпрд╛ рд╣реИ? рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рд╕рдореЛрдЪреНрдЪ рдХреЗ рдирд┐рд░реНрдорд╛рдг рдХреЗ рд▓рд┐рдП рдПрд▓реНрдЧреЛрд░рд┐рджрдо рдХреЛ рдХрд┐рд╕реА рднреА рддрд░рд╣ рд╕реЗ рдмрд┐рдВрджреБрдУрдВ рдХреЛ рдЪрд┐рд╣реНрдирд┐рдд рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП рддрд╛рдХрд┐ рдЙрдирдХреА рджреЛрд╣рд░рд╛рдпрд╛ рдпрд╛рддреНрд░рд╛ рдХреЛ рд░реЛрдХрд╛ рдЬрд╛ рд╕рдХреЗ, рдЗрд╕рд▓рд┐рдП, рд╡рд┐рдЪрд╛рд░ рдХрд┐рдП рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ рдмрд┐рдВрджреБ рдЙрд╕ рд╡рд╕реНрддреБ рдХреА рд╕рдВрдЦреНрдпрд╛ рдХреЗ рд╕рд╛рде рдЪрд┐рд╣реНрдирд┐рдд рд╣реЛрдВрдЧреЗ, рдЬрд┐рд╕рдХреЗ рд╡реЗ рд╕рдВрдмрдВрдзрд┐рдд рд╣реИрдВред

рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЗрд╕рдХреЗ рд▓рд┐рдП рдЙрддрдиреА рд╣реА рд╕реНрдореГрддрд┐ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреА рдЬрд┐рддрдиреА рдореВрд▓ рдЫрд╡рд┐ рдореЗрдВ рд╣реЛрддреА рд╣реИ, рд▓реЗрдХрд┐рди рд╣рдо рдПрдХ рдЕрдзрд┐рдХ рдХреБрд╢рд▓ рд╕рдВрд░рдЪрдирд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред рдпрд╣ рдЙрди рдмрд┐рдВрджреБрдУрдВ рдкрд░ рдореЗрдореЛрд░реА рдмрд░реНрдмрд╛рдж рдХрд░рдиреЗ рдХрд╛ рдХреЛрдИ рдорддрд▓рдм рдирд╣реАрдВ рд╣реИ рдЬреЛ рд╕рдореЛрдЪреНрдЪ рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рдирд╣реАрдВ рд╣реИрдВ рдпрд╛ рдЗрд╕рдХреЗ рдЕрдВрджрд░ рдЭреВрда рдирд╣реАрдВ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдореИрдВ рдХреЗрд╡рд▓ рдЫреЛрдЯреЗ рдУрд╡рд░рд╣реЗрдб рдХреЗ рд╕рд╛рде рд╕реАрдорд╛ рдмрд┐рдВрджреБрдУрдВ рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдФрд░ рдЙрдиреНрд╣реЗрдВ рдЬрд▓реНрджреА рд╕реЗ рд╕рдВрдмреЛрдзрд┐рдд рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реВрдВред


рд╕рдВрд░рдЪрдирд╛ рдПрд╕рдЯреАрдИрдкреА 2 рдЖрдХрд╛рд░ рдХреЗ рдЫрд╡рд┐ рдмреНрд▓реЙрдХреЛрдВ рдХреЗ рд╕реВрдЪрдХрд╛рдВрдХ рдкрд░ рдЖрдзрд╛рд░рд┐рдд рд╣реИред рд╕реВрдЪрдХрд╛рдВрдХ рдЕрдкрдиреЗ рдЖрдк рдореЗрдВ рдПрдХреНрд╕ / рдПрд╕рдЯреАрдИрдкреА * рд╡рд╛рдИ / рдПрд╕рдЯреАрдИрдкреА рдХреЗ рдмреНрд▓реЙрдХ рдХреЗ рд▓рд┐рдВрдХ рдХреА рдПрдХ рд╕рд░рдгреА рд╣реИ, рдЬрд╣рд╛рдВ рдПрдХреНрд╕ рдФрд░ рд╡рд╛рдИ рдореВрд▓ рдЫрд╡рд┐ рдХрд╛ рд╕рдВрдХрд▓реНрдк рд╣реИрдВред рд▓реЗрдЦрди рдХреЗ рд▓рд┐рдП рдПрдХ рдмреНрд▓реЙрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╕рдордп, рдЗрд╕реЗ рдореЗрдореЛрд░реА рдореЗрдВ рдЖрд╡рдВрдЯрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рд╕рдВрдмрдВрдзрд┐рдд рд╕реВрдЪрдХрд╛рдВрдХ рддрддреНрд╡ рдХреЛ рдЗрд╕рдХреЗ рд╕реВрдЪрдХ рдХреЗ рд╕рд╛рде рдЪрд┐рд╣реНрдирд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рд╕рдмрд╕реЗ рдЦрд░рд╛рдм рд╕реНрдерд┐рддрд┐ рдореЗрдВ, рдпрджрд┐ рд╣рдо рдкреНрд░рддреНрдпреЗрдХ (n * STEP, m * STEP) рдмрд┐рдВрджреБ рдХреЛ рдЪрд┐рд╣реНрдирд┐рдд рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рд╣рдореЗрдВ рдЪрд┐рддреНрд░ рдХреЗ рдЖрдХрд╛рд░ рдХреЗ рдмрд░рд╛рдмрд░ рдПрдХ рдореЗрдореЛрд░реА рдЙрдкрдпреЛрдЧ рдорд┐рд▓рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдФрд╕рддрди рд╣рдо 50-90% рдореЗрдореЛрд░реА рдмрдЪрд╛рддреЗ рд╣реИрдВред рдЗрдВрдбреЗрдХреНрд╕рд┐рдВрдЧ, рдЖрдкрдиреЗ рдЕрдиреБрдорд╛рди рд▓рдЧрд╛рдпрд╛, рдпрд╣ рдПрд╕рдЯреАрдИрдкреА рджреНрд╡рд╛рд░рд╛ рдирд┐рд░реНрджреЗрд╢рд╛рдВрдХ рдХреЛ рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд░рдХреЗ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдФрд░ рдпрджрд┐ рдПрд╕рдЯреАрдИрдкреА рджреЛ рдХреА рд╢рдХреНрддрд┐ рд╣реИ, рддреЛ рдпрд╣ рдЙрд▓реНрд▓реЗрдЦрдиреАрдп рд░реВрдк рд╕реЗ рдЬрд▓реНрджреА рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред

рд╡реИрд╕реЗ, рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж, рдЫрд╡рд┐ рдорд╛рдирдЪрд┐рддреНрд░ рдЫрд╡рд┐ рдкрд░ рд╡рд╕реНрддреБрдУрдВ рдХреЛ рд╕реВрдЪреАрдмрджреНрдз рдХрд░рдиреЗ рдХреЗ рдХрд╛рд░реНрдп рдХрд╛ рдкрд░рд┐рдгрд╛рдо рд╣реИред

рд╕рдореЛрдЪреНрдЪ рд╡рд┐рдзрд┐ рдХреЛ рд╕рдореЛрдЪреНрдЪ рдореЗрдВ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдФрд░ рд╡рд░реНрддрдорд╛рди рд╕рдореЛрдЪреНрдЪ рдХреЗ рд╕рд╛рде ImageMap рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ:
Point Contour::commitPoint( const Point& p)
{
if (!CurrentImageMap.isAssigned(p) && SourceImage.isFilled(p))
{
CurrentImageMap.assignSegment(p, this );
push_back(p);
}
return p;
}


рдмреЗрд╢рдХ, рдпреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╡рд┐рд╡рд░рдг рд╣реИрдВ, рд▓реЗрдХрд┐рди рдпрд╣рд╛рдВ рд╕рдм рдХреБрдЫ рд╕рд░рд▓ рд╣реИ рдФрд░ рдЗрд╕рдХрд╛ рдкреБрди: рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред MovePoint рдлрд╝рдВрдХреНрд╢рди рднреА рдХрд╛рдлреА рд╕рд░рд▓ рд╣реИ, рдпрд╣ рдмрд╕ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рд╡реЗрддрди рд╡реГрджреНрдзрд┐ рдХреЛ рдмрд┐рдВрджреБ рдкрд░ рдЬреЛрдбрд╝рддрд╛ рд╣реИ:
Point Contour::movePoint( const Point& src, int x, int y, bool InvertedAxis)
{
Point p = src;
if (InvertedAxis)
{
x = -x;
y = -y;
}
pX += x;
pY += y;
return p;
}


InvertedAxis рдкреИрд░рд╛рдореАрдЯрд░, рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рдЕрдиреБрдорд╛рди рд▓рдЧрд╛ рд╕рдХрддреЗ рд╣реИрдВ, рдмрд╕ рд╡реЗрддрди рд╡реГрджреНрдзрд┐ рдХреЛ рд╡рд┐рдкрд░реАрдд рдореЗрдВ рдмрджрд▓ рджреЗрддрд╛ рд╣реИ (рдпрд╣ рдмрд╛рдж рдореЗрдВ рдХрд╛рдо рдЖрдПрдЧрд╛)ред

рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рдХреЛрд░

рдЦреИрд░, рдЕрдм рджрд┐рд▓рдЪрд╕реНрдк рд╣реИред рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдмрд╛рдИрдкрд╛рд╕ рд╣реА рдХрд╛рд░реНрдп рдХрд░рддрд╛ рд╣реИ: рдкрд╛рд╕рдбрд╛рдЙрди рд▓реЙрдлреНрдЯред рджрд┐рдП рдЧрдП рд╢реБрд░реБрдЖрддреА рдмрд┐рдВрджреБ рдХреЗ рд▓рд┐рдП, рд╣рдо рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЗ рдЪрд╛рд░реЛрдВ рдУрд░ рдЬрд╛рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рдиреАрдЪреЗ рдЬрд╛ рд░рд╣реЗ рд╣реИрдВ, рдФрд░ рдпрджрд┐ рд╕рдВрднрд╡ рд╣реЛ рддреЛ рдмрд╛рдИрдВ рдУрд░ред

рдЬрдмрдХрд┐ рд╣рдо рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЗ рднреАрддрд░ рд╣реИрдВ (рдпрд╛рдиреА рд╡рд░реНрддрдорд╛рди рдмрд┐рдВрджреБ рдХрд╛ рд░рдВрдЧ рдкреГрд╖реНрдарднреВрдорд┐ рд░рдВрдЧ рдХреЗ рдмрд░рд╛рдмрд░ рдирд╣реАрдВ рд╣реИ):

рдпрд╣ рдХрд╛рдлреА рд╕рд░рд▓ рд▓рдЧрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рд╕рдЯреАрдХ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдереЛрдбрд╝рд╛ рдЕрдзрд┐рдХ рдЬрдЯрд┐рд▓ рд▓рдЧрддрд╛ рд╣реИ:
void Contour::passDownLeft(Point& p, bool InvertedAxis)
{
while (SourceImage.isInside(p))
{
commitPoint(p);

// step one point down
p = movePoint(p, 0,1, InvertedAxis);

// select one of neighbors which is filled, prefer left one...
Point left = movePoint(p, -1,0, InvertedAxis);
if (SourceImage.isFilled(left))
{
p = commitPoint(left);
// ...and shift left as many as possible
while (SourceImage.isInside(p))
{
Point left = movePoint(p, -1,0, InvertedAxis);
if (!SourceImage.isFilled(left))
break ; // no more left neighbors

p = commitPoint(left);

Point up = movePoint(p, 0,-1, InvertedAxis);
if (SourceImage.isFilled(up))
return ; // crossed inside area
}
}
else
{
// selection still unfilled...
while (SourceImage.isInside(p) && !SourceImage.isFilled(p))
{
// ...shift right by connected points and test again
Point right = movePoint(p, 1,0, InvertedAxis);
Point rightUp = movePoint(right, 0,-1, InvertedAxis);
if (!SourceImage.isFilled(rightUp))
return ; // no more bottom right neighbors
commitPoint(rightUp);
p = commitPoint(right);
}
}
}
}

рдпрджрд┐ рдХреЛрдИ рдмрд┐рдВрджреБ рдЫрд╡рд┐ рдХреЗ рднреАрддрд░ рд╕реНрдерд┐рдд рд╣реИ рддреЛ рдЗрдирд╕рд╛рдЗрдб рдлрд╝рдВрдХреНрд╢рди рдпрд╣ рдЬрд╛рдВрдЪрддрд╛ рд╣реИ рдХрд┐ рдХрд╣реАрдВ рдЙрд╕рдХреА рд╕реАрдорд╛ рд╕реЗ рдмрд╛рд╣рд░ рди рдЬрд╛рдПред

рдкрд░реАрдХреНрд╖рдг рдЪрд┐рддреНрд░ рдкрд░ рдЗрд╕ рдмрд╛рдИрдкрд╛рд╕ рдХреЛ рд▓реЙрдиреНрдЪ рдХрд░рдиреЗ рд╕реЗ (рд╣рд░реЗ рд░рдВрдЧ рдХреЗ рдмрд┐рдВрджреБ рдкреНрд░рддреНрдпреЗрдХ рд╡рд╕реНрддреБ рдХреЛ рдмрд╛рдпрдкрд╛рд╕ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╢реБрд░реБрдЖрддреА рдмрд┐рдВрджреБ рд╣реИрдВ), рдЬреИрд╕рд╛ рдХрд┐ рдЕрдкреЗрдХреНрд╖рд┐рдд рдерд╛, рд╣рдореЗрдВ рдХреЛрдИ рднреА рдЕрдВрддрд░реНрд╡рд┐рд░реЛрдз рдирд╣реАрдВ рдорд┐рд▓рд╛, рдХреНрдпреЛрдВрдХрд┐ рдирд┐рд░реНрдорд╛рдг рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдкреНрд░рддреНрдпреЗрдХ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЗ рдирд┐рдореНрдирддрдо рдмрд┐рдВрджреБрдУрдВ рдХреЗ рдЦрд┐рд▓рд╛рдл рдЯрд┐рдХреА рд╣реБрдИ рд╣реИред рдЗрд╕рд▓рд┐рдП, рдРрд╕рд╛ рдПрдХ рдлрд╝рдВрдХреНрд╢рди рдкрд░реНрдпрд╛рдкреНрдд рдирд╣реАрдВ рд╣реИред рд▓реЗрдХрд┐рди, рдЖрдк рдКрдкрд░ рдФрд░ рджрд╛рдПрдВ рддрд░рдл рд╕рдореЛрдЪреНрдЪ рдХреЛ рдкреВрд░рдХ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдЬреЛ рдЗрд╕ рдорд╛рдорд▓реЗ рдХреЗ рд▓рд┐рдП рдкреНрд░рджрд╛рди рдХрд┐рдП рдЧрдП InvertedAxis рдзреНрд╡рдЬ рджреНрд╡рд╛рд░рд╛ рдЖрд╕рд╛рдиреА рд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ! рдЗрд╕ рдкреНрд░рдХрд╛рд░, рдЕрдВрдд рдореЗрдВ рдЫреЛрдбрд╝ рджрд┐рдпрд╛ рдЧрдпрд╛ рдирд┐рд░реНрдорд╛рдгрдХрд░реНрддрд╛ рд╕рдореЛрдЪреНрдЪ рдирд┐рд░реНрдорд╛рдг рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рдореЗрдВ рдЬреЛрдбрд╝ рджреЗрдЧрд╛:

ontour::Contour( const Image& img, ImageMap& map, const Point& start)
: SourceImage(img), CurrentImageMap(map)
{
bool doneSomething = true ;
Point p = start;
for ( int iter = 0; doneSomething; iter++)
{
size_t count = size();
passDownLeft(p, iter % 2 == 1);
doneSomething = size() > count;
}
}



рд╣рдо рд╡реИрдХрд▓реНрдкрд┐рдХ рдмрд╛рдПрдБ-рджрд╛рдПрдБ рдФрд░ рджрд╛рдПрдБ-рдмрд╛рдПрдБ, рдЬрдм рддрдХ рдХрд┐ рдпрд╣ рдкрде рдореЗрдВ рдирдП рдмрд┐рдВрджреБрдУрдВ рдХреЛ рдЬреЛрдбрд╝рддрд╛ рд╣реИред

рддреЛ, рд╣рдореЗрдВ рдЗрд╕ рд╕рдореЛрдЪреНрдЪ рдХреЗ рдмрд┐рдВрджреБрдУрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ рдХреЗ рд╕рд╛рдкреЗрдХреНрд╖, рдХрд┐рд╕реА рджрд┐рдП рдЧрдП рдЫрд╡рд┐ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЗ рд▓рд┐рдП рдмрд╛рд╣рд░реА рд╕рдореЛрдЪреНрдЪ рдХреЗ рд╕рднреА рдмрд┐рдВрджреБрдУрдВ рдХреЛ рд╕реВрдЪреАрдмрджреНрдз рдХрд░рдиреЗ рдХреА рдПрдХ рдХрд╛рд░реНрдп рдкрджреНрдзрддрд┐ рдорд┐рд▓реА рд╣реИред

рдЖрд░рдВрднрд┐рдХ рдЕрдВрдХреЛрдВ рдХреА рдЧрдгрдирд╛

рд╕реНрд░реЛрдд рдЫрд╡рд┐ рд╕реЗ рдЖрдХреГрддрд┐ рдХреЗ рдирд┐рд░реНрдорд╛рдг рдХреЗ рд▓рд┐рдП рд╕рднреА рд╢реБрд░реБрдЖрддреА рдмрд┐рдВрджреБрдУрдВ рдХреЛ рдЦреЛрдЬрдиреЗ рдХреЗ рд▓рд┐рдП рдХреЗрд╡рд▓ рдПрдХ рдЪреАрдЬ рдмрдЪреА рд╣реИ:
void Vectorization::getContours()
{
Point p(0,0); // line-by-line scan to extract contours of objects
for (pY = 0; pY < SourceImage.getHeight(); p.Y++)
{
for (pX = 0; pX < SourceImage.getWidth(); p.X++)
{
if (SourceImage.isFilled(p) && !ImageMap.isAssigned(p))
{
// that pixel is unprocessed yet, so extract the contour starting from it
Contour* c = new Contour(SourceImage, ImageMap, p);
// add new contour
ContoursStorage.push_back( c );
}
}
}
}

рдЕрдм рддрдХ рдпрд╣ рдПрд▓реНрдЧреЛрд░рд┐рдердо рдХрд╛ рд╕рдмрд╕реЗ рдзреАрдорд╛ рд╣рд┐рд╕реНрд╕рд╛ рд╣реИ: рдЖрдЦрд┐рд░рдХрд╛рд░, рдЖрдкрдХреЛ рдЫрд╡рд┐ рдХреЗ рдкреНрд░рддреНрдпреЗрдХ рдмрд┐рдВрджреБ рдкрд░ рдЬрд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред

рд▓реЗрдХрд┐рди рдЗрд╕рдХрд╛ рдЕрдиреБрдХреВрд▓рди рд╡реНрдпрд╛рд╡рд╣рд╛рд░рд┐рдХ рд░реВрдк рд╕реЗ рд╕рддрд╣ рдкрд░ рднреА рд╣реИ: рд╣рдо рдЙрд╕реА рдЗрдВрдбреЗрдХреНрд╕ рд╕рдВрд░рдЪрдирд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ рдЬрдм рдЫрд╡рд┐ рдорд╛рдирдЪрд┐рддреНрд░ рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рддреЗ рд╣реБрдП, рдЫрд╡рд┐ рдХреЛ рдЖрдХрд╛рд░ STEP 2 рдХреЗ рдмреНрд▓реЙрдХ рдореЗрдВ рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред
void Vectorization::getContoursOptimized()
{
Point pIndex(0,0); // step-by-step scan
for (pIndex.Y = 0; pIndex.Y < SourceImage.getHeight(); pIndex.Y += STEP)
{
for (pIndex.X = 0; pIndex.X < SourceImage.getWidth(); pIndex.X += STEP)
{
if (!SourceImage.isEmptyIndex(pIndex))
{
Point pLocal = pIndex;
for (pLocal.Y = pIndex.Y ; pLocal.Y < STEP; pLocal.Y++)
{
for (pLocal.X = pIndex.X ; pLocal.X < STEP; pLocal.X++)
{
if (SourceImage.isFilled(pLocal))
{
if (Map.isAssigned(pLocal))
{
pLocal.X = dynamic_cast<Contour*>(Map.getSegment(pLocal))->getMaxX(pLocal.Y);
break ; /* skip already processed points by getting the max contour X for the specified Y */
}
// that pixel is unprocessed yet, so extract the contour starting from it
Contour* cntr = new Contour(SourceImage, Map, pLocal);
// add new contour
ContoursStorage.push_back( cntr ) ;
}
}
}
}
}
}
}

рдЗрд╕ рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рдХреА рдЬрдЯрд┐рд▓рддрд╛ рдЫрд╡рд┐ рд╡рд╕реНрддреБрдУрдВ рдХреЗ рд▓рд┐рдП рдмрд╛рд╣рд░реА рдЖрдХреГрддрд┐ рдХреЗ рдмрд┐рдВрджреБрдУрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ рдХреЗ рд▓рд┐рдП рдЖрдиреБрдкрд╛рддрд┐рдХ рд╣реИред

рдЪрд╛рд▓

рдЕрдВрддрд┐рдо рддрдереНрдп рд╕реЗ рдпрд╣ рдЗрд╕ рдкреНрд░рдХрд╛рд░ рд╣реИ рдХрд┐ рдпрд╣ рд╡рд┐рдзрд┐ рдЖрдо рддреМрд░ рдкрд░ рдЙрди рдЫрд╡рд┐рдпреЛрдВ рдкрд░ рдмрд╣реБрдд рдЕрдЪреНрдЫреА рдирд╣реАрдВ рд╣реЛрддреА рд╣реИ рдЬрд╣рд╛рдВ рд╡реНрдпрд╛рд╡рд╣рд╛рд░рд┐рдХ рд░реВрдк рд╕реЗ рдЬреБрдбрд╝реЗ рдмрд┐рдВрджреБрдУрдВ рдХрд╛ рдХреЛрдИ рд╕рдореВрд╣ рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИ, рдЬрдмрдХрд┐ рдмрд┐рдВрджреБрдУрдВ рдХреЛ рднрд░рдирд╛ рдкреВрд░реНрдг рд╕рдВрднрд╡ рдХреЗ рдХрд░реАрдм рд╣реИ (25% - рдкреНрд░рддреНрдпреЗрдХ рд╕рдордиреНрд╡рдп рдореЗрдВ рдкреНрд░рддреНрдпреЗрдХ рджреВрд╕рд░рд╛ рдмрд┐рдВрджреБ рднрд░рд╛ рдЬрд╛рддрд╛ рд╣реИ, рдмрд╛рдХреА - рдХреЛрдИ)ред

рд▓реЗрдХрд┐рди рдЫрд╡рд┐ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рд╕рдорд╕реНрдпрд╛рдУрдВ рдХреЗ рджреГрд╖реНрдЯрд┐рдХреЛрдг рд╕реЗ, рдРрд╕реА рддрд╕реНрд╡реАрд░реЗрдВ рд╕рд┐рд░реНрдл рд╢реЛрд░ рд╣реИрдВ, рдЬреЛ рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдлрд┐рд▓реНрдЯрд░ рджреНрд╡рд╛рд░рд╛ рдЖрд╕рд╛рдиреА рд╕реЗ рдХрдЯ рдЬрд╛рддреА рд╣реИрдВред рддреЛ рд╕рдм рдХреБрдЫ рдареАрдХ рд╣реИ :)

Source: https://habr.com/ru/post/In119461/


All Articles