积分图是为了加速计算HAAR特征值,积分图中每个点的值代表“积分”,即计算相应矩形框中所有像素的累积和。该矩形框的左上角为图像原点,右下角为图像每一点的位置。积分图比原图多一行和一列,分别对应原图像最上面和最左面,即最上面对应以最上面的点为矩形框右下角,此时累积和都为0;最左面对应以最左面的点为矩形框右下角,此时累积和也都为0。
为了方便计算积分图,每一点的值为以下二者的和:
1. 该点上一行对应位置的积分值
2. 该点所在行从起点到该点的累积和
该点的积分值为上述二者之和
//下面函数中的cn为图像的通道数,即channels,sum为求的积分图,src为原图
template<typename T, typename ST, typename QT>
void integral_( const T* src, size_t _srcstep, ST* sum, size_t _sumstep,
QT* sqsum, size_t _sqsumstep, ST* tilted, size_t _tiltedstep,
Size size, int cn ){
int x, y, k;
int srcstep = (int)(_srcstep/sizeof(T)); //src图每一行的元素个数
int sumstep = (int)(_sumstep/sizeof(ST)); //sum图每一行的元素个数
int tiltedstep = (int)(_tiltedstep/sizeof(ST));
int sqsumstep = (int)(_sqsumstep/sizeof(QT));
size.width *= cn; //原图像每一行的所有元素个数
memset( sum, 0, (size.width+cn)*sizeof(sum[0])); //积分图第一行的元素置为0,积分图比原图多一列和多一行,size.width为原图的宽度,因此积分图的宽度为size.width+cn
sum += sumstep + cn;//积分图第二行的第二个元素,这里从一开始计数
if( sqsum ){
memset( sqsum, 0, (size.width+cn)*sizeof(sqsum[0]));
sqsum += sqsumstep + cn;
}
if( tilted ){
memset( tilted, 0, (size.width+cn)*sizeof(tilted[0]));
tilted += tiltedstep + cn;
}
if( sqsum == 0 && tilted == 0 )
{//遍历原图的全部元素,计算相应的积分值
//原图每行累加srcstep - cn,积分图每行累加 sumstep – cn,都是为了下一行的初始指针指向原图
//下一行的第一个元素,积分图的下一行的第二个元素。-cn是因为在每次通道循环计算结束后,src++, //sum++,导致每一行计算完毕后,原图指向该行的第二个元素,积分图指向该行的第三个元素
for( y = 0; y < size.height; y++, src += srcstep - cn, sum += sumstep - cn )
{
for( k = 0; k < cn; k++, src++, sum++ )
{ //为实现多通道的积分图,即每次先计算一行中的一个通道的所有积分图
//再计算该行下一个通道的所有积分图
ST s = sum[-cn] = 0;//每一行的第一个元素,即最左边的元素的所有通道的积分值置0
for( x = 0; x < size.width; x += cn )
{
s += src[x];//计算原图从该行起点(s初始值为0)到对应像素点的累积和
sum[x] = sum[x - sumstep] + s;//积分值为上一行对应位置的积分值和
//该点所在行从起点到该点累积和之和。前面将积分图最上面一行置为0,
//就是为第一行计算服务的,方便在第一行计算时找到上一行对应位置的积分值。
}
}
}
}
else if( tilted == 0 ){
for( y = 0; y < size.height; y++, src += srcstep - cn,
sum += sumstep - cn, sqsum += sqsumstep - cn ){
for( k = 0; k < cn; k++, src++, sum++, sqsum++ ){
ST s = sum[-cn] = 0;
QT sq = sqsum[-cn] = 0;
for( x = 0; x < size.width; x += cn ){
T it = src[x];
s += it;
sq += (QT)it*it;
ST t = sum[x - sumstep] + s;
QT tq = sqsum[x - sqsumstep] + sq;
sum[x] = t;
sqsum[x] = tq;
}
}
}
}
else {
AutoBuffer<ST> _buf(size.width+cn);
ST* buf = _buf;
ST s;
QT sq;
for( k = 0; k < cn; k++, src++, sum++, tilted++, buf++ ){
sum[-cn] = tilted[-cn] = 0;
for( x = 0, s = 0, sq = 0; x < size.width; x += cn ){
T it = src[x];
buf[x] = tilted[x] = it;
s += it;
sq += (QT)it*it;
sum[x] = s;
if( sqsum )
sqsum[x] = sq;
}
if( size.width == cn )
buf[cn] = 0;
if( sqsum ){
sqsum[-cn] = 0;
sqsum++;
}
}
for( y = 1; y < size.height; y++ ){
src += srcstep - cn;
sum += sumstep - cn;
tilted += tiltedstep - cn;
buf += -cn;
if( sqsum )
sqsum += sqsumstep - cn;
for( k = 0; k < cn; k++, src++, sum++, tilted++, buf++ ){
T it = src[0];
ST t0 = s = it;
QT tq0 = sq = (QT)it*it;
sum[-cn] = 0;
if( sqsum )
sqsum[-cn] = 0;
tilted[-cn] = tilted[-tiltedstep];
sum[0] = sum[-sumstep] + t0;
if( sqsum )
sqsum[0] = sqsum[-sqsumstep] + tq0;
tilted[0] = tilted[-tiltedstep] + t0 + buf[cn];
for( x = cn; x < size.width - cn; x += cn ) {
ST t1 = buf[x];
buf[x - cn] = t1 + t0;
t0 = it = src[x];
tq0 = (QT)it*it;
s += t0;
sq += tq0;
sum[x] = sum[x - sumstep] + s;
if( sqsum )
sqsum[x] = sqsum[x - sqsumstep] + sq;
t1 += buf[x + cn] + t0 + tilted[x - tiltedstep - cn];
tilted[x] = t1;
}
if( size.width > cn ){
ST t1 = buf[x];
buf[x - cn] = t1 + t0;
t0 = it = src[x];
tq0 = (QT)it*it;
s += t0;
sq += tq0;
sum[x] = sum[x - sumstep] + s;
if( sqsum )
sqsum[x] = sqsum[x - sqsumstep] + sq;
tilted[x] = t0 + t1 + tilted[x - tiltedstep - cn];
buf[x] = t0;
}
if( sqsum )
sqsum++;
}
}
}
}