void fhogToCol(const cv::Mat& img, cv::Mat& cvFeatures, int binSize, int colIdx, PRIMITIVE_TYPE cosFactor) { const int orientations = 9; // ensure array is continuous const cv::Mat& image = (img.isContinuous() ? img : img.clone()); int channels = image.channels(); int computeChannels = 32; int width = image.cols; int height = image.rows; int widthBin = width / binSize; int heightBin = height / binSize; CV_Assert(channels == 1 || channels == 3); CV_Assert(cvFeatures.channels() == 1 && cvFeatures.isContinuous()); float* const H = (float*)wrCalloc(static_cast<size_t>(widthBin * heightBin * computeChannels), sizeof(float)); float* const I = (float*)wrCalloc(static_cast<size_t>(width * height * channels), sizeof(float)); float* const M = (float*)wrCalloc(static_cast<size_t>(width * height), sizeof(float)); float* const O = (float*)wrCalloc(static_cast<size_t>(width * height), sizeof(float)); // row major (interleaved) to col major (non-interleaved;clustered;block) float* imageData = reinterpret_cast<float*>(image.data); float* const redChannel = I; float* const greenChannel = I + width * height; float* const blueChannel = I + 2 * width * height; int colMajorPos = 0, rowMajorPos = 0; for (int row = 0; row < height; ++row) { for (int col = 0; col < width; ++col) { colMajorPos = col * height + row; rowMajorPos = row * channels * width + col * channels; blueChannel[colMajorPos] = imageData[rowMajorPos]; greenChannel[colMajorPos] = imageData[rowMajorPos + 1]; redChannel[colMajorPos] = imageData[rowMajorPos + 2]; } } // calc fhog in col major gradMag(I, M, O, height, width, channels, true); fhog(M, O, H, height, width, binSize, orientations, -1, 0.2f); // the order of rows in cvFeatures does not matter // as long as it is the same for all columns; // zero channel is not copied as it is the last // channel in H and cvFeatures rows doesn't include it PRIMITIVE_TYPE* cdata = reinterpret_cast<PRIMITIVE_TYPE*>(cvFeatures.data); int outputWidth = cvFeatures.cols; for (int row = 0; row < cvFeatures.rows; ++row) { cdata[outputWidth * row + colIdx] = H[row] * cosFactor; } wrFree(H); wrFree(M); wrFree(O); wrFree(I); }
void fhogToCvColT(const cv::Mat& img, cv::Mat& cvFeatures, int binSize, int colIdx, PRIMITIVE_TYPE cosFactor) { const int orientations = 9; // ensure array is continuous const cv::Mat& image = (img.isContinuous() ? img : img.clone()); int channels = image.channels(); int computeChannels = 32; int width = image.cols; int height = image.rows; int widthBin = width / binSize; int heightBin = height / binSize; CV_Assert(channels == 1 || channels == 3); CV_Assert(cvFeatures.channels() == 1 && cvFeatures.isContinuous()); float* const H = (float*)wrCalloc(static_cast<size_t>(widthBin * heightBin * computeChannels), sizeof(float)); float* const M = (float*)wrCalloc(static_cast<size_t>(width * height), sizeof(float)); float* const O = (float*)wrCalloc(static_cast<size_t>(width * height), sizeof(float)); float* I = NULL; if (channels == 1) { I = reinterpret_cast<float*>(image.data); } else { I = (float*)wrCalloc(static_cast<size_t>(width * height * channels), sizeof(float)); float* imageData = reinterpret_cast<float*>(image.data); float* redChannel = I; float* greenChannel = I + width * height; float* blueChannel = I + 2 * width * height; for (int i = 0; i < height * width; ++i) { blueChannel[i] = imageData[i * 3]; greenChannel[i] = imageData[i * 3 + 1]; redChannel[i] = imageData[i * 3 + 2]; } } // calc fhog in col major - switch width and height gradMag(I, M, O, width, height, channels, true); fhog(M, O, H, width, height, binSize, orientations, -1, 0.2f); // the order of rows in cvFeatures does not matter // as long as it is the same for all columns; // zero channel is not copied as it is the last // channel in H and cvFeatures rows doesn't include it PRIMITIVE_TYPE* cdata = reinterpret_cast<PRIMITIVE_TYPE*>(cvFeatures.data); int outputWidth = cvFeatures.cols; for (int row = 0; row < cvFeatures.rows; ++row) { cdata[outputWidth * row + colIdx] = H[row] * cosFactor; } wrFree(H); wrFree(M); wrFree(O); if (channels != 1) { wrFree(I); } }
// pad A by [pt,pb,pl,pr] and store result in B template<class T> void imPad( T *A, T *B, int h, int w, int d, int pt, int pb, int pl, int pr, int flag, T val ) { int h1=h+pt, hb=h1+pb, w1=w+pl, wb=w1+pr, x, y, z, mPad; int ct=0, cb=0, cl=0, cr=0; if(pt<0) { ct=-pt; pt=0; } if(pb<0) { h1+=pb; cb=-pb; pb=0; } if(pl<0) { cl=-pl; pl=0; } if(pr<0) { w1+=pr; cr=-pr; pr=0; } int *xs, *ys; x=pr>pl?pr:pl; y=pt>pb?pt:pb; mPad=x>y?x:y; bool useLookup = ((flag==2 || flag==3) && (mPad>h || mPad>w)) || (flag==3 && (ct || cb || cl || cr )); // helper macro for padding #define PAD(XL,XM,XR,YT,YM,YB) \ for(x=0; x<pl; x++) for(y=0; y<pt; y++) B[x*hb+y]=A[(XL+cl)*h+YT+ct]; \ for(x=0; x<pl; x++) for(y=pt; y<h1; y++) B[x*hb+y]=A[(XL+cl)*h+YM+ct]; \ for(x=0; x<pl; x++) for(y=h1; y<hb; y++) B[x*hb+y]=A[(XL+cl)*h+YB-cb]; \ for(x=pl; x<w1; x++) for(y=0; y<pt; y++) B[x*hb+y]=A[(XM+cl)*h+YT+ct]; \ for(x=pl; x<w1; x++) for(y=h1; y<hb; y++) B[x*hb+y]=A[(XM+cl)*h+YB-cb]; \ for(x=w1; x<wb; x++) for(y=0; y<pt; y++) B[x*hb+y]=A[(XR-cr)*h+YT+ct]; \ for(x=w1; x<wb; x++) for(y=pt; y<h1; y++) B[x*hb+y]=A[(XR-cr)*h+YM+ct]; \ for(x=w1; x<wb; x++) for(y=h1; y<hb; y++) B[x*hb+y]=A[(XR-cr)*h+YB-cb]; // build lookup table for xs and ys if necessary if( useLookup ) { xs = (int*) wrMalloc(wb*sizeof(int)); int h2=(pt+1)*2*h; ys = (int*) wrMalloc(hb*sizeof(int)); int w2=(pl+1)*2*w; if( flag==2 ) { for(x=0; x<wb; x++) { z=(x-pl+w2)%(w*2); xs[x]=z<w ? z : w*2-z-1; } for(y=0; y<hb; y++) { z=(y-pt+h2)%(h*2); ys[y]=z<h ? z : h*2-z-1; } } else if( flag==3 ) { for(x=0; x<wb; x++) xs[x]=(x-pl+w2)%w; for(y=0; y<hb; y++) ys[y]=(y-pt+h2)%h; } } // pad by appropriate value for( z=0; z<d; z++ ) { // copy over A to relevant region in B for( x=0; x<w-cr-cl; x++ ) memcpy(B+(x+pl)*hb+pt,A+(x+cl)*h+ct,sizeof(T)*(h-ct-cb)); // set boundaries of B to appropriate values if( flag==0 && val!=0 ) { // "constant" for(x=0; x<pl; x++) for(y=0; y<hb; y++) B[x*hb+y]=val; for(x=pl; x<w1; x++) for(y=0; y<pt; y++) B[x*hb+y]=val; for(x=pl; x<w1; x++) for(y=h1; y<hb; y++) B[x*hb+y]=val; for(x=w1; x<wb; x++) for(y=0; y<hb; y++) B[x*hb+y]=val; } else if( useLookup ) { // "lookup" PAD( xs[x], xs[x], xs[x], ys[y], ys[y], ys[y] ); } else if( flag==1 ) { // "replicate" PAD( 0, x-pl, w-1, 0, y-pt, h-1 ); } else if( flag==2 ) { // "symmetric" PAD( pl-x-1, x-pl, w+w1-1-x, pt-y-1, y-pt, h+h1-1-y ); } else if( flag==3 ) { // "circular" PAD( x-pl+w, x-pl, x-pl-w, y-pt+h, y-pt, y-pt-h ); } A += h*w; B += hb*wb; } if( useLookup ) { wrFree(xs); wrFree(ys); } #undef PAD }
// compute HOG features void hog( float *M, float *O, float *H, int h, int w, int binSize, int nOrients, int softBin, bool full, float clip ) { float *N, *R; const int hb=h/binSize, wb=w/binSize, nb=hb*wb; // compute unnormalized gradient histograms R = (float*) wrCalloc(wb*hb*nOrients,sizeof(float)); gradHist( M, O, R, h, w, binSize, nOrients, softBin, full ); // compute block normalization values N = hogNormMatrix( R, nOrients, hb, wb, binSize ); // perform four normalizations per spatial block hogChannels( H, R, N, hb, wb, nOrients, clip, 0 ); wrFree(N); wrFree(R); }
// compute FHOG features void fhog( float *M, float *O, float *H, int h, int w, int binSize, int nOrients, int softBin, float clip ) { const int hb=h/binSize, wb=w/binSize, nb=hb*wb, nbo=nb*nOrients; float *N, *R1, *R2; int o, x; // compute unnormalized constrast sensitive histograms R1 = (float*) wrCalloc(wb*hb*nOrients*2,sizeof(float)); gradHist( M, O, R1, h, w, binSize, nOrients*2, softBin, true ); // compute unnormalized contrast insensitive histograms R2 = (float*) wrCalloc(wb*hb*nOrients,sizeof(float)); for( o=0; o<nOrients; o++ ) for( x=0; x<nb; x++ ) R2[o*nb+x] = R1[o*nb+x]+R1[(o+nOrients)*nb+x]; // compute block normalization values N = hogNormMatrix( R2, nOrients, hb, wb, binSize ); // normalized histograms and texture channels hogChannels( H+nbo*0, R1, N, hb, wb, nOrients*2, clip, 1 ); hogChannels( H+nbo*2, R2, N, hb, wb, nOrients*1, clip, 1 ); hogChannels( H+nbo*3, R1, N, hb, wb, nOrients*2, clip, 2 ); wrFree(N); mxFree(R1); wrFree(R2); }
// compute HOG features given gradient histograms void hog( float *H, float *G, int h, int w, int bin, int nOrients, float clip ){ float *N, *N1, *H1; int o, x, y, hb=h/bin, wb=w/bin, nb=wb*hb; float eps = 1e-4f/4/bin/bin/bin/bin; // precise backward equality // compute 2x2 block normalization values N = (float*) wrCalloc(nb,sizeof(float)); for( o=0; o<nOrients; o++ ) for( x=0; x<nb; x++ ) N[x]+=H[x+o*nb]*H[x+o*nb]; for( x=0; x<wb-1; x++ ) for( y=0; y<hb-1; y++ ) { N1=N+x*hb+y; *N1=1/float(sqrt( N1[0] + N1[1] + N1[hb] + N1[hb+1] +eps )); } // perform 4 normalizations per spatial block (handling boundary regions) #define U(a,b) Gs[a][y]=H1[y]*N1[y-(b)]; if(Gs[a][y]>clip) Gs[a][y]=clip; for( o=0; o<nOrients; o++ ) for( x=0; x<wb; x++ ) { H1=H+o*nb+x*hb; N1=N+x*hb; float *Gs[4]; Gs[0]=G+o*nb+x*hb; for( y=1; y<4; y++ ) Gs[y]=Gs[y-1]+nb*nOrients; bool lf, md, rt; lf=(x==0); rt=(x==wb-1); md=(!lf && !rt); y=0; if(!rt) U(0,0); if(!lf) U(2,hb); if(lf) for( y=1; y<hb-1; y++ ) { U(0,0); U(1,1); } if(md) for( y=1; y<hb-1; y++ ) { U(0,0); U(1,1); U(2,hb); U(3,hb+1); } if(rt) for( y=1; y<hb-1; y++ ) { U(2,hb); U(3,hb+1); } y=hb-1; if(!rt) U(1,1); if(!lf) U(3,hb+1); } wrFree(N); #undef U }
void alFree(void *aligned) { void* raw = *(void**)((char*)aligned-sizeof(void*)); wrFree(raw); }
// platform independent alignned memory de-allocation (see also alMalloc) inline void alFree(void* aligned) { const size_t pSize = sizeof(void*); void* raw = *(void**)((char*)aligned - pSize); wrFree(raw); }
pyrOutput* chnsPyramid(float *image, pyrInput *input){ /* * Declaring variables */ float *I; int height = input->sz[0], width = input->sz[1], heightO = input->sz[0], widthO = input->sz[1], channels = input->sz[2]; int heightOriginal = height, widthOriginal = width; int misalign = 1; int sOfF = sizeof(float); /* * Get default parameters pPyramid */ if ( !input->complete ){ if(input->nApprox<0) input->nApprox = input->nPerOct - 1; input->pchns->pGradHist->binSize = input->shrink; input->pad[0] = round(input->pad[0]/input->shrink) * input->shrink; input->pad[1] = round(input->pad[1]/input->shrink) * input->shrink; input->minDs[0] = max(input->minDs[0], input->shrink * 4); input->minDs[1] = max(input->minDs[1], input->shrink * 4); input->complete = true; } /* * Convert I to appropriate color space (or simply normalize) */ int cs = input->pchns->pColor->colorSpace; I = rgbConvert(image, height*width, channels, cs, 1.0f); input->pchns->pColor->colorSpace = orig; /* * Get scales at which to compute features and list of real/approx scales */ float *scales = 0; float *scaleshw = 0; int nScales = getScales(scales, scaleshw, input->nPerOct, input->nOctUp, input->minDs, input->shrink, input->sz); //TODO :: WARNING :: This was done in the Dollar's Code int isRMax; if(true) isRMax = 0; else isRMax = 0 + input->nOctUp * input->nPerOct; //TODO :: WARNING :: END int *isR, *isA, *isN; //isR Vector Allocation int countIsR = 0; for ( int i = isRMax; i < nScales; i += (input->nApprox + 1) ) countIsR++; isR = new int[countIsR]; for ( int i = isRMax, j = 0; i < nScales; j++, i += (input->nApprox + 1) ) isR[j] = i; //isA and isN Vector Allocation int countIsA = nScales - countIsR; int countIsN = nScales; isA = new int[countIsA]; isN = new int[countIsN]; for ( int i = 0, auxI = 0; i < nScales; i++){ bool ok = true; for (int j = 0; j < countIsR; j++) if(i == isR[j]){ ok = false; break; } if (ok){ isA[auxI] = i; auxI++; } isN[i] = i; } int *auxIsJ; auxIsJ = new int[countIsR + 1]; auxIsJ[0] = 0; auxIsJ[countIsR] = nScales; for (int i = 0; i < countIsR - 1; i++) auxIsJ[i+1] = floor((isR[i] + 1 + isR[i+1] + 1) / 2); // " +1 " because we are in c++ and the vector already assumes the first // element to be index 0. for (int i = 0; i < countIsR; i++){ int minJ = auxIsJ[i]; int maxJ = auxIsJ[i+1]; for (int j = minJ; j < maxJ; j++) isN[j] = isR[i]; } /* * Compute image pyramid [real scales] */ int nTypes = 0; imgWrap ***data = (imgWrap ***) wrCalloc(nScales, sizeof(imgWrap**)); int shrink = input->shrink; float shr[3] = { 0, 0, 0}; for (int it = 0, i = isR[0]; it < countIsR; it++, i=isR[it]){ float scale = scales[i]; int newHeight = round((float) heightO * (float) scale / (float) shrink) * shrink; int newWidth = round((float) widthO * (float) scale / (float) shrink) * shrink; float *I1; if ( height == newHeight && width == newWidth){ //TODO :: WARNING :: Should I copy it over? I1 = (float*) wrCalloc(height*width*channels + misalign, sOfF) + misalign; int lengthArray = height*width*channels; for (int j = 0; j < lengthArray; j++) I1[j] = I[j]; }else{ I1 = (float*) wrCalloc(newHeight*newWidth*channels + misalign, sOfF) + misalign; //TODO :: WARNING :: Hardcoded value :: 1.f resample(I, I1, height, newHeight, width, newWidth, channels, 1.f); } if (scale == 0.5f && (input->nApprox > 0 || input->nPerOct == 1)){ //TODO :: WARNING :: Should I free "I"? // I replace old I with new I1, as I reduced the image to half size free(I); I = I1; height = newHeight; width = newWidth; } //TODO :: WARNING :: Hardcoded value :: downsample float *I2 = 0; int downsample = 1; convTriAux(I1, I2, misalign, newHeight, newWidth, channels, input->smoothIm, downsample ); /* * Channels Compute for this isR[i] scale */ infoOut *chns = chnsCompute(I2, newHeight, newWidth, channels, input->pchns ); imgWrap **data1 = chns->data; wrFree(I2-misalign); nTypes = chns->nTypes; if (i == isR[0]){ /* * This is checking the size of each transformation. By design only * the H channel will have the correct dimensions. */ for (int j = 0; j < nTypes; j++){ shr[j] = data1[j]->height; shr[j] = newHeight / shr[j]; if (shr[j] > shrink || (int)shr[j] % 1 > 0){ cout << "Something went wrong with the shrinking." << endl << "Source code line: " << __FILE__ << " @ " << __LINE__ << endl; return NULL; //This should never happen } shr[j]=shr[j]/shrink; } } for(int j = 0; j < nTypes; j++){ if (shr[j] == 1) continue; int nH = newHeight*shr[j], nW = newWidth*shr[j], chnsTransform = data1[j]->channels; float *chnTypeData = (float*) wrCalloc(nH*nW*channels + misalign, sOfF) + misalign; //TODO :: WARNING :: Hardcoded value :: 1.f resample(data1[j]->image, chnTypeData, newHeight, nH, newWidth, nW, chnsTransform, 1.f ); data1[j]->height = nH; data1[j]->width = nW; wrFree(data1[j]->image - misalign); data1[j]->image = chnTypeData; } data[i] = data1; } // In case I changed it when scale = 0.5f height = heightO; width = widthO; /* * If lambdas not specified compute image specific lambdas */ int nApprox = input->nApprox; float *lambdas = input->lambdas; if ( nApprox > 0 && !lambdas){ int nOctUp = input->nOctUp; int nPerOct = input->nPerOct; //TODO :: WARNING :: Yet again I start at 0. // The is Vector :: is=1 + nOctUp*nPerOct:nApprox+1:nScales; int countIs = 0; int *isTemp = new int[nScales]; for (int i = nOctUp*nPerOct; i < nScales; i += nApprox + 1){ isTemp[countIs] = i; countIs++; } if (countIs > 2){ isTemp[0] = isTemp[1]; isTemp[1] = isTemp[2]; }else{ cout << "Couldn't calculate lambdas. Not enough scales to use." << endl << "Source code line: " << __FILE__ << " @ " << __LINE__ << endl; return NULL; } float *f0 = new float[nTypes]; float *f1 = new float[nTypes]; imgWrap **d0 = data[isTemp[0]]; imgWrap **d1 = data[isTemp[1]]; for (int i = 0; i < nTypes; i++){ float numElem = (float) (d0[i]->width * d0[i]->height * d0[i]->channels); float sumElem = 0.f; for (int j = 0; j < numElem; j++) sumElem += d0[i]->image[j]; f0[i] = sumElem / numElem; } for (int i = 0; i < nTypes; i++){ float numElem = (float) (d1[i]->width * d1[i]->height * d1[i]->channels); float sumElem = 0.f; for (int j = 0; j < numElem; j++) sumElem += d1[i]->image[j]; f1[i] = sumElem / numElem; } lambdas = new float[nTypes]; float lambdaValue = log2(scales[isTemp[0]] / scales[isTemp[1]]); for (int i = 0; i < nTypes; i++) lambdas[i] = -log2(f0[i] / f1[i]) / lambdaValue; } /* * Compute image pyramid [approximated scales] */ shrink = input->shrink; for (int it = 0, i = isA[0]; it < countIsA; it++, i=isA[it]){ int iR = isN[i]; float scale = scales[i]; //TODO :: WARNING :: The value height may have been modified to half of // it, hence using heightOriginal (width) int newHeight = round((float) heightOriginal * (float) scale / (float) shrink); int newWidth = round((float) widthOriginal * (float) scale / (float) shrink); float scaleRatio = (scale / scales[iR]); float *rs = new float[nTypes]; for (int j = 0; j < nTypes; j++) rs[j] = pow(scaleRatio, -lambdas[j] ); imgWrap **dataImgA = (imgWrap **) wrCalloc(nTypes, sizeof(imgWrap*)); imgWrap **dataImgR = data[iR]; for (int j = 0; j < nTypes; j++){ int ijChannels = dataImgR[j]->channels; float *isAimage = (float*) wrCalloc(newHeight*newWidth*ijChannels + misalign, sOfF) + misalign; //TODO :: WARNING :: Hardcoded value resample(dataImgR[j]->image, isAimage, dataImgR[j]->height, newHeight, dataImgR[j]->width, newWidth, ijChannels, rs[j]); dataImgA[j] = new imgWrap(isAimage, newWidth, newHeight,ijChannels); } data[i] = dataImgA; delete [] rs; } /* * Smooth channels, optionally pad and concatenate channels */ int downSample = 1; // WARNING : This is the default by dollar int s = downSample; for (int i = 0; i < nScales; i++){ for (int j = 0; j < nTypes; j++){ float *S; int height = data[i][j]->height; int width = data[i][j]->width; int channel = data[i][j]->channels; /* * Smoothing Channels */ convTriAux(data[i][j]->image, S, misalign, height, width, channel, input->smoothChns, s ); wrFree(data[i][j]->image - misalign); /* * Padding according to the scale. Then change the shrink value. */ int padTB = input->pad[0] / shrink, padLR = input->pad[1] / shrink; if (padTB > 0 || padLR > 0){ int newHeight = height + padTB * 2; int newWidth = width + padLR * 2; float *P = (float*) wrCalloc(newHeight*newWidth*channel + misalign, sOfF) + misalign; imPad(S, P, height, width, channel, padTB, padTB, padLR, padLR, padvalue, 0.f ); wrFree(S - misalign); data[i][j]->height = newHeight; data[i][j]->width = newWidth; S = P; } data[i][j]->image = S; } } /* * Concatenate. */ int totalChannels = 0; for (int j = 0; j < nTypes; j++) totalChannels += data[0][j]->channels; if(input->concat){ int chnsArr[nTypes]; for (int j = 0; j < nTypes; j++) chnsArr[j] = data[0][j]->channels; for (int i = 0; i < nScales; i++){ int height = data[i][0]->height; int width = data[i][0]->width; float *imgC = (float*) wrCalloc(height*width*totalChannels + misalign, sOfF) + misalign; int totalSize = 0; for (int j = 0; j < nTypes; j++){ float *imgO = data[i][j]->image; copy(imgO, imgO + height*width*chnsArr[j], imgC + totalSize); totalSize += height*width*chnsArr[j]; } for (int j=1; j < nTypes; j++){ wrFree(data[i][j]->image - misalign); wrFree(data[i][j]); } wrFree(data[i][0]->image - misalign); data[i][0]->image = imgC; data[i][0]->channels = totalChannels; } } /* * Create output struct */ pyrOutput *output = new pyrOutput(); output->input = input; output->chnsPerScale = data; output->nScales = nScales; output->scales = scales; output->nChannels = totalChannels; /* * Clean Memory */ delete [] isR; delete [] isA; delete [] isN; delete [] lambdas; delete [] scaleshw; /* * Output */ return output; }
void cvFhogT(const cv::Mat& img, std::shared_ptr<OUT>& cvFeatures, int binSize, int fhogChannelsToCopy = 31) { const int orientations = 9; // ensure array is continuous const cv::Mat& image = (img.isContinuous() ? img : img.clone()); int channels = image.channels(); int computeChannels = 32; int width = image.cols; int height = image.rows; int widthBin = width / binSize; int heightBin = height / binSize; CV_Assert(channels == 1 || channels == 3); float* const H = (float*)wrCalloc(static_cast<size_t>(widthBin * heightBin * computeChannels), sizeof(float)); float* const M = (float*)wrCalloc(static_cast<size_t>(width * height), sizeof(float)); float* const O = (float*)wrCalloc(static_cast<size_t>(width * height), sizeof(float)); float* I = NULL; if (channels == 1) { I = reinterpret_cast<float*>(image.data); } else { I = (float*)wrCalloc(static_cast<size_t>(width * height * channels), sizeof(float)); float* imageData = reinterpret_cast<float*>(image.data); float* redChannel = I; float* greenChannel = I + width * height; float* blueChannel = I + 2 * width * height; for (int i = 0; i < height * width; ++i) { blueChannel[i] = imageData[i * 3]; greenChannel[i] = imageData[i * 3 + 1]; redChannel[i] = imageData[i * 3 + 2]; } } // calc fhog in col major - switch width and height gradMag(I, M, O, width, height, channels, true); if (fhogChannelsToCopy == 27) { fhog(M, O, H, width, height, binSize, orientations, -1, 0.2f, false); } else { fhog(M, O, H, width, height, binSize, orientations, -1, 0.2f); } // only copy the amount of the channels the user wants // or the amount that fits into the output array int channelsToCopy = std::min(fhogChannelsToCopy, OUT::numberOfChannels()); // init channels for (int c = 0; c < channelsToCopy; ++c) { cv::Mat_<PRIMITIVE_TYPE> m(heightBin, widthBin); cvFeatures->channels[c] = m; } PRIMITIVE_TYPE* cdata = 0; // implicit transpose on every channel due to col-major to row-major matrix for (int c = 0; c < channelsToCopy; ++c) { float* Hc = H + widthBin * heightBin * c; cdata = reinterpret_cast<PRIMITIVE_TYPE*>(cvFeatures->channels[c].data); for (int i = 0; i < heightBin * widthBin; ++i) { cdata[i] = Hc[i]; } } wrFree(M); wrFree(O); if (channels != 1) { wrFree(I); } wrFree(H); }
void cvFhog(const cv::Mat& img, std::shared_ptr<OUT>& cvFeatures, int binSize, int fhogChannelsToCopy = 31) { const int orientations = 9; // ensure array is continuous const cv::Mat& image = (img.isContinuous() ? img : img.clone()); int channels = image.channels(); int computeChannels = 32; int width = image.cols; int height = image.rows; int widthBin = width / binSize; int heightBin = height / binSize; float* const I = (float*)wrCalloc(static_cast<size_t>(width * height * channels), sizeof(float)); float* const H = (float*)wrCalloc(static_cast<size_t>(widthBin * heightBin * computeChannels), sizeof(float)); float* const M = (float*)wrCalloc(static_cast<size_t>(width * height), sizeof(float)); float* const O = (float*)wrCalloc(static_cast<size_t>(width * height), sizeof(float)); // row major (interleaved) to col major (non interleaved;clustered) float* imageData = reinterpret_cast<float*>(image.data); float* const redChannel = I; float* const greenChannel = I + width * height; float* const blueChannel = I + 2 * width * height; int colMajorPos = 0, rowMajorPos = 0; for (int row = 0; row < height; ++row) { for (int col = 0; col < width; ++col) { colMajorPos = col * height + row; rowMajorPos = row * channels * width + col * channels; blueChannel[colMajorPos] = imageData[rowMajorPos]; greenChannel[colMajorPos] = imageData[rowMajorPos + 1]; redChannel[colMajorPos] = imageData[rowMajorPos + 2]; } } // calc fhog in col major gradMag(I, M, O, height, width, channels, true); if (fhogChannelsToCopy == 27) { fhog(M, O, H, height, width, binSize, orientations, -1, 0.2f, false); } else { fhog(M, O, H, height, width, binSize, orientations, -1, 0.2f); } // only copy the amount of the channels the user wants // or the amount that fits into the output array int channelsToCopy = std::min(fhogChannelsToCopy, OUT::numberOfChannels()); for (int c = 0; c < channelsToCopy; ++c) { cv::Mat_<PRIMITIVE_TYPE> m(heightBin, widthBin); cvFeatures->channels[c] = m; } PRIMITIVE_TYPE* cdata = 0; //col major to row major with separate channels for (int c = 0; c < channelsToCopy; ++c) { float* Hc = H + widthBin * heightBin * c; cdata = reinterpret_cast<PRIMITIVE_TYPE*>(cvFeatures->channels[c].data); for (int row = 0; row < heightBin; ++row) for (int col = 0; col < widthBin; ++col) { cdata[row * widthBin + col] = Hc[row + heightBin * col]; } } wrFree(M); wrFree(O); wrFree(I); wrFree(H); }