DSO学习笔记二 makeMaps函数

目录

  • 一、概述
  • 二、代码测试
    • 测试结果
  • 问题
    • 更新:问题

一、概述

接着上一次的学习。DSO在完成输入图像、计算金字塔等图像处理操作后,会进入初始化流程。初始化对于DSO而言非常重要,选择不同的初始化图像,最后DSO的效果也会有差别。
在探索过程中,我遇到名为makeMaps的函数,虽然这个函数的设计非常巧妙,但是还是有很多地方让我很迷惑。

二、代码测试

这里先把测试makeMaps的代码贴上。主要代码引用自JakobEngel/dso,代码注释主要参考alalagong/DSO。

#include 
#include
#include
#include 
#include 
#include 
#include 

using namespace std;
using namespace cv;

#define PYR_LEVELS 6            //最大金字塔层数
typedef Eigen::Matrix<float,2,1> Vect2f;
enum PixelSelectorStatus {
     PIXSEL_VOID=0, PIXSEL_1, PIXSEL_2, PIXSEL_3};//定义枚举类型,占用整型内存
int currentPotential=3;
float* absSquaredGrad[PYR_LEVELS];  //x,y方向梯度的平方和
int wG[PYR_LEVELS], hG[PYR_LEVELS];//图像宽高
int bins[PYR_LEVELS];//梯度直方图大小范围
unsigned char* randomPattern;
int* gradHist;
float* ths;
float* thsSmoothed;
int thsStep;
bool gradHistFrame=false;
Eigen::Vector3f* dI;				 //图像导数
Eigen::Vector3f* dIp[PYR_LEVELS];	 //各金字塔层的图像导数

