#include "SWT.h"
#include "ConnectDomain.h"
int cmp(const void *a , const void *b)
{
float* x=(float*)a;
float* y=(float*)b;
if(*x<*y)return -1;
else return 1;
}
void CSWT::loadImage(const string path)
{
srcImage=imread(path);
}
void CSWT::loadImage(char* path)
{
srcImage=imread(path);
}
void CSWT::loadImage(const Mat& im)
{
im.copyTo(srcImage);
}
void CSWT::grayImage()
{
imshow("original", srcImage);
cvtColor(srcImage, grayImage8U, CV_BGR2GRAY);
grayImage8U.convertTo(grayImage32F, CV_32FC1);
height=srcImage.rows;
width=srcImage.cols;
}
void CSWT::computeGradient()//计算梯度方向角度
{
Canny(grayImage8U, edgeImage, 30, 90);
Sobel(grayImage32F, gradient_dx, grayImage32F.depth(), 1, 0);
Sobel(grayImage32F, gradient_dy, grayImage32F.depth(), 0, 1);
angle.create(grayImage32F.size(), grayImage32F.type());
for(int h=0; h<height; ++h)
{
for(int w=0; w<width; ++w)
{
if(edgeImage.at<uchar>(h,w))
angle.at<float>(h,w)=atan2(gradient_dy.at<float>(h,w), gradient_dx.at<float>(h,w))/*/PI*180+180*/; //atan2()返回值(-PI,PI)
else angle.at<float>(h,w)=0.0f;
}
}
}
void CSWT::computeSWT()
{
Mat tmp_SWTMap(grayImage32F.size(), grayImage32F.type(), Scalar(INF));
float strokeWidth;
int initialX,initialY;
int nextX, nextY;
int step;
float initialTheta;
int* rayX=new int[maxStrokeWidth];
int* rayY=new int[maxStrokeWidth];
int indexRay;
float oppositeTheta;
int strokePointsX[100000];//每条射线的起点坐标(注意此处射线起点可能过多)
int strokePointsY[100000];
int indexStrokePoints=0;//记录有多少笔画边缘点,即射线起点
//第一次扫描
for(int h=0; h<height; ++h)
{
for(int w=0; w<width; ++w)
{
if(edgeImage.at<uchar>(h,w))
{
initialX=w;
initialY=h;
initialTheta=angle.at<float>(initialY,initialX);
indexRay=0;
step=1;
rayX[indexRay]=initialX;
rayY[indexRay]=initialY;
indexRay++;
while (step<maxStrokeWidth)
{
nextX = (int)(initialX + cos(initialTheta) * searchDirection * step);
nextY = (int)(initialY + sin(initialTheta) * searchDirection * step);
step++;
if(nextY<0||nextX<0||nextX>=width||nextY>=height)
{
break;
}
rayX[indexRay]=nextX;
rayY[indexRay]=nextY;
indexRay++;
if(edgeImage.at<uchar>(nextY,nextX))
{
oppositeTheta=angle.at<float>(nextY,nextX);
//if(fabs(initialTheta+oppositeTheta)<PI/4)
if (abs(abs(initialTheta - oppositeTheta) - PI) < PI/3)
{
strokeWidth=sqrt((nextX-initialX)*(nextX-initialX)+(nextY-initialY)*(nextY-initialY));
for(int i=0; i<indexRay; ++i)//给射线上的所有点赋值
{
tmp_SWTMap.at<float>(rayY[i],rayX[i])=min(tmp_SWTMap.at<float>(rayY[i],rayX[i]),strokeWidth);
}
strokePointsX[indexStrokePoints]=initialX;
strokePointsY[indexStrokePoints]=initialY;
indexStrokePoints++;
}
break;
}
}//while
}
}//for(w)
}
for(int h=0; h<height; ++h)
{
for(int w=0; w<width; ++w)
{
if (tmp_SWTMap.at<float>(h,w)==INF)
{
tmp_SWTMap.at<float>(h,w)=0;
}
}
}
//第二次扫描,每条射线上大于射线中值的像素值赋为中值
int* arryMedian=new int[maxStrokeWidth];
int indexMedian=0;
for(int i=0; i<indexStrokePoints; ++i)
{
step=1;
indexRay=0;
indexMedian=0;
initialX=strokePointsX[i];
initialY=strokePointsY[i];
initialTheta=angle.at<float>(initialY,initialX);
rayX[indexRay]=initialX;
rayY[indexRay]=initialY;
indexRay++;
arryMedian[indexMedian++]=tmp_SWTMap.at<float>(initialY, initialX);
while (step<maxStrokeWidth)//找同一条射线上所有笔画宽度
{
nextX = (int)(initialX + cos(initialTheta) * searchDirection * step);
nextY = (int)(initialY + sin(initialTheta) * searchDirection * step);
step++;
rayX[indexRay]=nextX;
rayY[indexRay]=nextY;
indexRay++;
arryMedian[indexMedian++]=tmp_SWTMap.at<float>(nextY,nextX);
if(edgeImage.at<uchar>(nextY, nextX))
break;
}
qsort(arryMedian,indexMedian,sizeof(float) , cmp);
float medianVal = arryMedian[indexMedian/2];
for(int j=0; j<indexRay; ++j)
{
tmp_SWTMap.at<float>(rayY[j], rayX[j])=min(tmp_SWTMap.at<float>(rayY[j], rayX[j]),medianVal);
}
}
for(int h=0; h<height; ++h)
{
for(int w=0; w<width; ++w)
{
if (tmp_SWTMap.at<float>(h,w)>maxStrokeWidth)
{
tmp_SWTMap.at<float>(h,w)=0;
}
}
}
imshow("swtMap", tmp_SWTMap);
//dilate(tmp_SWTMap, tmp_SWTMap, cv::Mat(), cv::Point(-1,-1), 1);
Mat ker_x=(Mat_<int>(1,3)<<1,1,1);
Mat ker_y=(Mat_<int>(2,1)<<1,1);
cv::dilate(tmp_SWTMap, tmp_SWTMap, ker_x, Point(-1,-1),1);
cv::dilate(tmp_SWTMap, tmp_SWTMap, ker_y, Point(-1,-1),1);
tmp_SWTMap.copyTo(SWTMap);
delete []arryMedian;
delete []rayX;
delete []rayY;
}
void CSWT::computeConnDomain()
{
//注意:相连的区域不一定就是同一连通域
labelMap = connDomain(SWTMap, connCount);
cout << "connCount = " << connCount << endl;
imshow("labelMap",labelMap);
}
void CSWT::filterConnDomain()
{
//第一步:计算各个连通域的属性:
//varianceSW:连通域笔画的方差。meanSW:连通域笔画的均值。
//aspectRatio:连通域高宽比。diameter:连通域直径。
//width:连通域宽。height:连通域高
connAttri=new connAttribute[connCount+1];
//初始化属性列表
for(int i=1; i<=connCount; ++i)
{
connAttri[i].varianceSW = 0.0;
connAttri[i].meanSW = 0.0;
connAttri[i].aspectRatio = 0.0;
connAttri[i].areaRatio = 0.0;
connAttri[i].diameter = 0.0;
connAttri[i].totalSW = 0.0;
connAttri[i].width = 0;
connAttri[i].height = 0;
connAttri[i].num = 0;
connAttri[i].L = width;
connAttri[i].U = height;
connAttri[i].R = 0;
connAttri[i].D = 0;
connAttri[i].flag = true;
}
for(int h=0; h<height; ++h)
{
for(int w=0; w<width; ++w)
{
int k = labelMap.at<float>(h,w);
if(k)
{
connAttri[k].num++;
connAttri[k].totalSW+=SWTMap.at<float>(h,w);
if(connAttri[k].L>w)connAttri[k].L=w;
if(connAttri[k].R<w)connAttri[k].R=w;
if(connAttri[k].U>h)connAttri[k].U=h;
if(connAttri[k].D<h)connAttri[k].D=h;
}
}
}
//计算每个连通域的属性
for(int i=1; i<=connCount; ++i)
{
connAttri[i].width =connAttri[i].R-connAttri[i].L+1;
connAttri[i].height =connAttri[i].D-connAttri[i].U+1;
connAttri[i].cx =(connAttri[i].L+connAttri[i].R)/2;
connAttri[i].cy =(connAttri[i].U+connAttri[i].D)/2;
connAttri[i].aspectRatio =(float)connAttri[i].width/connAttri[i].height;
connAttri[i].areaRatio =(float)connAttri[i].num/(connAttri[i].width*connAttri[i].height);
connAttri[i].meanSW =connAttri[i].totalSW/connAttri[i].num;
connAttri[i].diameter =sqrt(connAttri[i].width*connAttri[i].width+connAttri[i].height*connAttri[i].height)/2;
}
//计算每个连通域的方差(近似计算)
for(int h=0; h<height; ++h)
{
for(int w=0; w<width; ++w)
{
int k = labelMap.at<float>(h,w);
if(k)
{
connAttri[k].varianceSW+=fabs(SWTMap.at<float>(h,w)-connAttri[k].meanSW);
}
}
}
Mat temp;
labelMap.copyTo(temp);
int num =0;
for(int h=0; h<height; ++h)
{
for(int w=0; w<width; ++w)
{
int k = labelMap.at<float>(h,w);
if(!k)continue;
if(connAttri[k].width<10||connAttri[k].height<15||connAttri[k].width>(width/3)||connAttri[k].height>(height/2)
||connAttri[k].num<30||connAttri[k].num>1600
||connAttri[k].aspectRatio<0.1||connAttri[k].aspectRatio>10.0
||connAttri[k].areaRatio<0.35||connAttri[k].meanSW>20|| connAttri[k].varianceSW>6000
//||connAttri[k].diameter/connAttri[k].meanSW>10.0
)
{
temp.at<float>(h,w)=0.0f;
connAttri[k].flag = false;
}
}
}
for(int i=1; i<=connCount; ++i)
{
if(connAttri[i].flag)
{
num++