Хочу расписать два метода поиска углов черного прямоугольника, вписанного в растровую карту.
Метод первый. поиск углов по несовпадению с фоном.
грубый метод, но можно использовать его для предварительной оценки, а затем более точный метод.
используем паттерн предполагающий не сильный наклон сторон прямоугольника.
- Код: Выделить всё
фон фон фон фон фон фон
фон фон фон фон фон фон
фон фон фон ... ... ...
фон фон ... ЦВТ ... ...
фон фон ... ... ... ...
фон фон ... ... ... ...
при совпадении с паттерном считаем точку с надписью ЦВТ углом. ЦВЕТ в этой точке должен отличаться от фонового, а при грязном фоне желательно еще задать порог
Создаем маски для трех каналов цвета и 4х углов
- Код: Выделить всё
const BYTE P1Mask[6][18]=
{{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}};
const BYTE P2Mask[6][18]=
{{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}};
const BYTE P3Mask[6][18]=
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}};
const BYTE P4Mask[6][18]=
{{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}};
искать будем в пределах 500 пикселов от углов изображения на примере фона 0xFF в каждом цветовом канале
- Код: Выделить всё
int x,y,w,h;
w=img->Picture->Width;
h=img->Picture->Height;
x=-3;y=-3;
while(!Pattern11(img,x,y))
{
x++;
if(x>500) {x=-3;y++;}
if(y>500) return false;
}
x=w-3;y=-3;
while(!Pattern12(img,x,y))
{
x--;
if(x<w-500) {x=w-3;y++;}
if(y>500) return false;
}
x=w-3;y=h-3;
while(!Pattern13(img,x,y))
{
x--;
if(x<w-500) {x=w-3;y--;}
if(y<h-500) return false;
}
x=-3;y=h-3;
while(!Pattern14(img,x,y))
{
x++;
if(x>500) {x=-3;y--;}
if(y<h-500) return false;
}
Mem->Lines->Add("("+IntToStr(Corn1X)+","+IntToStr(Corn1Y)+"),("
+IntToStr(Corn2X)+","+IntToStr(Corn2Y)+"),("
+IntToStr(Corn3X)+","+IntToStr(Corn3Y)+"),("
+IntToStr(Corn4X)+","+IntToStr(Corn4Y)+")");
Pattern21(img);
Pattern22(img);
Pattern23(img);
Pattern24(img);
Mem->Lines->Add("("+IntToStr(Corn1X)+","+IntToStr(Corn1Y)+"),("
+IntToStr(Corn2X)+","+IntToStr(Corn2Y)+"),("
+IntToStr(Corn3X)+","+IntToStr(Corn3Y)+"),("
+IntToStr(Corn4X)+","+IntToStr(Corn4Y)+")");
return true;
Придется залезть за пределы изображения, иначе мы не найдем углы в районе 1-3 пикселов от края. будем в этом случае принимать цвет за фон.
- Код: Выделить всё
//---------------------------------------------------------------------------
BYTE* __fastcall TForm1::PatGet(TImage* img,int Y)
{
BYTE* res=NULL;
int h=img->Picture->Height;
if(0<=Y && Y<h) res=(BYTE*)img->Picture->Bitmap->ScanLine[Y];
return res;
}
//---------------------------------------------------------------------------
BYTE __fastcall TForm1::ByteGet(TImage* img,BYTE* Patt,int X,int Bkg)
{
int w=img->Picture->Width;
BYTE res=Bkg;
if(Patt!=NULL) if(X>=0 && X<w*3) res=(BYTE)Patt[X];
return res;
}
Теперь ищем углы
- Код: Выделить всё
//---------------------------------------------------------------------------
bool __fastcall TForm1::Pattern11(TImage* img,int imX,int imY)
{
BYTE Bkg=0xFA;
BYTE* Ptrs[6];
BYTE* PP;
int i,j,k;
for(i=0;i<6;i++) Ptrs[i]=PatGet(img,imY+i);
int Cnt=0;
for(i=0;i<3;i++)
if(ByteGet(img,Ptrs[3],(imX+3)*3+i,Bkg)==Bkg) Cnt++;
if(Cnt==3) return false;
for(i=0;i<3;i++) for(j=0;j<imX;j++)
if(ByteGet(img,Ptrs[3],j*3+i,Bkg)!=Bkg) return false;
for(j=0;j<imY;j++)
{
PP=PatGet(img,j);
for(i=0;i<3;i++)
if(ByteGet(img,PP,(imX+3)*3+i,Bkg)!=Bkg) return false;
}
PP=PatGet(img,imY+20);
for(i=0;i<3;i++) for(j=0;j<imX-10;j++)
if(ByteGet(img,PP,j*3+i,Bkg)!=Bkg) return false;
for(i=0;i<6;i++) for(j=0;j<18;j++)
if((ByteGet(img,Ptrs[i],imX*3+j,Bkg)&P1Mask[i][j])!=(Bkg&P1Mask[i][j])) return false;
Corn1X=imX+3;
Corn1Y=imY+3;
for(i=3;i<6;i++) for(j=0;j<3;j++) if(ByteGet(img,Ptrs[2],(imX+i)*3+j,Bkg)!=Bkg) Corn1Y=imY+2;
for(i=3;i<6;i++) for(j=0;j<3;j++) if(ByteGet(img,Ptrs[i],(imX+2)*3+j,Bkg)!=Bkg) Corn1X=imX+2;
return true;
}
//---------------------------------------------------------------------------
bool __fastcall TForm1::Pattern12(TImage* img,int imX,int imY)
{
BYTE Bkg=0xFA;
BYTE* Ptrs[6];
BYTE* PP;
int w=img->Picture->Width;
int i,j,k;
for(i=0;i<6;i++) Ptrs[i]=PatGet(img,imY+i);
int Cnt=0;
for(i=0;i<3;i++)
if(ByteGet(img,Ptrs[3],(imX+2)*3+i,Bkg)==Bkg) Cnt++;
if(Cnt==3) return false;
for(i=0;i<3;i++) for(j=imX+6;j<w;j++)
if(ByteGet(img,Ptrs[3],j*3+i,Bkg)!=Bkg) return false;
for(j=0;j<imY;j++)
{
PP=PatGet(img,j);
for(i=0;i<3;i++)
if(ByteGet(img,PP,(imX+2)*3+i,Bkg)!=Bkg) return false;
}
PP=PatGet(img,imY+20);
for(i=0;i<3;i++) for(j=imX+16;j<w;j++)
if(ByteGet(img,PP,j*3+i,Bkg)!=Bkg) return false;
for(i=0;i<6;i++) for(j=0;j<18;j++)
if((ByteGet(img,Ptrs[i],imX*3+j,Bkg)&P2Mask[i][j])!=(Bkg&P2Mask[i][j])) return false;
Corn2X=imX+2;
Corn2Y=imY+3;
for(i=0;i<3;i++) for(j=0;j<3;j++) if(ByteGet(img,Ptrs[2],(imX+i)*3+j,Bkg)!=Bkg) Corn2Y=imY+2;
for(i=3;i<6;i++) for(j=0;j<3;j++) if(ByteGet(img,Ptrs[i],(imX+3)*3+j,Bkg)!=Bkg) Corn2X=imX+3;
return true;
}
//---------------------------------------------------------------------------
bool __fastcall TForm1::Pattern13(TImage* img,int imX,int imY)
{
BYTE Bkg=0xFA;
BYTE* Ptrs[6];
BYTE* PP;
int w=img->Picture->Width;
int h=img->Picture->Height;
int i,j,k;
for(i=0;i<6;i++) Ptrs[i]=PatGet(img,imY+i);
int Cnt=0;
for(i=0;i<3;i++)
if(ByteGet(img,Ptrs[2],(imX+2)*3+i,Bkg)==Bkg) Cnt++;
if(Cnt==3) return false;
for(i=0;i<3;i++) for(j=imX+6;j<w;j++)
if(ByteGet(img,Ptrs[2],j*3+i,Bkg)!=Bkg) return false;
for(j=imY+6;j<h;j++)
{
PP=PatGet(img,j);
for(i=0;i<3;i++)
if(ByteGet(img,PP,(imX+2)*3+i,Bkg)!=Bkg) return false;
}
PP=PatGet(img,imY-14);
for(i=0;i<3;i++) for(j=imX+16;j<w;j++)
if(ByteGet(img,PP,j*3+i,Bkg)!=Bkg) return false;
for(i=0;i<6;i++) for(j=0;j<18;j++)
if((ByteGet(img,Ptrs[i],imX*3+j,Bkg)&P3Mask[i][j])!=(Bkg&P3Mask[i][j])) return false;
Corn3X=imX+2;
Corn3Y=imY+2;
for(i=0;i<3;i++) for(j=0;j<3;j++) if(ByteGet(img,Ptrs[3],(imX+i)*3+j,Bkg)!=Bkg) Corn3Y=imY+3;
for(i=0;i<3;i++) for(j=0;j<3;j++) if(ByteGet(img,Ptrs[i],(imX+3)*3+j,Bkg)!=Bkg) Corn3X=imX+3;
return true;
}
//---------------------------------------------------------------------------
bool __fastcall TForm1::Pattern14(TImage* img,int imX,int imY)
{
BYTE Bkg=0xFA;
BYTE* Ptrs[6];
BYTE* PP;
int h=img->Picture->Height;
int i,j,k;
for(i=0;i<6;i++) Ptrs[i]=PatGet(img,imY+i);
int Cnt=0;
for(i=0;i<3;i++)
if(ByteGet(img,Ptrs[2],(imX+3)*3+i,Bkg)==Bkg) Cnt++;
if(Cnt==3) return false;
for(i=0;i<3;i++) for(j=0;j<imX;j++)
if(ByteGet(img,Ptrs[2],j*3+i,Bkg)!=Bkg) return false;
for(j=imY+6;j<h;j++)
{
PP=PatGet(img,j);
for(i=0;i<3;i++)
if(ByteGet(img,PP,(imX+3)*3+i,Bkg)!=Bkg) return false;
}
PP=PatGet(img,imY-14);
for(i=0;i<3;i++) for(j=0;j<imX-10;j++)
if(ByteGet(img,PP,j*3+i,Bkg)!=Bkg) return false;
for(i=0;i<6;i++) for(j=0;j<18;j++)
if((ByteGet(img,Ptrs[i],imX*3+j,Bkg)&P4Mask[i][j])!=(Bkg&P4Mask[i][j])) return false;
Corn4X=imX+3;
Corn4Y=imY+2;
for(i=3;i<6;i++) for(j=0;j<3;j++) if(ByteGet(img,Ptrs[3],(imX+i)*3+j,Bkg)!=Bkg) Corn4Y=imY+3;
for(i=0;i<3;i++) for(j=0;j<3;j++) if(ByteGet(img,Ptrs[i],(imX+2)*3+j,Bkg)!=Bkg) Corn4X=imX+2;
return true;
}
Здесь приведена последняя версия кода, убирающего большинство ошибок, когда изображение вылезает за рамки.
Если фон не однотонный, а грязный надо сравнивать не точно цвета а задавать доверительный интервал, но это уже другая история.