int makeMaps(float* map_out, float density, int recursionsLeft, bool plot, float thFactor)
{
     
    float numHave=0;
    float numWant=density;
    float quotia;
    int idealPotential = currentPotential;//初始化为3
    int w = wG[0];//0层图像宽度
    int h = hG[0];
    int w32 = w/32;//将整个图像分成小块
    int h32 = h/32;//每个block大小为32*32
    int thsStep = w32;
    // 0, 1, 2层的梯度平方和
    float * mapmax0 = absSquaredGrad[0];
    float * mapmax1 = absSquaredGrad[1];
    float * mapmax2 = absSquaredGrad[2];

    {
     
        //遍历每个block
        for(int y=0;y<h32;y++)
            for(int x=0;x<w32;x++)
            {
     
        //1、为每个32*32的block计算梯度直方图
                float* map0 = mapmax0+32*x+32*y*w;//地址移动,指向(x,y)block的左上角像素
                int* hist0 = gradHist;
                //sizeof获取某个数据类型所占用空间的字节数,memset为逐字节填充
                memset(hist0,0,sizeof(int)*50);//从gradHist地址开始,用0填充50个int位置
                for(int j=0;j<32;j++) for(int i=0;i<32;i++)
                {
     
                    int it = i+32*x;
                    int jt = j+32*y;//32*32block中(i,j)坐标对应的图像中的坐标
                    if(it>w-2 || jt>h-2 || it<1 || jt<1) continue;
                    int g = sqrtf(map0[i+j*w]);//(x,y)block中的(i,j)对应的像素梯度的模
                    if(g>48) g=48;//设置梯度上限
                    hist0[g+1]++;//梯度为g对应的block中的像素个数
                    hist0[0]++;//计算总个数
                }
        //2、为block选择梯度阈值
                float below = 0.5;
                int th = hist0[0]*below+0.5f;//block中的梯度个数的一半
                for(int i=0;i<90;i++)
                {
     
                    th -= hist0[i+1];// 梯度值为0-i的所有像素个数占 below%
                    if(th<0) 
                    	{
     
                    		ths[x+y*w32]=i+7;//block的值选择梯度中位数位置
                    		break;//原来这里少个break
                    	}
                }
                if(th>=0)
                {
     
                    ths[x+y*w32]=97;
                    cout<<"**************th >= 0"<<endl;
                }
            }
        //3、block梯度阈值平滑
        for(int y=0;y<h32;y++)
            for(int x=0;x<w32;x++)
            {
     
                float sum=0,num=0;
                if(x>0)
                {
     
                    if(y>0) 	{
     num++; 	sum+=ths[x-1+(y-1)*w32];}
                    if(y<h32-1) {
     num++; 	sum+=ths[x-1+(y+1)*w32];}
                    num++; sum+=ths[x-1+(y)*w32];
                }

                if(x<w32-1)
                {
     
                    if(y>0) 	{
     num++; 	sum+=ths[x+1+(y-1)*w32];}
                    if(y<h32-1) {
     num++; 	sum+=ths[x+1+(y+1)*w32];}
                    num++; sum+=ths[x+1+(y)*w32];
                }

                if(y>0) 	{
     num++; 	sum+=ths[x+(y-1)*w32];}
                if(y<h32-1) {
     num++; 	sum+=ths[x+(y+1)*w32];}
                num++; sum+=ths[x+y*w32];
                thsSmoothed[x+y*w32] = (sum/num) * (sum/num);//用3*3个block求平均值平方作为新的block的值
            }

        //4、选择像素
        Eigen::Vector3f const * const map_0 = dI;
        int w = wG[0];
        int w1 = wG[1];
        int w2 = wG[2];
        int h = hG[0];
        //随机选这16个对应方向上的梯度和阈值比较
        //每个pot里面的方向随机选取的, 防止特征相同, 重复
        const Vect2f directions[16] = {
     
                 Vect2f(0,    1.0000),
                 Vect2f(0.3827,    0.9239),
                 Vect2f(0.1951,    0.9808),
                 Vect2f(0.9239,    0.3827),
                 Vect2f(0.7071,    0.7071),
                 Vect2f(0.3827,   -0.9239),
                 Vect2f(0.8315,    0.5556),
                 Vect2f(0.8315,   -0.5556),
                 Vect2f(0.5556,   -0.8315),
                 Vect2f(0.9808,    0.1951),
                 Vect2f(0.9239,   -0.3827),
                 Vect2f(0.7071,   -0.7071),
                 Vect2f(0.5556,    0.8315),
                 Vect2f(0.9808,   -0.1951),
                 Vect2f(1.0000,    0.0000),
                 Vect2f(0.1951,   -0.9808)};
        memset(map_out,0,w*h*sizeof(PixelSelectorStatus));//填充0,float和int都是4个字节
        // 金字塔层阈值的减小倍数
        float dw1 = 0.75;
        float dw2 = dw1*dw1;
        int pot = currentPotential;//网格大小为3
        int n3=0, n2=0, n4=0;
        bool setting_selectDirectionDistribution=true;
        //0层2*2个像素对应1层1个像素,1层2*2个像素对应2层1个像素
        //同理0层2*2个pot对应1层1个pot,1层2*2个pot对应2层1个pot
        //先选择0层合适的像素,在第0层2*2个pot里都不合适,再到第1层选择
        //之后第1层选择同理,最后保存被选像素在第0层的坐标
        for(int y4=0;y4<h;y4+=(4*pot)) for(int x4=0;x4<w;x4+=(4*pot))
        {
     
            int my3 = std::min((4*pot), h-y4);
            int mx3 = std::min((4*pot), w-x4);
            int bestIdx4=-1; float bestVal4=0;
            Vect2f dir4 = directions[randomPattern[n4] & 0xF];// 取低4位, 0-15, 和directions对应
            for(int y3=0;y3<my3;y3+=(2*pot)) for(int x3=0;x3<mx3;x3+=(2*pot))
            {
     
                int x34 = x3+x4;
                int y34 = y3+y4;
                int my2 = std::min((2*pot), h-y34);
                int mx2 = std::min((2*pot), w-x34);
                int bestIdx3=-1; float bestVal3=0;
                Vect2f dir3 = directions[randomPattern[n3] & 0xF];
                for(int y2=0;y2<my2;y2+=pot) for(int x2=0;x2<mx2;x2+=pot)
                {
     
                    int x234 = x2+x34;
                    int y234 = y2+y34;
                    int my1 = std::min(pot, h-y234);
                    int mx1 = std::min(pot, w-x234);
                    int bestIdx2=-1; float bestVal2=0;
                    Vect2f dir2 = directions[randomPattern[n2] & 0xF];
                    for(int y1=0;y1<my1;y1+=1) for(int x1=0;x1<mx1;x1+=1)
                    {
     
                        assert(x1+x234 < w);//值为假,则打印信息终止程序
                        assert(y1+y234 < h);
                        int xf = x1+x234;//idx像素坐标
                        int yf = y1+y234;
                        int idx = xf + w*yf;//第0层4*4个pot里,第(x2,y2)个pot的第(x1,y1)的像素id
                        if(xf<4 || xf>=w-5 || yf<4 || yf>h-4) continue;//不考虑0层最外一圈4*4的像素
                        float pixelTH0 = thsSmoothed[(xf>>5) + (yf>>5) * thsStep];//三个阈值
                        float pixelTH1 = pixelTH0*dw1;
                        float pixelTH2 = pixelTH1*dw2;
                        float ag0 = mapmax0[idx];//第0层对应坐标的梯度平方和
                        if(ag0 > pixelTH0*thFactor)
                        {
     
                            Vect2f ag0d = map_0[idx].tail<2>();//第0层(dx,dy)
                            float dirNorm = fabsf((float)(ag0d.dot(dir2)));//点乘,计算在dir2上的投影
                            if(!setting_selectDirectionDistribution) dirNorm = ag0;
                            if(dirNorm > bestVal2)//记录每个pot在n2方向中的梯度最大值
                            {
      bestVal2 = dirNorm; bestIdx2 = idx; bestIdx3 = -2; bestIdx4 = -2;}
                        }
                        //如果同时满足梯度平方大于阈值,在dir2方向上的投影大于存储的值,则检测pot里下一个像素
                        if(bestIdx3==-2) continue;//初始为-1
                        float ag1 = mapmax1[(int)(xf*0.5f+0.25f) + (int)(yf*0.5f+0.25f)*w1];//第1层对应的梯度平方和
                        if(ag1 > pixelTH1*thFactor)
                        {
     
                            Vect2f ag0d = map_0[idx].tail<2>();
                            float dirNorm = fabsf((float)(ag0d.dot(dir3)));
                            if(!setting_selectDirectionDistribution) dirNorm = ag1;
                            if(dirNorm > bestVal3)
                            {
      bestVal3 = dirNorm; bestIdx3 = idx; bestIdx4 = -2;}
                        }
                        //如果第0层都不满足,在第1层中寻找合适像素
                        if(bestIdx4==-2) continue;
                        //如果第1层都不满足,在第2层中寻找合适像素
                        float ag2 = mapmax2[(int)(xf*0.25f+0.125) + (int)(yf*0.25f+0.125)*w2];
                        if(ag2 > pixelTH2*thFactor)
                        {
     
                            Vect2f ag0d = map_0[idx].tail<2>();
                            float dirNorm = fabsf((float)(ag0d.dot(dir4)));
                            if(!setting_selectDirectionDistribution) dirNorm = ag2;
                            if(dirNorm > bestVal4)
                            {
      bestVal4 = dirNorm; bestIdx4 = idx; }
                        }
                    }
                    //如果在第0层找到像素,记录像素位置,改变投影方向
                    if(bestIdx2>0)
                    {
     
                        map_out[bestIdx2] = 1;
                        bestVal3 = 1e10;//第0层每2*2个pot里只选择一个像素
                        n2++;
                    }
                }
                //如果在第0层没找到,第1层找到
                if(bestIdx3>0)
                {
     
                    map_out[bestIdx3] = 2;
                    bestVal4 = 1e10;//第1层每2*2个pot里只选择一个像素
                    n3++;
                }
            }
            //如果在第1层没找到,第2层找到
            if(bestIdx4>0)
            {
     
                map_out[bestIdx4] = 4;
                n4++;
            }
        }
        Eigen::Vector3i n(n2,n3,n4);//记录第0,1,2层选点的个数
        numHave = n[0]+n[1]+n[2];//numHave表示已选像素个数
        cout << "numHave = " << numHave << endl;
        cout << "n2 = " << n2 << endl;
        quotia = numWant / numHave;
        //0层1个pot里只选择1个像素,因此K相当于计算已经被占用的像素的个数
        //numWant表示目标像素个数
        float K = numHave * (currentPotential+1) * (currentPotential+1);
        idealPotential = sqrtf(K/numWant)-1;//sqrtf(nH/nW)*(pot+1)-1
        cout << "numWant = " << numWant << endl;
//        cout << "K = " << K << endl;
        cout << "quotia = " << quotia << endl;
        if(idealPotential<1) idealPotential=1;
        //比例大于1.25,需要缩小pot,增加选点数numHave
        if( recursionsLeft>0 && quotia > 1.25 && currentPotential>1)
        {
     
            if(idealPotential>=currentPotential)
                idealPotential = currentPotential-1;
            currentPotential = idealPotential;
            return makeMaps(map_out, density, recursionsLeft-1, plot,thFactor);//递归,重采样
        }
        //比例小于0.25,增大pot,减少选点数
        else if(recursionsLeft>0 && quotia < 0.25)
        {
     
            if(idealPotential<=currentPotential)
                idealPotential = currentPotential+1;
            currentPotential = idealPotential;
            return makeMaps(map_out, density, recursionsLeft-1, plot,thFactor);//递归,重采样
        }
        cout << "idealPotential = " << idealPotential << endl;
        cout << "currentPotential = " << currentPotential << endl;

        //显示0层的梯度直方图
        bins[0]=49;//第0层有49个梯度
        int hist_w = 392;//直方图宽度
        int hist_h = 400;//直方图高度
        int bin_w = cvRound((double)hist_w / bins[0]);//每个bin的宽度
        Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3);//初始化直方图
        //归一化直方图数据
        for(int i=1; i<bins[0]; i++)
        {
     
            rectangle(histImage, Point(bin_w*(i - 1), hist_h - cvRound(400*gradHist[i]/gradHist[0])),
                      Point(bin_w*(i), hist_h - 1), Scalar(255, 0, 0), 1, 8, 0);//图像,bin坐标左上角,右下角,颜色
        }
        // 显示直方图
        cout << "gradHist[0] = " << gradHist[0] << endl;
        cout << "bins[0] = " << bins[0] << endl;
        imshow("Histogram Demo", histImage);
    }
    int numHaveSub = numHave;
    if(quotia < 0.95)//选点数超过预定值
    {
     
        int wh=wG[0]*hG[0];
        int rn=0;
        unsigned char charTH = 255*quotia;
        //遍历第0层所有像素
        for(int i=0;i<wh;i++)
        {
     
            if(map_out[i] != 0)//如果被选中
            {
     
                if(randomPattern[rn] > charTH )//随机删除点
                {
     
                    map_out[i]=0;
                    numHaveSub--;
                }
                rn++;
            }
        }
        cout <<"rn = "<<rn<<endl;//rn的值也远比后面的大,很奇怪
    }
    int num_test=0;
    for(int y=0; y<h;y++)
        for(int x=0;x<w;x++)
        {
     
            if(map_out[x+y*w]!=0)
                num_test++;
        }
    cout <<"num_test = "<<num_test<<endl;
    currentPotential = idealPotential;

    //画出像素选择结果
