П .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; /**/ 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 changeN; } //проверяем два соседних длинных вектора// dAlpha = vecDotL.begin()->alpha - (++vecDotL.begin())->alpha; if (abs(dAlpha) > (TEST_ALPHA / 180.0 * M_PI)) //сильный изгиб// { if (historyDotL.empty()) { //сохранение состояния// resetDot = vecDotL.back(); bestDot.alpha = 0.0; } if (dAlpha > 0) //раздвоение alpha = (vecDotL.front().alpha - M_PI + (vecDotL.back().alpha)) / 2.0; else //окончание alpha = (vecDotL.front().alpha + M_PI + (vecDotL.back().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.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 = bestDot.coord; //наиболее вероятная точка для СТ CPoint dotForAccept = FindAcceptDot(wdot, alpha, iter->type); if (dotForAccept.x != -1) { //точка имеет продолжение// COLORREF cl; cl = (historyDotL.begin()->type)?0x000000:0xffffff; //здесь можно поиграть с разной толщиной линии// pic->Line(wdot, dotForAccept, 4, cl); _dot->pr1 = true; //эту линию необходио еще раз проанализировать changeN++; stopKol += (stopKol-kol < 200)?200:0; //stopKol += (kol*1.5 > stopKol)?500:0; //загрузить начальное состояние if(!historyDotL.begin()->type) { //если ликвидировано слипание то необходимо добавить новую точку на карту _map.push_back(TMapElDot(dot)); } //пройдена начальная точка, продлим анализ //очень возможно, что начальную точку мы больше не попадем if(ret-KOL_S*LEN_S < 0) { ret = 0; homeOver = false; stopKol = 500; } A = B = dot = resetDot.coord; vecDotS.clear(); vecDotL.clear(); //------------------------------ } historyDotL.clear(); } } } 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 changeN; }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->pr2 = false; return changeN; } inline double TAnalysePicture::GetAlpha(const CPoint A, const CPoint B) //Направлени из точки А в В [-pi,pi) { if(A == B) return 0.0; double alpha; if (A.x - B.x == 0) { if (A.y > B.y) alpha = M_PI_2; else alpha = -M_PI_2; }else { double a = ((double)A.y-B.y)/((double)B.x-A.x); alpha = atan(a); if (A.x > B.x) { if (alpha < 0) alpha += M_PI; else alpha -= M_PI; if (A.y == B.y) alpha = -M_PI; } } return alpha; } bool TAnalysePicture::TestFindDot(int _x, int _y) //тест точки: Разность направлений вперед и назад должно быть меньше 110 градусов { const int len = 7; CPoint A(_x, _y), B, C; //первый вектор B = A; int vec = 0; for(int i = 1; i<=len; i++) B = tmpPic->NextDotCW(B, vec); //------расчет угла-------// double alpha1 = GetAlpha(A, B); //второй вектор C = B; B = A; vec = 0; for(int i = 1; i<=len; i++) { B = tmpPic->NextDotCCW(B, vec); if(abs(B.x-C.x) < 3 && abs(B.y-C.y) < 3) return true; } //------расчет угла-------// double alpha2 = GetAlpha(A, B); //-----alpha1, alpha2------// alpha1 = abs(alpha2 - alpha1); if (alpha1 > M_PI) alpha1 = 2.0*M_PI - alpha1; return alpha1 < (110.0/180.0 * M_PI); } CPoint TAnalysePicture::FindAcceptDot(CPoint dot, double alpha, bool type) //Поиск продолжения из окончания/раздвоения { const int maxL = 11; const int minL = 3; COLORREF color; color = (type)?0x000000:0xffffff; //окончание - ищем черную точку //раздвоение - ищем белую точку int i = 0; while (i<=6) //разброс поиска в указанном направлении alpha { int l = minL; int k = (i+1) / 2; if (i % 2 == 1) k = -k; while (l<=maxL) { double arg = alpha + k * M_PI * 5.0/180.0; int x = dot.x + (int)(l*cos(arg)+0.5); int y = dot.y - (int)(l*sin(arg)+0.5); if (tmpPic->GetPixel(x, y) == color) //важное условие цвета точки!!! { if(TestFindDot(x,y)) //проверка найденной точки (на "вшивость" :) ) return CPoint(x, y); //найденная точка else break; } l++; //увеличение дальности поиска } i++; } return CPoint(-1, -1); //точка не найдена } bool TAnalysePicture::Show(int x, int y, int xt, int yt) { if(xt!=-1) pic2->Show(xt, yt); return pic->Show(x, y); } TFingPicture *TAnalysePicture::GetPic1() { return pic; } TFingPicture *TAnalysePicture::GetPic2() { return pic2; } double TAnalysePicture::ChangeAlphaInterval(double _alpha) //Приведение итрервала к [-pi,pi) { double ret = abs(_alpha); while(ret >= 2.0*M_PI) ret -= 2.0*M_PI; if(ret > M_PI) ret = 2.0*M_PI - ret; else ret = -ret; if(_alpha > 0) ret = -ret; return ret; } /*Фильтрование полученных точек отсеиваются близкостоящие направленные в противоположные строки а так же точки слева и справа от которых нет линий*/ int TAnalysePicture::DotsFilter(TAbsFing &_dots) { int leftDots = 0; TAbsFing::iterator iter1; TAbsFing::iterator iter2; for(iter1 = _dots.begin(); iter1 != _dots.end(); iter1++) { if(!iter1->show) continue; //отсев точек сложным условием (условие окружения) iter1->show = LeftDot(iter1); } for(iter1 = _dots.begin(); iter1 != _dots.end(); iter1++) { if(!iter1->show) continue; //отсев близкостоящих точек for(iter2 = iter1, ++iter2; iter2 != _dots.end(); iter2++) { if(!iter2->show) continue; double difL = GetS(iter1->coord,iter2->coord); if( //условия отсева ( //на близком растоянии (15) находятся два окончания/раздвоения направленных друг на друга (difL < 15)&& ((abs(iter2->alpha - iter1->alpha) > (165.0/180.0*M_PI))&&(abs(iter2->alpha - iter1->alpha)<(195.0/180.0*M_PI))) ) || ( //или просто очень близкие точки (<5..10) (difL < 10)&&(iter1->type == iter2->type) ) ) { iter1->show = false; iter2->show = false; } } } return leftDots; } inline double TAnalysePicture::GetS(CPoint A, CPoint B) //растояние между точками { return sqrt( (double)((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y)) ); } /*Если точка является окончанием, то слева и справа от нее должны быть линии если это не так, то точку нужно исключить из дальнейшего анализа*/ bool TAnalysePicture::LeftDot(TAbsFing::iterator &iter) { COLORREF color = 0x000000; //ищем черную точку для окончаний if(!iter->type) color = 0xffffff;; //ищем белую точку для раздвоений int l, k = 35; const int minL = 4, maxL = 12; bool find = false; while(k <= 55) { l = minL; while(l <= maxL) { int x = iter->coord.x + (int)(l*cos(iter->alpha + k/180.0*M_PI)+0.5); int y = iter->coord.y - (int)(l*sin(iter->alpha + k/180.0*M_PI)+0.5); if(pic->GetPixel(x,y) == color) // важное условие!!! { find = true; break;} //нашли точку слева l++; } if(find) break; k += 10; //Поиск с шагом 10гр } if(!find) return false; k = 35; while(k <= 55) { l= minL; while(l <= maxL) { int x = iter->coord.x + (int)(l*cos(iter->alpha - k/180.0*M_PI)+0.5); int y = iter->coord.y - (int)(l*sin(iter->alpha - k/180.0*M_PI)+0.5); if(pic->GetPixel(x,y) == color) // важное условие!!! return true; //нашли точку справа l++; } k += 10; } return false; }
Популярное: Модели организации как закрытой, открытой, частично открытой системы: Закрытая система имеет жесткие фиксированные границы, ее действия относительно независимы... Почему люди поддаются рекламе?: Только не надо искать ответы в качестве или количестве рекламы... Почему двоичная система счисления так распространена?: Каждая цифра должна быть как-то представлена на физическом носителе... ©2015-2024 megaobuchalka.ru Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. (174)
|
Почему 1285321 студент выбрали МегаОбучалку... Система поиска информации Мобильная версия сайта Удобная навигация Нет шокирующей рекламы |