误差可视化小结
误差可视化小结
问题描述
在做水印工作的时候,需要衡量原模型与水印模型之间的误差。为了更加直观的看出误差的大小,可以将误差进行可视化。下图是可视化误差的一个例子,其中左边的模型为原始模型A,右边第二行的模型是某个算法计算出的原模型的近似模型B,右边第三行的模型是一个有色的模型,通过颜色表示出模型A、B之间的误差,颜色条显示不同颜色与误差大小的关系。
在水印工作中,也许要对原始模型和水印模型的误差进行衡量,误差可简单计算为两个模型上对应点之间的欧氏距离。在计算误差之前,首先要确保两个模型已经对齐(最简单的处理可以将两个模型的中点放置在一起),代码如下:
//将两个模型的中心移到一起
//将原始中心读取出来
double *RCenter = new double[6];
char center_name[100];
ifstream centerfile;
sprintf(center_name, "D:\\code\\GeometryProcessing-1\\Txt\\Offset\\Center.txt");
centerfile.open(center_name,ios_base::in );
if (centerfile)
{
// read into memory
centerfile.seekg (0, centerfile.end);
int length = centerfile.tellg();
centerfile.seekg (0, centerfile.beg);
char *buffer = new char[length];
centerfile.read(buffer, length);
centerfile.close();
// parse into array
std::istringstream iss(buffer);
int i = 0;
while ( i < 6)
{
iss >> RCenter[i++];
}
delete [] buffer;
// print or use it.
}
centerfile.close();
double currEntityCenter[3]; //** store the center of current entity's bounding box *//
double firstMeshCenter[3];
entity_meshA->get_bb_center(firstMeshCenter);
for (int i = 0; i<2 ; ++i)
{
PGMeshEntity* meshEntity = (PGMeshEntity*)meshList[i];
Mesh* mesh = meshEntity->get_mesh();
Mesh::ConstVertexIter cvIt = mesh->vertices_begin();
Mesh::ConstVertexIter cvIt_end = mesh->vertices_end();
meshEntity->get_bb_center(currEntityCenter);
double offset[3] = {0,0,0};
offset[0] =currEntityCenter[0] - RCenter[0];
offset[1]= currEntityCenter[1] - RCenter[1];
offset[2]= currEntityCenter[2] - RCenter[2];
RCenter+=3;
//** update the leftmost point for the next entity *//
//** adjust the position of all points of current entity *//
for ( ; cvIt != cvIt_end; ++cvIt )
{
OpenMesh::Vec3d tmpPoint = mesh->point(cvIt);
tmpPoint[0] -= offset[0];
tmpPoint[1] -= offset[1];
tmpPoint[2] -= offset[2];
mesh->set_point( cvIt.handle(), tmpPoint ); //** modify core mesh D.S. embedded in PGMeshEntity D.S., updating the corresponding render in PGMeshEntity D.S. is needed *//
}
//** update the center point of PGMeshEntity instance bounding box *//
meshEntity->cal_bounding_box();
meshEntity->update_rendering();
mesh->update_face_normals();
}
误差计算
上文中已经说过,误差可以简单计算为两个模型对应点之间的欧氏距离。可视化误差实际上就是给模型B(或A)着色,用颜色来表示误差。具体做法是,声明一个向量ErrorB,用来存放模型B的每个点距离模型A的对应点的距离,然后设置一个colorMap,根据距离,选取colorMap中的颜色,作为B中点的颜色,最后绘制出来。误差计算代码如下:
void SequenceWaterMark::error_Map()
{
BaseEntity * entity_meshA;
BaseEntity * entity_meshB;
entity_meshA = meshList[0];
entity_meshB = meshList[1];
PolygonMesh::Mesh * _meshA = ((PolygonMesh::PGMeshEntity *) entity_meshA)->get_mesh();
PolygonMesh::Mesh * _meshB = ((PolygonMesh::PGMeshEntity *) entity_meshB)->get_mesh();
//可视化的量
vector<double> ErrorB;
//用来存放每个点的三维坐标
VectorXd ACoor(3);
VectorXd BCoor(3);
int ia = 0;
for ( auto va_it = _meshA->vertices_begin();va_it != _meshA->vertices_end();++va_it, ia++ )
{
auto t_p = _meshA->point(va_it.handle());
ACoor[0] = t_p[0];
ACoor[1] = t_p[1];
ACoor[2] = t_p[2];
int ib = 0;
double dis = 0.0;
for ( auto vb_it = _meshB->vertices_begin();vb_it != _meshB->vertices_end();++vb_it, ib++ )
{
auto t_pb = _meshB->point(vb_it.handle());
if ( ia == ib )
{
BCoor[0] = t_pb[0];
BCoor[1] = t_pb[1];
BCoor[2] = t_pb[2];
dis = (ACoor - BCoor).norm();
ErrorB.push_back( dis );
break;
}
}
}
vector<double>::iterator max_it;
max_it = max_element( ErrorB.begin(), ErrorB.end() );
double maxD = *max_it;
vector<double>::iterator min_it;
min_it = min_element( ErrorB.begin(), ErrorB.end() );
double minD = *min_it;
Mesh::Color CL;
int v = 0;
for (auto vit = _meshB->vertices_begin();vit != _meshB->vertices_end();++vit, v++)
{
ErrorB[v] = 100.0f * ( ErrorB[v] - minD )/( maxD - minD );
double clampV = ErrorB[v]< 99.0f ? ErrorB[v] : 99.0f;
clampV = clampV > 0.0f ? clampV : 0.0f;
int colorPercent = (int)clampV;
unsigned char* colorPtr = ErrorColorMap + colorPercent * 3;
CL.values_[0] = colorPtr[0];
CL.values_[1] = colorPtr[1];
CL.values_[2] = colorPtr[2];
_meshB->set_color(vit.handle(), CL);//动态显示
}
_meshB->update_face_normals();
entity_meshB->update_rendering();
最后为了便于查看,将第二个模型的位置稍微偏移一下
//为了显示方便,将第二帧偏移一下
PGMeshEntity* meshEntity = (PGMeshEntity*)meshList[1];
Mesh* mesh = meshEntity->get_mesh();
Mesh::ConstVertexIter cvIt = mesh->vertices_begin();
Mesh::ConstVertexIter cvIt_end = mesh->vertices_end();
meshEntity->get_bb_center(currEntityCenter);
double radius = meshEntity->get_bb_radius();
double offset[3] = {0,0,0};
offset[0] =currEntityCenter[0] + radius;
offset[1]= currEntityCenter[1];
offset[2]= currEntityCenter[2];
//** update the leftmost point for the next entity *//
//** adjust the position of all points of current entity *//
for ( ; cvIt != cvIt_end; ++cvIt )
{
OpenMesh::Vec3d tmpPoint = mesh->point(cvIt);
tmpPoint[0] += offset[0];
tmpPoint[1] += offset[1];
tmpPoint[2] += offset[2];
mesh->set_point( cvIt.handle(), tmpPoint ); //** modify core mesh D.S. embedded in PGMeshEntity D.S., updating the corresponding render in PGMeshEntity D.S. is needed *//
}
//** update the center point of PGMeshEntity instance bounding box *//
meshEntity->cal_bounding_box();
meshEntity->update_rendering();
mesh->update_face_normals();
}
我们用一个简单的模型来验证上述代码
下图为输入的两个模型,左边为模型A,右边为模型B
下图为执行结果
用matlab绘制颜色条
现在已经得到了误差图,但是我们仍然不知道颜色与误差之间的关系,换句话说,只有上面的执行结果,我们并不了解深蓝色对应的误差到底是大还是小,因此需要将我们用来表示误差的颜色映射到一个颜色条上。
1.首先在matlab中输入一个矩阵MAP,表示要绘制的颜色条包含的RGB值
2.将MAP的每个值除以255,即AMAP = MAP/255
3.将AMAP传入COLORMAP函数中,即执行COLORMAP(AMAP)
4.绘制结果,即执行figure;colorbar;
结果如下: