HOG可视化

可视化说明

在之前博客HOG原理及OpenCV实现中,我们解释了HOG算法的原理。最终提取到的特征就是一串向量,其实我们并不知道它具体是什么样子,也不知道它到底是不是能体现目标区域与非目标区域的差异。为了解决这个问题,我们需要对HOG特征做可视化处理。
HOG特征首先去计算每个像素的梯度,然后建立滑动窗口,在滑动窗中建立滑动块,在块中建立等分的单元(cell)。我们仔细思考下这个过程,一个块在滑动时,每次包含的单元是不同的,但是对于一个单元而言,它是不随块滑动而改变的。这就意味着,如果块尺寸,块步长,单元尺寸确定了,一个窗口中的单元数目与它们中分别包含的像素就确定了。HOG的可视化就是利用这一点,它可视化的东西就是一个单元内的bin投票结果。
为了让下面的过程变得更直观,我们将整个图像作为一个检测窗来使用,也就是说不存在滑动窗的概念。
特别要注意,这应该是HOG最容易产生异常的地方。下面的图片本来是个900×600900×600


代码实现

#include  <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

// HOGDescriptor visual_imagealizer  
// adapted for arbitrary size of feature sets and training images  
Mat get_hogdescriptor_visual_image(Mat& origImg,  
    vector<float>& descriptorValues,  
    Size winSize,  
    Size cellSize,                                     
    int scaleFactor,  
    double viz_factor)  
{     
    Mat visual_image;  
    resize(origImg, visual_image, Size(origImg.cols*scaleFactor, origImg.rows*scaleFactor));  

    int gradientBinSize = 9;  
    // dividing 180° into 9 bins, how large (in rad) is one bin?  
    float radRangeForOneBin = 3.14/(float)gradientBinSize;   

    // prepare data structure: 9 orientation / gradient strenghts for each cell  
    int cells_in_x_dir = winSize.width / cellSize.width;  
    int cells_in_y_dir = winSize.height / cellSize.height;  
    int totalnrofcells = cells_in_x_dir * cells_in_y_dir;  
    float*** gradientStrengths = new float**[cells_in_y_dir];  
    int** cellUpdateCounter   = new int*[cells_in_y_dir];  
    for (int y=0; y<cells_in_y_dir; y++)  
    {  
        gradientStrengths[y] = new float*[cells_in_x_dir];  
        cellUpdateCounter[y] = new int[cells_in_x_dir];  
        for (int x=0; x<cells_in_x_dir; x++)  
        {  
            gradientStrengths[y][x] = new float[gradientBinSize];  
            cellUpdateCounter[y][x] = 0;  

            for (int bin=0; bin<gradientBinSize; bin++)  
                gradientStrengths[y][x][bin] = 0.0;  
        }  
    }  

    // nr of blocks = nr of cells - 1  
    // since there is a new block on each cell (overlapping blocks!) but the last one  
    int blocks_in_x_dir = cells_in_x_dir - 1;  
    int blocks_in_y_dir = cells_in_y_dir - 1;  

    // compute gradient strengths per cell  
    int descriptorDataIdx = 0;  
    int cellx = 0;  
    int celly = 0;  

    for (int blockx=0; blockx<blocks_in_x_dir; blockx++)  
    {  
        for (int blocky=0; blocky<blocks_in_y_dir; blocky++)              
        {  
            // 4 cells per block ...  
            for (int cellNr=0; cellNr<4; cellNr++)  
            {  
                // compute corresponding cell nr  
                int cellx = blockx;  
                int celly = blocky;  
                if (cellNr==1) celly++;  
                if (cellNr==2) cellx++;  
                if (cellNr==3)  
                {  
                    cellx++;  
                    celly++;  
                }  
                for (int bin=0; bin<gradientBinSize; bin++)  
                {  
                    float gradientStrength = descriptorValues[ descriptorDataIdx ];  
                    descriptorDataIdx++;  
                    gradientStrengths[celly][cellx][bin] += gradientStrength;  
                } // for (all bins)  
                // note: overlapping blocks lead to multiple updates of this sum!  
                // we therefore keep track how often a cell was updated,  
                // to compute average gradient strengths  
                cellUpdateCounter[celly][cellx]++;  
            } // for (all cells)  
        } // for (all block x pos)  
    } // for (all block y pos)  


    // compute average gradient strengths  
    for (int celly=0; celly<cells_in_y_dir; celly++)  
    {  
        for (int cellx=0; cellx<cells_in_x_dir; cellx++)  
        {  

            float NrUpdatesForThisCell = (float)cellUpdateCounter[celly][cellx];  

            // compute average gradient strenghts for each gradient bin direction  
            for (int bin=0; bin<gradientBinSize; bin++)  
            {  
                gradientStrengths[celly][cellx][bin] /= NrUpdatesForThisCell;  
            }  
        }  
    }  


    cout << "descriptorDataIdx = " << descriptorDataIdx << endl;  

    // draw cells  
    for (int celly=0; celly<cells_in_y_dir; celly++)  
    {  
        for (int cellx=0; cellx<cells_in_x_dir; cellx++)  
        {  
            int drawX = cellx * cellSize.width;  
            int drawY = celly * cellSize.height;  

            int mx = drawX + cellSize.width/2;  
            int my = drawY + cellSize.height/2;  

            rectangle(visual_image,  
                Point(drawX*scaleFactor,drawY*scaleFactor),  
                Point((drawX+cellSize.width)*scaleFactor,  
                (drawY+cellSize.height)*scaleFactor),  
                CV_RGB(100,100,100),  
                1);  

            // draw in each cell all 9 gradient strengths  
            for (int bin=0; bin<gradientBinSize; bin++)  
            {  
                float currentGradStrength = gradientStrengths[celly][cellx][bin];  

                // no line to draw?  
                if (currentGradStrength==0)  
                    continue;  

                float currRad = bin * radRangeForOneBin + radRangeForOneBin/2;  

                float dirVecX = cos( currRad );  
                float dirVecY = sin( currRad );  
                float maxVecLen = cellSize.width/2;  
                float scale = viz_factor; // just a visual_imagealization scale,  
                // to see the lines better  

                // compute line coordinates  
                float x1 = mx - dirVecX * currentGradStrength * maxVecLen * scale;  
                float y1 = my - dirVecY * currentGradStrength * maxVecLen * scale;  
                float x2 = mx + dirVecX * currentGradStrength * maxVecLen * scale;  
                float y2 = my + dirVecY * currentGradStrength * maxVecLen * scale;  

                // draw gradient visual_imagealization  
                line(visual_image,  
                    Point(x1*scaleFactor,y1*scaleFactor),  
                    Point(x2*scaleFactor,y2*scaleFactor),  
                    CV_RGB(0,0,255),  
                    1);  

            } // for (all bins)  

        } // for (cellx)  
    } // for (celly)  


    // don't forget to free memory allocated by helper data structures!  
    for (int y=0; y<cells_in_y_dir; y++)  
    {  
        for (int x=0; x<cells_in_x_dir; x++)  
        {  
            delete[] gradientStrengths[y][x];              
        }  
        delete[] gradientStrengths[y];  
        delete[] cellUpdateCounter[y];  
    }  
    delete[] gradientStrengths;  
    delete[] cellUpdateCounter;  

    return visual_image;  
}  


int main()  
{  
    HOGDescriptor hog;  
    hog.winSize=Size(904,600);  
    vector<float> des;  
    Mat src = imread("timg.jpg");  
    Mat dst ;  
    resize(src,dst,Size(904,600));  
    imshow("src",src);  
    hog.compute(dst,des);  
    cout<<des.size()<<endl;
    Mat background = Mat::zeros(Size(904,600),CV_8UC1);
    Mat background_hog = get_hogdescriptor_visual_image(background,des,hog.winSize,hog.cellSize,1,2.0);  
    imshow("HOG特征1",background_hog);  
    imwrite("特征可视化1.jpg",background_hog);
    Mat src_hog = get_hogdescriptor_visual_image(src,des,hog.winSize,hog.cellSize,1,2.0); 
    imshow("HOG特征2",src_hog);  
    imwrite("特征可视化2.jpg",src_hog);
    waitKey();  
    return 0;  
}  
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197

这里写图片描述
这里写图片描述

这里写图片描述

    • 1
      点赞
    • 4
      收藏
      觉得还不错? 一键收藏
    • 0
      评论

    “相关推荐”对你有帮助么?

    • 非常没帮助
    • 没帮助
    • 一般
    • 有帮助
    • 非常有帮助
    提交
    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值