//    /*
    if(plot)//输入false
    {
     
        int w=wG[0];int h=hG[0];
        Mat img_select_result = Mat::zeros(h, w, CV_8UC3);
        Mat map_out_show = Mat::zeros(h, w, CV_8UC3);
        for(int y=0; y<h;y++)
            for(int x=0;x<w;x++)
            {
     
                float c = dI[x+y*w][0]*0.7;
                if(c>255) c=255;
                img_select_result.at<Vec3b>(y,x) = Vec3b(c,c,c);
//                switch (int(map_out[x+y*w]))//值为1的点集中在图像下方
//                {
     
//                case 0:map_out_show.at(y,x)=Vec3b(255,255,255);break;
//                case 1:map_out_show.at(y,x)=Vec3b(255,0,0);break;
//                case 2:map_out_show.at(y,x)=Vec3b(0,255,0);break;
//                case 4:map_out_show.at(y,x)=Vec3b(0,0,255);break;
//                }
            }
        imshow("Selector Image", img_select_result);
//        imshow("map_out Image", map_out_show);
        int num=0;
        for(int y=3; y<h-3;y++)
            for(int x=3;x<w-3;x++)
            {
     
                int pi=x+y*w;
                int val;
                if(map_out[pi] == 1)
                    val= 0;
                else if(map_out[pi] == 2)
                    val= 1;
                else if(map_out[pi] == 4)
                    val= 2;
                else
                    continue;
                for(int i=-3;i<=3;i++)
                {
     
                    img_select_result.at<Vec3b>(y+i,x+3)[val] = 255;
                    img_select_result.at<Vec3b>(y+i,x-3)[val] = 255;
                    img_select_result.at<Vec3b>(y+i,x+2)[val] = 255;
                    img_select_result.at<Vec3b>(y+i,x-2)[val] = 255;

                    img_select_result.at<Vec3b>(y-3,x+i)[val] = 255;
                    img_select_result.at<Vec3b>(y+3,x+i)[val] = 255;
                    img_select_result.at<Vec3b>(y-2,x+i)[val] = 255;
                    img_select_result.at<Vec3b>(y+2,x+i)[val] = 255;
                }
                num++;
            }
        cout <<"num = "<< num <<endl;
        imshow("Selector Pixels", img_select_result);
    }
