Хочу расписать два метода поиска углов черного прямоугольника, вписанного в растровую карту.
Метод первый. поиск углов по несовпадению с фоном.
грубый метод, но можно использовать его для предварительной оценки, а затем более точный метод.
используем паттерн предполагающий не сильный наклон сторон прямоугольника.
Код: Выделить всё
фон фон фон фон фон фон
фон фон фон фон фон фон
фон фон фон ... ... ...
фон фон ... ЦВТ ... ...
фон фон ... ... ... ...
фон фон ... ... ... ...
Создаем маски для трех каналов цвета и 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}};Код: Выделить всё
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;Код: Выделить всё
//---------------------------------------------------------------------------
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;
}Если фон не однотонный, а грязный надо сравнивать не точно цвета а задавать доверительный интервал, но это уже другая история.