上一篇文章中讲到了多边形的绘制实现,但是有一个问题:锯齿感比较强。本文也顺着Games101在上一篇文章的基础上,实现其中的一种抗锯齿方法,实现方式大致是,将每个点再“细分”成多个点,计算细分点在多边形中所占的比例以决定该点的透明度。结果就是将边缘模糊(去除边缘的高频信号)。话不多少,代码如下
// 画一条分割线
cv::line(_mainMatImg, cv::Point(500, 0), cv::Point(500, 500), cv::Scalar(255, 0, 0));
// 再画抗锯齿的三角形
int posPtCnt;
unsigned char mixColor[4], fColor[4] = {0, 0, 255, 0};
const int antiTime = 4; // 超分辨率倍率
double dTmp;
for (int y = 0; y < _mainMatImg.rows; ++y)
{
for (int x = 0; x < _mainMatImg.cols / 2; ++x)
{
// 此处将一个像素通过“超分辨率”提升为 antiTime*antiTime 个像素
posPtCnt = 0;
for (int yy = 0; yy < antiTime; ++yy)
{
for (int xx = 0; xx < antiTime; ++xx)
{
for (i = 0; i < polyEdgeNum; ++i)
{
// 求多边形形边向量
v1[0] = triAngPt[(i + 1) % polyEdgeNum][0] - triAngPt[i][0];
v1[1] = triAngPt[(i + 1) % polyEdgeNum][1] - triAngPt[i][1];
// 求当前“超分辨率”点和多边形当前边起始点的向量
v2[0] = (x - 0.5 + 1.0 / (antiTime * 2) + xx * 1.0 / antiTime) - triAngPt[i][0];
v2[1] = (y - 0.5 + 1.0 / (antiTime * 2) + yy * 1.0 / antiTime) - triAngPt[i][1];
// 将上述两个向量叉乘以求方向
vxvRst = v1[0] * v2[1] - v1[1] * v2[0];
//
if (i == 0)
{
ifNegative = (vxvRst > 0 ? false : true);
}
else
{
if (ifNegative == true && vxvRst > 0
|| ifNegative == false && vxvRst < 0)
{
break;
}
}
}
//
if (i >= polyEdgeNum)
{
++posPtCnt;
}
}
}
if (posPtCnt > 0)
{
// dTmp即求得的当前像素点的透明度值
dTmp = posPtCnt * 1.0 / (antiTime * antiTime);
#if 0
fColor[3] = dTmp * 255.0;
// 使用颜色融合,将前景色和背景色进行融合
ColorMix(fColor, bkColor, mixColor);
_mainMatImg.data[y * _mainMatImg.step + (x + _mainMatImg.cols / 2) * 3 + 0] = mixColor[0];
_mainMatImg.data[y * _mainMatImg.step + (x + _mainMatImg.cols / 2) * 3 + 1] = mixColor[1];
_mainMatImg.data[y * _mainMatImg.step + (x + _mainMatImg.cols / 2) * 3 + 2] = mixColor[2];
#else
_mainMatImg.data[y * _mainMatImg.step + (x + _mainMatImg.cols / 2) * 3 + 0] = fColor[0] * posPtCnt * 1.0 / (antiTime * antiTime);
_mainMatImg.data[y * _mainMatImg.step + (x + _mainMatImg.cols / 2) * 3 + 1] = fColor[1] * posPtCnt * 1.0 / (antiTime * antiTime);
_mainMatImg.data[y * _mainMatImg.step + (x + _mainMatImg.cols / 2) * 3 + 2] = fColor[2] * posPtCnt * 1.0 / (antiTime * antiTime);
#endif
}
}
}
为了便于展示,我们先把背景颜色调成黑色,结果如下,左边是上一篇文章的结果,右边是此处抗锯齿后的结果,可以修改代码查看不同倍率的抗锯齿效果。
特别说明:
(1)为什么此处我们改用黑色背景,我们把背景调成其他颜色就可以知道了,下面是不同背景颜色的显示结果
可以发现不仅没有抗锯齿效果,还多了黑色的“锯齿”!究其原因是此处使用了简单的计算结果得到的颜色填充(这种方式在背景为黑色的时候没有问题),而正确的做法是需要将前景颜色和背景颜色进行颜色叠加才是最终的颜色,下面就是使用了颜色叠加的效果,而且可以任意更改背景颜色也不会影响显示效果
关于颜色融合可以查看这里:如何实现颜色叠加? - 知乎
最后,感谢闫令琪和Games101!