1:BMP文件組成
BMP文件由文件頭、位圖信息頭、顏色信息和圖形數據四部分組成。
2:BMP文件頭(14字節)
BMP文件頭數據結構含有BMP文件的類型、文件大小和位圖起始位置等信息。
其結構定義如下:
typedef struct tagBITMAPFILEHEADER
{
WORD bfType; // 位圖文件的類型,必須為BM(1-2字節)
DWORD bfSize; // 位圖文件的大小,以字節為單位(3-6字節)
WORD bfReserved1; // 位圖文件保留字,必須為0(7-8字節)
WORD bfReserved2; // 位圖文件保留字,必須為0(9-10字節)
DWORD bfOffBits; // 位圖數據的起始位置,以相對于位圖(11-14字節)
// 文件頭的偏移量表示,以字節為單位
} BITMAPFILEHEADER;
3:位圖信息頭(40字節)
BMP位圖信息頭數據用于說明位圖的尺寸等信息。
typedef struct tagBITMAPINFOHEADER{
DWORD biSize; // 本結構所占用字節數(15-18字節)
LONG biWidth; // 位圖的寬度,以像素為單位(19-22字節)
LONG biHeight; // 位圖的高度,以像素為單位(23-26字節)
WORD biPlanes; // 目標設備的級別,必須為1(27-28字節)
WORD biBitCount;// 每個像素所需的位數,必須是1(雙色),(29-30字節)
// 4(16色),8(256色)或24(真彩色)之一
DWORD biCompression; // 位圖壓縮類型,必須是 0(不壓縮),(31-34字節)
// 1(BI_RLE8壓縮類型)或2(BI_RLE4壓縮類型)之一
DWORD biSizeImage; // 位圖的大小,以字節為單位(35-38字節)
LONG biXPelsPerMeter; // 位圖水平分辨率,每米像素數(39-42字節)
LONG biYPelsPerMeter; // 位圖垂直分辨率,每米像素數(43-46字節)
DWORD biClrUsed;// 位圖實際使用的顏色表中的顏色數(47-50字節)
DWORD biClrImportant;// 位圖顯示過程中重要的顏色數(51-54字節)
} BITMAPINFOHEADER;
4:顏色表
顏色表用于說明位圖中的顏色,它有若干個表項,每一個表項是一個RGBQUAD類型的結構,定義一種顏色。RGBQUAD結構的定義如下:
typedef struct tagRGBQUAD {
BYTE rgbBlue;// 藍色的亮度(值范圍為0-255)
BYTE rgbGreen; // 綠色的亮度(值范圍為0-255)
BYTE rgbRed; // 紅色的亮度(值范圍為0-255)
BYTE rgbReserved;// 保留,必須為0
} RGBQUAD;
顏色表中RGBQUAD結構數據的個數有biBitCount來確定:
當biBitCount=1,4,8時,分別有2,16,256個表項;
當biBitCount=24時,沒有顏色表項。
位圖信息頭和顏色表組成位圖信息,BITMAPINFO結構定義如下:
typedef struct tagBITMAPINFO {
BITMAPINFOHEADER bmiHeader; // 位圖信息頭
RGBQUAD bmiColors[1]; // 顏色表
} BITMAPINFO;
5:位圖數據
位圖數據記錄了位圖的每一個像素值,記錄順序是在掃描行內是從左到右,掃描行之間是從下到上。位圖的一個像素值所占的字節數:
當biBitCount=1時,8個像素占1個字節;
當biBitCount=4時,2個像素占1個字節;
當biBitCount=8時,1個像素占1個字節;
當biBitCount=24時,1個像素占3個字節;
Windows規定一個掃描行所占的字節數必須是
4的倍數(即以long為單位),不足的以0填充,
biSizeImage = ((((bi.biWidth * bi.biBitCount) + 31) & ~31) / 8) * bi.biHeight;
這個在百度百科大家可以做個詳細的了解,這里就不多說了。
驗證碼圖片:
1.預處理:
接下來就是對圖片進行讀取,
2.灰度化:
對其各個像素的GBR值進行灰度化處理,我用的公式是求平均值的方法,比較方便,效果也還不錯。,將求得的平均值存入一個二維數組中,方便后面的處理。
3.二值化
二值化有很多種算法,我試了試大津法(最大方差法)還有自適應閾值法,不知道什么原因,二值化出來的圖片簡直把圖片就給毀了。。。。最后還是將圖片的GBR信息打印出來,自己找了個臨界值,效果還不錯,二值化之后的噪點也只有幾個。后面的處理就方便多了。將大于這個臨界值的像素點設為255,小于的設為0.出來的圖像就完全黑白二值了。
4.去噪
去噪,看了看幾張驗證碼,發現字母組成最少的就是i,j上面的點了,4個像素點組成,于是將圖片中一個像素點周圍的8個點進行判斷,如果這個點周圍有不超過三個黑點,則證明這個點為噪點,需要去除,需要注意的是邊界周圍只有5個點,需要進行判斷是否為邊界。
5.分割
因為我們的BMP圖片是有間據的,所以分割就用最簡單的一種了
先將去噪完后的BMP像素數組在按自左向右的基礎上從上往下找,找到的第一個黑點即為字符的左邊界,再向右,找到的一列全不為黑點的話,則上一列即為字符的右邊界,再在左邊界和右邊界的區間下,從下往上按行遍歷,找到字符的下邊界,再從上往下找到上邊界,其他字符同理。就可以將圖片分割出來了。
6.識別
我用的識別方法還是比較麻煩的,先是對驗證碼的字符進行輸出(0,1組成),然后再找他們之間的不同相似之處,所以不是很方便,這里也就不細提了,看代碼就應該理解了。
下面是代碼:
view plainprint?
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
using namespace std;
void OtsuThreshold(int *p_data)
{
int i,j;
int nWidth = 70;
int nHeight = 30;
for(j = 0;j < nHeight; j++)
{//二值化實現
for(i = 0; i < nWidth ; i++)
{
if(p_data[j * nWidth +i] < 38)
p_data[j * nWidth + i] = 0;
else
p_data[j * nWidth + i] = 255;
}
}
}
void Print(int graph[][70])
{ int i,j;
for(i = 0; i < 30; i++)
{ for(j = 0; j < 70; j++)
{
if(graph[i][j] == 255)
{
// printf(" ");
graph[i][j] = 1;
}
// else printf("*");
}
// printf("\n");
}
// printf("\n\n\n\n");
}
void duibi(int z[][20][20],int bl1,int br1,int bl2,int br2,int bl3,int br3,int bl4,int br4)
{
int jianju[4];
int i;
jianju[0] = br1-bl1+1;
jianju[1] = br2-bl2+1;
jianju[2] = br3-bl3+1;
jianju[3] = br4-bl4+1;
for(i = 0; i < 4; i++)
{
if(jianju[i] <= 5)//<=5 字符占 小于等于5列的
{
if(jianju[i] == 5)
{
if(z[i][0][0] == 0)
printf("r");
else if(z[i][0][1] == 1)
printf("i");
else printf("t");
}
else printf("i");
}
else if(jianju[i] == 6)//6 字符占 6列
{
if(z[i][0][1] == 0)
{
if(z[i][0][4] == 1)
printf("t");
else printf("s");
}
else if(z[i][0][2] == 1)
printf("j");
else if(z[i][0][4] == 1)
printf("t");
else printf("f");
}
else if(jianju[i] == 7)//7
{
if(z[i][0][0] == 1 && z[i][0][1] == 1 && z[i][0][2] == 1)
{
if(z[i][0][6] == 1)
printf("e");
else if(z[i][0][3] == 0 && z[i][0][4] == 0 && z[i][0][5] == 0 && z[i][0][6] == 0)printf("c");
else printf("f");
}
else if(z[i][0][0] == 1 && z[i][0][1] == 1)
{
if(z[i][0][5] == 1)
{
if(z[i][1][1] == 1)
printf("t");
else printf("e");
}
else if(z[i][0][4] == 1)
printf("r");
else printf("f");
}
else if(z[i][0][0] == 1)
{
printf("3");
}
else if(z[i][0][2] == 1 && z[i][0][3] == 0)
printf("p");
else if(z[i][0][0] == 0 && z[i][0][1] == 0 && z[i][0][2] == 0)printf("z");
else if(z[i][0][0] == 0 && z[i][0][1] == 0 && z[i][0][2] == 1 && z[i][0][3] == 1) printf("h");
else printf("r");
}
else if(jianju[i] == 8)//8
{
if(z[i][0][0] == 1 && z[i][1][1] == 1 && z[i][2][2] == 1 && z[i][3][3] == 1)
printf("j");
else if(z[i][0][0] == 1 && z[i][1][1] == 1 && z[i][2][2] == 1)
printf("d");
else if(z[i][0][0] == 1 && z[i][1][1] == 1)
{
if(z[i][3][3] == 1 &&z[i][4][4] == 1)
printf("c");
else if(z[i][3][3] == 1 && z[i][4][4] ==0)printf("a");
else printf("f");
}
else if(z[i][0][0] == 1 && z[i][2][2] == 1)
{
if(z[i][1][0] == 0) printf("3");
else if(z[i][4][4] == 1 && z[i][0][1] == 0)
printf("2");
else printf("a");
}
else if(z[i][0][0] == 1 && z[i][6][6] == 1)
printf("c");
else if(z[i][0][0] == 1 && z[i][3][3] == 1)
printf("g");
else if(z[i][0][0] == 1)
printf("s");
else if(z[i][1][1] == 1)
printf("2");
else if(z[i][2][2] != 1)
printf("n");
else if(z[i][4][4] == 1)
{
if(z[i][5][5] == 1) printf("u");
else printf("7");
}
else if(z[i][7][7] == 1) printf("z");
else printf("h");
}
else if(jianju[i] == 9) //9
{
if(z[i][0][0] == 1 && z[i][3][3] == 1 && z[i][4][4] == 0 && z[i][5][5] == 0 && z[i][6][6] == 0 && z[i][7][7] ==0 && z[i][8][8] == 0)
printf("a");
else if(z[i][2][2] == 0 && z[i][3][3] ==1 && z[i][4][4] == 0 && z[i][5][5] == 0 && z[i][6][6] == 1 && z[i][7][7] == 1)
printf("e");
else if(z[i][0][0] == 1 && z[i][1][1] == 1 &&z[i][2][2]== 1)
printf("d");
else if(z[i][1][1] == 0 && z[i][2][2] == 0 && z[i][4][4] ==1 && z[i][5][5] == 1 && z[i][7][7] == 0)
{
if(z[i][0][5] == 1) printf("g");
else if(z[i][0][7] == 0) printf("n");
else printf("p");
}
else if(z[i][0][0] ==0 && z[i][1][1] == 0 && z[i][3][3] == 1 && z[i][4][4] == 1 && z[i][5][5] == 0 && z[i][7][7] ==1 && z[i][8][8] ==1)
{
if(z[i][0][3] == 1 && z[i][10][0] == 0)
printf("v");
else if(z[i][0][3] == 1 && z[i][10][0] == 1) printf("y");
else printf("7");
}
else if(z[i][0][0] == 0 && z[i][1][1] ==0 && z[i][2][2] ==0 && z[i][3][3] ==1 &&z[i][4][4] == 1)
{
printf("y");
}
else if(z[i][0][0] == 1 && z[i][1][1] ==1 && z[i][2][2] == 0)
{
if(z[i][3][3] == 1)printf("6");
else if(z[i][4][4] == 1)printf("k");
else if(z[i][5][5] == 1 && z[i][12][4] == 1)printf("h");
else if(z[i][12][4] == 0 && z[i][12][2] == 1) printf("b");
else printf("s");
}
else if(z[i][0][0] == 1 && z[i][1][1] == 0)
{
if(z[i][2][2] == 1)
{
if(z[i][4][4] ==1 ) printf("2");
else printf("z");
}
else if(z[i][3][3] == 0)printf("r");
else printf("8");
}
else printf("b");
}
else if(jianju[i] == 10) //10
{
if(z[i][0][0] == 1 && z[i][1][1] == 1 && z[i][2][2] == 1)
{
if(z[i][3][3] == 1) printf("d");
else printf("x");
}
else if(z[i][0][0] == 1 && z[i][1][1] == 1 && z[i][2][2] == 0)
{
if(z[i][3][3] == 1 && z[i][10][0] == 0)printf("3");
else if(z[i][3][3] == 1 && z[i][10][0] == 1) printf("2");
else if(z[i][4][4] == 1 && z[i][5][5] == 1 && z[i][6][6] ==1)printf("p");
else if(z[i][6][6] == 1) printf("b");
else if(z[i][5][5] == 1) printf("k");
else if(z[i][9][9] == 1) printf("5");
else if(z[i][4][4] == 1) printf("6");
else printf("8");
}
else if(z[i][0][0] == 1 && z[i][1][1] == 0)
{
if(z[i][2][2] == 0)printf("n");
else if(z[i][4][4] == 1) printf("7");
else printf("z");
}
else if(z[i][5][5] == 0) printf("x");
else if(z[i][12][0] == 1) printf("y");
else printf("v");
}
else if(jianju[i] == 11)//11
{
if(z[i][0][2] == 1)
{
if(z[i][0][3] == 1)
printf("4");
else printf("2");
}
else if(z[i][0][8] == 1)
printf("x");
else printf("u");
}
else if(jianju[i] >=13)//>=13
{
if(jianju[i] == 13||jianju[i] == 15)
{
if(jianju[i] == 15)
if(z[i][0][0] == 1) printf("m");
else printf("w");
}
else if(jianju[i] == 14)
printf("m");
else if(z[i][0][0] == 1)
printf("m");
else printf("w");
}
}
}
int main(int argc,char *argv[])
{
FILE *fp;
int rgb[30*70];
int gbr[30 * (70*3)];
int graph[30][70] = {0};
int g=0,b=0,r=0;
int i,j,n,a,d,k;
int Height,Width;
int bl1=0,br1=0,bg1=0,bd1=0,bl2=0,br2=0,bg2=0,bd2=0;
int bl3=0,br3=0,bg3=0,bd3=0,bl4=0,br4=0,bg4=0,bd4=0;
int z[4][20][20] = {0};
// memset(z,0,sizeof(z));
fp = fopen(argv[1],"rb");
if(fp == NULL)
cout<<"read error!";
fseek(fp,18,0);
fread(&Width,4,1,fp);
fread(&Height,4,1,fp);
fseek(fp,54,0);
for(i = 0; i < 30 ; i++)//讀取圖片進行灰度化并保存到rgb數組
{ for(j = 0; j < 70; j++)
{
fread(&g,1,1,fp);
fread(&b,1,1,fp);
fread(&r,1,1,fp);
rgb[i * 70 + j]=(g+b+r)/3;//灰度化
}
fseek(fp,2,1);
}
OtsuThreshold(rgb);//二值化
for(i = 0; i < Height; i++)
{
for(j = 0; j < Width; j++)
graph[30-1-i][j] = rgb[i * 70 + j];
}
//輸出圖片
Print(graph);
//去噪
for(i = 0; i < 30; i++)
{
for(j = 0; j < 70; j++)
{ n = 0;
if(i == 29)
{
if(graph[i][j] == 0 && graph[i][j-1] != 0 && graph[i][j+1] != 0 && graph[i-1][j] != 0)
graph[i][j] = 1;
if(graph[i][j] == 0)
{ n = 0;
if(graph[i-1][j-1] == 0 )
n++;
if(graph[i-1][j] == 0)
n++;
if(graph[i-1][j+1] == 0)
n++;
if(graph[i][j-1] == 0)
n++;
if(graph[i][j+1] == 0)
n++;
if(n < 2)
graph[i][j] = 1;
}
}
/* if(graph[i][j] == 0 && graph[i-1][j-1] != 0 && graph[i-1][j] != 0 && graph[i-1][j+1] != 0 && graph[i][j-1] != 0 && graph[i][j+1] != 0 && graph[i+1][j-1] != 0 && graph[i+1][j] != 0 && graph[i+1][j+1] != 0)
graph[i][j] = 1;
*/
if(graph[i][j] == 0)
{ n = 0;
if(graph[i-1][j-1] == 0 )
n++;
if(graph[i-1][j] == 0)
n++;
if(graph[i-1][j+1] == 0)
n++;
if(graph[i][j-1] == 0)
n++;
if(graph[i][j+1] == 0)
n++;
if(graph[i+1][j-1] == 0)
n++;
if(graph[i+1][j] == 0)
n++;
if(graph[i+1][j+1] == 0)
n++;
if(n < 2)
graph[i][j] = 1;
}
}
}
//第一個字符
// 左邊界
for(i = 0; i < Width; i++)
{
for(j = 0; j < Height; j++)
{
if(graph[j][i] == 0)
{
bl1 = i;
break;
}
}
if(bl1 != 0)
break;
}
//右邊界
for(i = bl1; i < Width; i++)
{
n = 0;
for(j = 0; j < Height; j++)
{
if(graph[j][i] == 0)
n++;
}
if(n == 0)
{
br1 = i-1;
break;
}
}
//上邊界
for(i = 0; i < Height; i++ )
{ n = 0;
for(j = bl1; j <= br1; j++)
{
if(graph[i][j] == 0)
{ bg1 = i;
n = 1;
break;
}
}
if(n != 0)
break;
}
//下邊界
for(i = Height-1; i >= 0 ; i--)
{
n = 0;
for(j = bl1; j <= br1; j++)
{
if(graph[i][j] == 0)
{
bd1 = i;
n = 1;
break;
}
}
if(n != 0)
break;
}
//第二個字符
//左邊界
for(i = br1+1; i < Width; i++)
{
for(j = 0; j < Height; j++)
{
if(graph[j][i] == 0)
{
bl2 = i;
break;
}
}
if(bl2 != 0)
break;
}
//右邊界
for(i = bl2; i < Width; i++)
{
n = 0;
for(j = 0; j < Height; j++)
{
if(graph[j][i] == 0)
n++;
}
if(n == 0)
{
br2 = i-1;
break;
}
}
//上邊界
for(i = 0; i < Height; i++)
{ n = 0;
for(j = bl2; j <= br2; j++)
{
if(graph[i][j] == 0)
n++;
}
if(n != 0)
{ bg2 = i;
break;
}
}
//下邊界
for(i = Height-1; i >= 0; i--)
{ n = 0;
for(j = bl2; j <= br2; j++)
{
if(graph[i][j] == 0)
{ n = 1;
bd2 = i;
}
}
if(n != 0)
break;
}
//第三個字符
//左邊界
for(i = br2+1; i < Width; i++)
{
for(j = 0; j < Height; j++)
{
if(graph[j][i] == 0 )
{ bl3 = i;
break;
}
}
if(bl3 != 0)
break;
}
//右邊界
for(i = bl3; i < Width; i++)
{ n = 0;
for(j = 0; j < Height; j++)
{
if(graph[j][i] == 0)
{
n++;
break;
}
}
if(n == 0)
{
br3 = i-1;
break;
}
}
//上邊界
for(i = 0; i < Height; i++)
{
for(j = bl3; j <= br3; j++)
{
if(graph[i][j] == 0)
{
bg3 = i;
break;
}
}
if(bg3 != 0)
break;
}
//下邊界
for(i = Height-1; i >= 0; i--)
{ n = 0;
for(j = bl3; j <= br3; j++)
{
if(graph[i][j] == 0)
{ n = 1;
bd3 = i;
break;
}
}
if(n != 0)
break;
}
//第四個字符
//左邊界
for(i = br3+1; i < Width; i++)
{
for(j = 0; j < Height; j++)
{
if(graph[j][i] == 0)
{
bl4 = i;
break;
}
}
if(bl4 != 0)
break;
}
//右邊界
for(i = bl4; i < Width; i++)
{ n = 0;
for(j = 0; j < Height; j++)
{
if(graph[j][i] == 0)
{ n++;
break;
}
}
if(n == 0)
{
br4 = i-1;
break;
}
}
if(i == Width)
br4 = Width-1;
//上邊界
for(i = 0; i < Height; i++)
{
for(j = bl4; j <= br4; j++)
{
if(graph[i][j] == 0)
{
bg4 = i;
break;
}
}
if(bg4 != 0)
break;
}
//下邊界
for(i = Height-1; i >= 0; i--)
{ n = 0;
for(j = bl4; j <= br4; j++)
{
if(graph[i][j] == 0)
{
n = 1;
bd4 = i;
break;
}
}
if(n != 0)
break;
}
//輸出圖片
//Print(graph);
//將圖片保存到z【】【】【】數組中
for(i = bg1,a = 0;i <= bd1; i++,a++)
{ for(j = bl1,d = 0; j <= br1; j++,d++)
z[0][a][d] = graph[i][j];
}
for(i = bg2,a = 0;i <= bd2; i++,a++)
{ for(j = bl2,d = 0; j <= br2; j++,d++)
z[1][a][d] = graph[i][j];
}
for(i = bg3,a = 0;i <= bd3; i++,a++)
{ for(j = bl3,d = 0; j <= br3; j++,d++)
z[2][a][d] = graph[i][j];
}
for(i = bg4,a = 0;i <= bd4; i++,a++)
{ for(j = bl4,d = 0; j <= br4; j++,d++)
z[3][a][d] = graph[i][j];
}
duibi(z,bl1,br1,bl2,br2,bl3,br3,bl4,br4);
printf("\n");
/* for(i = 0; i < 4; i++)
{
for(j = 0; j < 20; j++)
{ for(k = 0; k < 20; k++)
if(z[i][j][k] == 1)
printf("1,");
else printf("0,");
printf("\n");
}
printf("\n");
}
*/
cout<<endl;
fclose(fp);
return (0);
}
回復 更多評論