//    */
    return numHaveSub;
}

//int makePixelStatus(Eigen::Vector3f* grads, bool* map, int w, int h, float desiredDensity, int recsLeft=5, float THFac = 1)
//{
     
//}

int main(int argc, char *argv[])
{
     
    Mat img,img_f;
    float* color;
    int pyrLevelsUsed;
    float* img_pyr[PYR_LEVELS];

//step1:读入图像
// /*
    if(argc<=3)
        img = imread(argv[1], IMREAD_GRAYSCALE);
    else
    {
     
        cout << "error, input './img_test path/image.png path/camera.txt' " <<endl;
        return -1;
    }
    imshow("raw image", img);
    wG[0]=img.cols;hG[0]=img.rows;
    int w=wG[0];//0层图像宽度
    int h=hG[0];
    color = new float[w*h];
    // 数据类型转化 unsigned char 转化为 float
    img.convertTo(img_f, CV_32F);
    memcpy(color, img_f.data, w*h*sizeof(float));//void memcpy(void * _Dst, const void *_Src, size_t _Size);
// */

//step2:初始化金字塔
// /*
    //2.1 确定图像金字塔层数
    int wlvl=w;
    int hlvl=h;
    pyrLevelsUsed=1;
    while(wlvl%2==0 && hlvl%2==0 && wlvl*hlvl > 5000 && pyrLevelsUsed < PYR_LEVELS)
    {
     
        wlvl /=2;
        hlvl /=2;
        pyrLevelsUsed++;
    }
    printf("using pyramid levels 0 to %d. coarsest resolution: %d x %d!\n",
            pyrLevelsUsed-1, wlvl, hlvl);
    if(wlvl>100 && hlvl > 100)
    {
     
        printf("\n\n===============WARNING!===================\n "
                "using not enough pyramid levels.\n"
                "Consider scaling to a resolution that is a multiple of a power of 2.\n");
    }
    if(pyrLevelsUsed < 3)
    {
     
        printf("\n\n===============WARNING!===================\n "
                "I need higher resolution.\n"
                "I will probably segfault.\n");
    }
    //2.2 初始化
    for (int level = 1; level < pyrLevelsUsed; ++ level)
    {
     
        wG[level] = w >> level;//位右移,等效除以2
        hG[level] = h >> level;
    }
    for(int i=0;i<pyrLevelsUsed;i++)
    {
     
        dIp[i] = new Eigen::Vector3f[wG[i]*hG[i]];//初始化各层图像导数,new结果是一段3*1向量数组的地址
        absSquaredGrad[i] = new float[wG[i]*hG[i]];//xy方向梯度平方和
        img_pyr[i] = new float[wG[i]*hG[i]];
    }
    dI = dIp[0];//图像导数指针,dI指向第0层图像梯度
// */

//step3:生成金字塔
// /*
    for(int i=0;i<w*h;i++)
    {
     
        dI[i][0] = color[i];//图像按照辐射度数组存储,第0层第一通道存储原图
        img_pyr[0][i] = color[i];
    }
    //3.1 生成图像金字塔
    for(int lvl=0; lvl<pyrLevelsUsed; lvl++)
    {
     
        int wl = wG[lvl], hl = hG[lvl];//当前层图像尺寸
        Eigen::Vector3f* dI_l = dIp[lvl];//当前层图像梯度数组地址
        float* dabs_l = absSquaredGrad[lvl];//当前层图像梯度平方和数组地址
        if(lvl>0)//第0层不执行
        {
     
            int lvlm1 = lvl-1;//上一层ID
            int wlm1 = wG[lvlm1];//上一层列数
            Eigen::Vector3f* dI_lm = dIp[lvlm1];//上一层梯度数组地址
            //像素4合1,生成金字塔
            for(int y=0;y<hl;y++)
                for(int x=0;x<wl;x++)
                {
     
                    //(x,y)位置的第一个通道存入灰度值,由上一层4合1得到
                    dI_l[x + y*wl][0] = 0.25f * (dI_lm[2*x   + 2*y*wlm1][0] +
                                                dI_lm[2*x+1 + 2*y*wlm1][0] +
                                                dI_lm[2*x   + 2*y*wlm1+wlm1][0] +
                                                dI_lm[2*x+1 + 2*y*wlm1+wlm1][0]);
                    img_pyr[lvl][x + y*wl] = dI_l[x + y*wl][0];//
                }
        }
    //3.2 对当前层图像求梯度
        for(int idx=wl;idx < wl*(hl-1);idx++)//从第2行第1列开始
        {
     
            float dx = 0.5f*(dI_l[idx+1][0] - dI_l[idx-1][0]);//x方向梯度(宽度)
            float dy = 0.5f*(dI_l[idx+wl][0] - dI_l[idx-wl][0]);
            if(!std::isfinite(dx)) dx=0;//当参数不是NaN、Infinity、-Infinity 时,返回true
            if(!std::isfinite(dy)) dy=0;

            dI_l[idx][1] = dx;//第2通道存储x方向梯度
            dI_l[idx][2] = dy;//第3通道存储y方向梯度
            dabs_l[idx] = dx*dx+dy*dy;//absSquaredGrad存储梯度平方和
        }
    }
    //3.3 显示金字塔
    for(int i=0; i<pyrLevelsUsed; i++)
    {
     
        Mat img_pyr_show(hG[i], wG[i], CV_32F);
        memcpy(img_pyr_show.data, img_pyr[i], wG[i]*hG[i]*sizeof(float));//
        img_pyr_show.convertTo(img_pyr_show, CV_8UC1);
        string name = to_string(i);
        imshow("P"+name, img_pyr_show);
    }
    cout << "pyrLevelsUsed = " << pyrLevelsUsed << endl;
// */

//step4:为每层计算内参K
// /*
    double fx[PYR_LEVELS], fy[PYR_LEVELS], cx[PYR_LEVELS], cy[PYR_LEVELS];
    double k1, k2, p1, p2;
    Eigen::Matrix<double,3,3> K[PYR_LEVELS];
    ifstream readFile(argv[2]);//打开相机内参数据文件
    if (!readFile.is_open())
    {
     
        cout << "未成功打开内参文件" << endl;
        return -1;
    }
    readFile >> fx[0] >> fy[0] >> cx[0] >> cy[0]
                >> k1 >> k2 >> p1 >> p2;
    K[0] << fx[0], 0.0, cx[0], 0.0, fy[0], cy[0], 0.0, 0.0, 1.0;
    for (int level = 1; level < pyrLevelsUsed; ++ level)
    {
     
        fx[level] = fx[level-1] * 0.5;
        fy[level] = fy[level-1] * 0.5;
        cx[level] = (cx[0] + 0.5) / ((int)1<<level) - 0.5;
        cy[level] = (cy[0] + 0.5) / ((int)1<<level) - 0.5;//左移,相当于乘以2的幂
        K[level] << fx[level], 0.0, cx[level], 0.0, fy[level], cy[level], 0.0, 0.0, 1.0;
        cout << K[level] << endl;
    }
    readFile.close();   //关闭文件
// */

//step5:提取特征像素
// /*
    float* statusMap = new float[wG[0]*hG[0]];
    bool* statusMapB = new bool[wG[0]*hG[0]];
    float densities[] = {
     0.03,0.05,0.15,0.5,1};//不同层点密度
    gradHist = new int[100*(1+wG[0]/32)*(1+hG[0]/32)];//gradHist可能只是为了开辟足够大的空间
    ths = new float[(wG[0]/32)*(hG[0]/32)+100];
    thsSmoothed = new float[(wG[0]/32)*(hG[0]/32)+100];
    //5.1 产生随机数
    randomPattern = new unsigned char[wG[0]*hG[0]];
    std::srand(3141592);	// want to be deterministic.rand()和srand()要一起使用,其中srand()用来初始化随机数种子,rand()用来产生随机数。
    for(int i=0;i<wG[0]*hG[0];i++) randomPattern[i] = rand() & 0xFF;

    //5.2 遍历金字塔
    for(int lvl=0; lvl<pyrLevelsUsed; lvl++)
    {
     
        int npts;
//        //如果是第0层
        if(lvl == 0)
            npts = makeMaps(statusMap,densities[lvl]*w*h,1,true,2);//
//        else//封印中
//            npts = makePixelStatus(firstFrame->dIp[lvl], statusMapB, w[lvl], h[lvl], densities[lvl]*w[0]*h[0]);
    }

    delete []color;
    delete []randomPattern;
    delete []gradHist;
    delete []ths;
    delete []thsSmoothed;
    delete []statusMap;
    delete []statusMapB;
    
    for(int i=0;i<pyrLevelsUsed;i++)
    {
     
        delete []dIp[i];
        delete []absSquaredGrad[i];
        delete []img_pyr[i];
    }
    waitKey(0);
    return 0;
}

