если это не так, то точку нужно исключить из дальнейшего анализа*/
public:
TAnalysePicture(const CString src, CDC *screen);
~TAnalysePicture(void);
int getErr();
CString getErrMsg();
CString getPathSrc(){return srcImg;};
TAbsFing AnalysePicture(); //Обработка загруженного изображения и получение образа
bool Show(int x, int y, int xt=-1, int yt=-1);
TFingPicture *GetPic1();
TFingPicture *GetPic2();
};
П.1.9 ТЕКСТ МОДУЛЯ TAnalysePicture.cpp
#include "StdAfx.h"
#include "TAnalysePicture.h"
TAnalysePicture::TAnalysePicture(const CString src, CDC *screen)
{
pic = new TFingPicture(screen);
err = -1;
if(!pic->Load(src)) err = 0;
pic->Rectangle(CPoint(0, 0), pic->GetSize(), 10);
srcImg = src;
tmpPic = new TFingPicture(screen);
tmpPic->Load(src);
pic2 = new TFingPicture(screen);
pic2->Load(BLANK);
}
TAnalysePicture::~TAnalysePicture(void)
{
delete(tmpPic);
delete(pic2);
delete(pic);
}
//Код ошибки
int TAnalysePicture::getErr()
{
return err;
}
//Сообщение ошибки
CString TAnalysePicture::getErrMsg()
{
CString msg = "";
switch (err)
{
case -1: {msg = "Ошибок при загрузке изображения нет"; break;}
case 0: {msg = "Изображение не загружено"; break;}
case 1: {msg = "Возникла ошибка при загрузке изображения"; break;}
default: {msg = "Нераспознанная ошибка";}
}
return msg;
}
// Обработка загруженного изображения и получение образа
TAbsFing TAnalysePicture::AnalysePicture()
{
TAbsFing ret, ret2;
if(err != -1)
{
if(MESSAGEOUT) MessageBox(NULL, getErrMsg(), "Ошибка", MB_OK);
return ret;
}
int prevCol;
int changeN = 0; //Счетчик произведенных изменений на изображении
list<TMapElDot> map; //Карта точек принадлежащих линиям
list<TMapElDot>::iterator imap; //Итератор для map
map = LookPic(); //сканирование картинки и нахождение линий на ней
do{
changeN = 0;
prevCol = (int)map.size();
imap = map.begin();
do{ //Изображение можно модифицировать
if(imap->pr1) //Линия нуждается в обработке
changeN += ChangeLine(imap, map); //Обработка (преобразование) изображения
imap++; //Переход для обработки следующей линии
}while(imap != map.end()); //Изображение можно модифицировать
}while(prevCol<0.1*map.size()); //Изображение можно модифицировать
map = LookPic(); //сканирование картинки и нахождение линий на ней
imap = map.begin();
do{ //Изображение можно модифицировать
ret.merge(ReadPic(imap));
imap++; //Переход для обработки следующей линии
}while(imap != map.end()); //Изображение можно модифицировать
////////////////////////////////////////////////////////////////////
/////////////////////Фильтрование полученных точек//////////////////
///отсеиваются близкостоящие направленные в противоположные строки//
//////////а так же точки слева и справа от которых нет линий////////
int leftDots = 0; //число отсеянных точек
leftDots = DotsFilter(ret); //Фильтрование полученных точек
////////////////////////////////////////////////////////////////////
ret2.clear();
for(TAbsFing::iterator iter = ret.begin(); iter != ret.end(); iter++)
{
if(!iter->show) continue;
//рисование найденных точек (цвет окончания и раздвоения различный)
COLORREF col = (iter->type)?0xFF0000:0x000000;
pic2->Line(iter->coord, iter->coord, 5, col);
pic2->Line(iter->coord,
CPoint(iter->coord.x+(int)(10.0*cos(iter->alpha)),iter->coord.y-(int)(10.0*sin(iter->alpha))),
2, col);
ret2.push_back(*iter);
}
ret.clear();
return ret2;
}
TAbsFing TAnalysePicture::ReadPic(list<TMapElDot>::iterator _dot)
//Нахождение на изображении спец точек
{
TAbsFing retFing; //Образ отпечатка в абсолютных координатах
int kol = 0; //количество пройденных точек
int vec = 0; //направление поиска очередной точки
int tekS = 0; //Текущее количество коротких векторов
CPoint A, //Начало вектора
B; //Конец вектора
TAbsFing vecDotS; //массив точек для коротких векторов
TAbsFing vecDotL; //массив точек для длинных векторов
TAbsFing historyDotL; //история точек для длинных векторов
TAbsDot _tmpDotFing, bestDot;
TAbsFing::iterator iter;
double alpha; //направление вектора (в радианах)
int stopKol = 2000; //предел шагов
int ret = 0; //счетчик шагов после прохождения начальной точки
bool homeOver = false; //признак окончания обработки
A = _dot->coord; B = _dot->coord;
CPoint olddot, dot = _dot->coord; //Текущая точка на линии
do{
//основной цикл обработки,
//варианты завершения цикла
//продолжается до тех пор пока вся линия не будет пройдена (нормальный вариант)
//зацикливание (не нормальный вариант, их несколько)
//
olddot = dot;
dot = pic->NextDotCW(dot, vec); //Поиск следующей точки _по часовой_ стрелке
if(dot.x == olddot.x && dot.y == olddot.y)
{//положение точки не изменилось => выход//
CString s;
s.Format("x = %d, y = %d, kol= %d", dot.x, dot.y, kol);
if(MESSAGEOUT)MessageBox(0, "положение точки не изменилось => выход\n" + s, "", MB_OK);
return retFing;
}
kol++; //подсчет пройденных точек
if(kol % LEN_S == 0)
{//появился новый короткий вектор
tekS++;
A = B;
B = dot;
pic2->Line(A,B, 1, 0x999999);
_tmpDotFing.coord = A;
alpha = GetAlpha(A, B); //расчет локального направления между KOL_S пикселями (направление короткого вектора)//
double dAlpha = 0.0; //Разница углов
if(vecDotS.size() > 0) //в списке можно взять предыдущее значение
dAlpha = alpha - vecDotS.begin()->alpha;
/**/ if (abs(dAlpha) >= M_PI) //разница между новым углом и предыдущим не нормальная!
{//необходимо скорректировать текущую alpha
/**/ if (dAlpha < 0.0)
{
while (abs(dAlpha) > M_PI)
{
alpha += 2.0 * M_PI;
dAlpha += 2.0 * M_PI;
}
}else
{
while (dAlpha >= M_PI)
{
alpha -= 2.0 * M_PI;
dAlpha -= 2.0 * M_PI;
}
}
}
_tmpDotFing.alpha = alpha; //запоминание направления из точки А//
vecDotS.push_front(_tmpDotFing);
///////////////////////////////////////////////////////////////////////
///////проверяем два соседних длинных вектора при условии что//////////
///////пройдено достаточно точек, чтоб сравнивать длнинные вектора/////
if(vecDotS.size() < KOL_S) continue;
//Вычисление среднего направления LEN_L коротких векторов//
//запись данных по длинному вектору////////////////////////
double sumAlpha = 0.0;
iter = vecDotS.begin();
vecDotL.clear(); //пересчитаем длинные вектора
for(int i = 0; i < KOL_S; i++)
{
sumAlpha += iter->alpha;
if ((i+1) % LEN_L == 0)
{
_tmpDotFing = *iter;
_tmpDotFing.alpha = sumAlpha / LEN_L;
vecDotL.push_back(_tmpDotFing);
sumAlpha = 0.0;
}
iter++;
}
if (abs(vecDotL.begin()->alpha) > 3*2*M_PI)
{//слишком много оборотов//
CString s;
s.Format("alpha = %.2f", vecDotL.begin()->alpha*180);
if(MESSAGEOUT)MessageBox(0, "слишком много оборотов\n"+s, "", MB_OK);
return retFing;
}
//проверяем два соседних длинных вектора//
dAlpha = vecDotL.begin()->alpha - (++vecDotL.begin())->alpha;
if (abs(dAlpha) > (TEST_ALPHA / 180.0 * M_PI)) //сильный изгиб//
{
if (historyDotL.empty())
{ //сохранение состояния//
bestDot.alpha = 0.0;
}
if (dAlpha > 0) //раздвоение
alpha = (vecDotL.begin()->alpha - M_PI + (++vecDotL.begin())->alpha) / 2.0;
else //окончание
alpha = (vecDotL.begin()->alpha + M_PI + (++vecDotL.begin())->alpha) / 2.0;
_tmpDotFing = vecDotL.front();
_tmpDotFing.alpha = alpha; //направление в СТ (специфичная точка)//
_tmpDotFing.type = dAlpha<0; //тип СТ//
historyDotL.push_front(_tmpDotFing);
if(bestDot.alpha <= abs(dAlpha))
{
bestDot.coord = _tmpDotFing.coord;
bestDot.alpha = abs(dAlpha);
}
}
else //сильный изгиб//
{
if (!historyDotL.empty()) //был _пройден_ сильный изгиб
{
alpha = 0;
for(iter = historyDotL.begin(); iter != historyDotL.end(); iter++)
alpha += iter->alpha;
alpha /= historyDotL.size(); //среднее значение в пройденной СТ
iter = historyDotL.begin();
for(unsigned int i = 0; i<(historyDotL.size()/2); i++) iter++;
// CPoint wdot = iter->coord; //наиболее вероятная точка для СТ
CPoint wdot = bestDot.coord; //наиболее вероятная точка для СТ
//Если раскомментировать эти строки, то исключатся точки имеющие продолжение
// CPoint dotForAccept = FindAcceptDot(wdot, alpha, iter->type);
// if (dotForAccept.x == -1)
{ //точка не имеет продолжения, запомним ее//
_tmpDotFing.alpha = ChangeAlphaInterval(alpha);
_tmpDotFing.coord = wdot;
_tmpDotFing.show = true;
_tmpDotFing.type = historyDotL.begin()->type;
retFing.push_back(_tmpDotFing);
}
historyDotL.clear();
stopKol += (kol*1.5 > stopKol)?1000:0;
}
}
}
if (dot.x == _dot->coord.x && dot.y == _dot->coord.y)
{//вероятно обход линии завершен
if (kol <= 2)
{//Линия подозрительно короткая
CString s;
s.Format("%d", kol);
if(MESSAGEOUT)MessageBox(0, "kol<=2 kol = " + s, "", MB_OK);
return retFing;
}else
{
homeOver = true; //пройти необходимо дальше начала
stopKol = kol + KOL_L*LEN_L*LEN_S;
}
}
if (homeOver) ret++;
}while(ret < (LEN_L*LEN_S*KOL_L) && ret < stopKol && kol <= stopKol);
_dot->pr1 = false;
_dot->pr2 = false;
return retFing;
}
list<TMapElDot> TAnalysePicture::LookPic()
//Попиксельное "пробегание" по картинке и
//запоминание черных точек, после нахождения черной точки
//заливка всей линии в цвет фона (удаление линии с картинки)
{
list<TMapElDot> map;
TMapElDot dot;
tmpPic->Copy(*pic);
for(int j = 0; j < pic->GetSize().y; j++)
for(int i = 0; i < pic->GetSize().x; i++)
{
if(!tmpPic->GetPixel(i,j)) //найден черный пиксель
{
dot.coord.x = i; dot.coord.y = j;
dot.pr1 = dot.pr2 = true;
map.push_back(dot);
tmpPic->FloodFill(i, j, 0xffffff); //удаление линии
}
}
tmpPic->Copy(*pic);
return map;
}
int TAnalysePicture::ChangeLine(list<TMapElDot>::iterator _dot, list<TMapElDot> &_map)
//Обработка картинки, ее изменение
//Обработка линии на которую указывает imap
//Исправление псевдо-раздвоений и псевдо-окончаний на указанной линии
{
int changeN = 0; //количество модификаций на линии
int kol = 0; //количество пройденных точек
int vec = 0; //направление поиска очередной точки
int tekS = 0; //Текущее количество коротких векторов
CPoint A, //Начало вектора
B; //Конец вектора
TAbsFing vecDotS; //массив точек для коротких векторов
TAbsFing vecDotL; //массив точек для длинных векторов
TAbsFing historyDotL; //история точек для длинных векторов
TAbsDot _tmpDotFing;
TAbsFing::iterator iter;
TAbsDot resetDot, bestDot;
double alpha; //направление вектора (в радианах)
int stopKol = 1500; //предел шагов
int ret = 0; //счетчик шагов после прохождения начальной точки
bool homeOver = false; //признак окончания обработки
_dot->pr1 = false;
A = _dot->coord; B = _dot->coord;
CPoint olddot, dot = _dot->coord; //Текущая точка на линии
do{
//основной цикл обработки,
//варианты завершения цикла
//продолжается до тех пор пока вся линия не будет пройдена (нормальный вариант)
//зацикливание (не нормальный вариант, их несколько)
//
olddot = dot;
dot = pic->NextDotCW(dot, vec); //Поиск следующей точки _по часовой_ стрелке
if(dot.x == olddot.x && dot.y == olddot.y)
{//положение точки не изменилось => выход//
CString s;
s.Format("x = %d, y = %d, kol= %d", dot.x, dot.y, kol);
if(MESSAGEOUT)MessageBox(0, "положение точки не изменилось => выход\n" + s, "", MB_OK);
return changeN;
}
kol++; //подсчет пройденных точек
if(kol % LEN_S == 0)
{//появился новый короткий вектор
tekS++;
A = B;
B = dot;
//pic2->Line(A,B, 1, 0x999999);
_tmpDotFing.coord = A;
alpha = GetAlpha(A, B); //расчет локального направления между KOL_S пикселями (направление короткого вектора)//
double dAlpha = 0.0; //Разница углов
if(vecDotS.size() > 0) //в списке можно взять предыдущее значение
dAlpha = alpha - vecDotS.begin()->alpha;