Visual Description
In the previous blog hog principle and OPENCV implementation, we explained the principle of hog algorithm. The final feature is a string of vectors, and we don't know exactly what it looks like, or whether it can reflect the difference between the target area and the non-target region. To solve this problem, we need to visualize the hog feature.
The Hog feature first calculates the gradient of each pixel, then creates a sliding window, creates a sliding block in the sliding window, and creates an equal unit (cell) in the block. We think about this process, when a block is sliding, each contains a different unit, but for a unit, it does not change with the block sliding. This means that if the block size, block step, and cell size are determined, the number of cells in a window and the pixels contained in each of them are determined. The visualization of hog is to take advantage of this, and what it visualizes is a bin poll result within a unit.
To make the following process more intuitive, we use the entire image as a test window, meaning that there is no concept of sliding windows.
In particular, this should be the place where hog is most likely to produce anomalies. The picture below was originally a 900x600 900x600 900\times600 size, but I scaled it to 904x600 904x600 904\times600. This is to allow 904 of the range to slide out of the whole number of blocks, because at this time hog is using the default parameters, namely the block size 16x16 16x16 16\TIMES16, block step 8x8 8x8 8\times8.
900−168=110.5 900−16 8 = 110.5 \frac{900-16}{8}=110.5
904−168=111 904−16 8 = 111 \frac{904-16}{8}=111
Code Implementation
#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_HOGDESCR Iptor_visual_image (mat& origimg, vector<float>& descriptorvalues, size winsize, size CellS
ize, 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/cel
Lsize.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; bl ocky++) {//4 cells per block ... for (int cellnr=0; cellnr<4; Celln
r++) {//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 Gradien
Tstrength = descriptorvalues[Descriptordataidx];
descriptordataidx++;
Gradientstrengths[celly][cellx][bin] + = gradientstrength; }//for (all bins)//NOTE: Overlapping blocks leads to multiple updates of this sum!
We therefore keep track how often a cell is updated,//to compute average gradient strengths
cellupdatecounter[celly][cellx]++; }//for (all cells)}//for (all Block x POS)}//for (all Block y pos)//COMPUTE average Grad Ient strengths for (int celly=0, celly<cells_in_y_dir; celly++) {for (int cellx=0; Cellx<cell S_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; DrawCells for (int celly=0, celly<cells_in_y_dir; celly++) {for (int cellx=0; cellx<cells_in_x_di R
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+cells
Ize.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 COO
rdinates 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 a
Llocated 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 characteristic 1", background_hog);
Imwrite ("Feature visualization 1.jpg", Background_hog);
Mat Src_hog = Get_hogdescriptor_visual_image (src,des,hog.winsize,hog.cellsize,1,2.0);
Imshow ("Hog characteristic 2", src_hog);
Imwrite ("Feature visualization 2.jpg", Src_hog);
Waitkey ();
return 0; }