测试结果

DSO学习笔记二 makeMaps函数_第1张图片DSO学习笔记二 makeMaps函数_第2张图片

问题

1、直方图归一化我直接用的总数,所以画出的图显得有点大。
2、最大的问题还是特征像素选取上。可以看到为了满足需要的选点个数,第0层的选点(蓝色点)大部分都集中到图像下部,数量占总数的90%。最开始我以为是测试程序出错,但是对DSO项目运行过程中,也观测到这种不合理。(是只有我吗,还是已经有过解释了?)不过DSO项目还是可以正常运行,可能影响不大。

笔记先记录到这了,最后祝大家新年快乐,牛年大吉。

更新:问题

经过各种调试,终于发现问题所在。原来程序每个block的阈值都是96,这个问题再往上看,才发现自己在中位数选值后忘记break,失之毫厘谬以千里啊。

这里贴上修改之后的结果。虽然已经得到和原DSO项目一样的效果,但是图像下部集中了大量的像素(苦笑)。
DSO学习笔记二 makeMaps函数_第3张图片
继续修改,我发现DSO项目程序里有这样一句代码

                        if(xf<4 || xf>=w-5 || yf<4 || yf>h-4) continue;

刚开始我的理解是选点忽略最外的一圈像素。可是在我继续深究图像下部的像素集中问题时,我发现并不是这样。
xf>>5 和 yf>>5 的值是分别等于w32和h32的,而梯度阈值的序号是从0开始,最大到w32-1,这些多余的像素位阈值为0,必定被选中,所以底下有一条错误选点带。于是修改上面这句代码为

                        if(xf<4 || xf>=w-17 || yf<4 || yf>h-17) continue;

可以得到更好的结果,见下图。
DSO学习笔记二 makeMaps函数_第4张图片DSO学习笔记二 makeMaps函数_第5张图片

你可能感兴趣的:(dso,计算机视觉,slam,c++)