cv::Mat ParImageToIplImage(DImage& img) { int width = img.width(); int height = img.height(); int nChannels = img.nchannels(); if(width <= 0 || height <= 0 || nChannels != 1) return cv::Mat(); BaseType*& pData = img.data(); cv::Mat image = cv::Mat(height, width, CV_MAKETYPE(8, 1)); for(int i = 0;i < height;i++) { for(int j = 0;j < width;j++) { image.ptr<uchar>(i)[j] = pData[i*width + j] * 255; } } return image; }
void OpticalFlow::estGaussianMixture(const DImage& Im1,const DImage& Im2,GaussianMixture& para,double prior) { int nIterations = 3, nChannels = Im1.nchannels(); DImage weight1(Im1),weight2(Im1); double *total1,*total2; total1 = new double[nChannels]; total2 = new double[nChannels]; for(int count = 0; count<nIterations; count++) { double temp; memset(total1,0,sizeof(double)*nChannels); memset(total2,0,sizeof(double)*nChannels); // E step for(int i = 0;i<weight1.npixels();i++) for(int k=0;k<nChannels;k++) { int offset = i*weight1.nchannels()+k; temp = Im1[offset]-Im2[offset]; temp *= temp; weight1[offset] = para.Gaussian(temp,0,k)*para.alpha[k]; weight2[offset] = para.Gaussian(temp,1,k)*(1-para.alpha[k]); temp = weight1[offset]+weight2[offset]; weight1[offset]/=temp; weight2[offset]/=temp; total1[k] += weight1[offset]; total2[k] += weight2[offset]; } // M step para.reset(); for(int i = 0;i<weight1.npixels();i++) for(int k =0;k<nChannels;k++) { int offset = i*weight1.nchannels()+k; temp = Im1[offset]-Im2[offset]; temp *= temp; para.sigma[k]+= weight1[offset]*temp; para.beta[k] += weight2[offset]*temp; } for(int k =0;k<nChannels;k++) { para.alpha[k] = total1[k]/(total1[k]+total2[k])*(1-prior)+0.95*prior; // regularize alpha para.sigma[k] = sqrt(para.sigma[k]/total1[k]); para.beta[k] = sqrt(para.beta[k]/total2[k])*(1-prior)+0.3*prior; // regularize beta } para.square(); count = count; } }
DPlane DColorCluster::apply_clustering(const DImage &input) { DPlane result(input.rows(), input.cols()); for(int i=0; i<input.rows(); i++) for(int j=0; j<input.cols(); j++) { int closest_cluster=0; double min_dist=1000000000; DTriple sample(input[0][i][j], input[1][i][j], input[2][i][j]); for(int c=0; c<clusters.size(); c++) if(clusters[c].distance_to(sample) < min_dist) { min_dist = clusters[c].distance_to(sample); closest_cluster = c; } result[i][j] = closest_cluster+1; } return result; }
void GaussianPyramid::ConstructPyramidLevels(const DImage &image, double ratio, int _nLevels) { // the ratio cannot be arbitrary numbers if(ratio>0.98 || ratio<0.4) ratio=0.75; nLevels = _nLevels; if(ImPyramid!=NULL) delete []ImPyramid; ImPyramid=new DImage[nLevels]; ImPyramid[0].copyData(image); double baseSigma=(1/ratio-1); int n=log(0.25)/log(ratio); double nSigma=baseSigma*n; for(int i=1;i<nLevels;i++) { DImage foo; if(i<=n) { double sigma=baseSigma*i; image.GaussianSmoothing(foo,sigma,sigma*3); foo.imresize(ImPyramid[i],pow(ratio,i)); } else { ImPyramid[i-n].GaussianSmoothing(foo,nSigma,nSigma*3); double rate=(double)pow(ratio,i)*image.width()/foo.width(); foo.imresize(ImPyramid[i],rate); } } }
void WritePPMImage(const DImage &img, const char *filename) { FILE *fp = fopen(filename, "wb"); char temp[1024]; // write magic number fprintf(fp, "P6\n"); // write dimensions fprintf(fp, "%d %d\n", img.cols(), img.rows()); // write max pixel value fprintf(fp, "255\n"); for(int i=0; i<img.rows(); i++) for(int j=0; j<img.cols(); j++) for(int k=0; k<3; k++) fputc(int(img[k][i][j]), fp); fclose(fp); return; }
/**Each row of img is projected onto the vertical axis. Resulting data length will be equal to the height of img. The profile is a summation of the grayscale values in each row. If fNormalize is true, then each value is divided by img.width() so it is the average grayscale value for the row instead of the sum. If fNormalize is true, the resulting profile values are divided by the image width. */ void DProfile::getImageVerticalProfile(const DImage &img, bool fNormalize){ int w, h; w = img.width(); h = img.height(); // allocate the rgProf array if(NULL == rgProf){ rgProf = (double*)malloc(h * sizeof(double)); D_CHECKPTR(rgProf); len = h; } else{ if(len != h){ rgProf = (double*)realloc(rgProf,h*sizeof(double)); D_CHECKPTR(rgProf); len = h; } } switch(img.getImageType()){ case DImage::DImage_u8: { D_uint8 *pu8; pu8=img.dataPointer_u8(); for(int y = 0, idx=0; y < h; ++y){ rgProf[y] = 0.; for(int x = 0; x < w; ++x, ++idx){ rgProf[y] += pu8[idx]; } if(fNormalize) rgProf[y] /= w; } } break; case DImage::DImage_flt_multi: { float *pflt; if(img.numChannels() > 1){ fprintf(stderr,"DProfile::getImageVerticalProfile() floats only " "supported with a single channel\n"); abort(); } pflt=img.dataPointer_flt(0); for(int y = 0, idx=0; y < h; ++y){ rgProf[y] = 0.; for(int x = 0; x < w; ++x, ++idx){ rgProf[y] += pflt[idx]; } if(fNormalize) rgProf[y] /= w; } } break; default: fprintf(stderr, "Not yet implemented!\n"); abort(); }//end switch(img.getImageType()) }
//-------------------------------------------------------------------------------------- // function to perfomr coarse to fine optical flow estimation //-------------------------------------------------------------------------------------- void OpticalFlow::Coarse2FineFlow(DImage &vx, DImage &vy, DImage &warpI2,const DImage &Im1, const DImage &Im2, double alpha, double ratio, int minWidth, int nOuterFPIterations, int nInnerFPIterations, int nCGIterations) { // first build the pyramid of the two images GaussianPyramid GPyramid1; GaussianPyramid GPyramid2; if(IsDisplay) cout<<"Constructing pyramid..."; GPyramid1.ConstructPyramid(Im1,ratio,minWidth); GPyramid2.ConstructPyramid(Im2,ratio,minWidth); if(IsDisplay) cout<<"done!"<<endl; // now iterate from the top level to the bottom DImage Image1,Image2,WarpImage2; for(int k=GPyramid1.nlevels()-1; k>=0; k--) { if(IsDisplay) cout<<"Pyramid level "<<k; int width=GPyramid1.Image(k).width(); int height=GPyramid1.Image(k).height(); im2feature(Image1,GPyramid1.Image(k)); im2feature(Image2,GPyramid2.Image(k)); if(k==GPyramid1.nlevels()-1) // if at the top level { vx.allocate(width,height); vy.allocate(width,height); //warpI2.copyData(Image2); WarpImage2.copyData(Image2); } else { vx.imresize(width,height); vx.Multiplywith(1/ratio); vy.imresize(width,height); vy.Multiplywith(1/ratio); //warpFL(warpI2,GPyramid1.Image(k),GPyramid2.Image(k),vx,vy); warpFL(WarpImage2,Image1,Image2,vx,vy); } //SmoothFlowPDE(GPyramid1.Image(k),GPyramid2.Image(k),warpI2,vx,vy,alpha,nOuterFPIterations,nInnerFPIterations,nCGIterations); //SmoothFlowPDE(Image1,Image2,WarpImage2,vx,vy,alpha*pow((1/ratio),k),nOuterFPIterations,nInnerFPIterations,nCGIterations); SmoothFlowPDE(Image1,Image2,WarpImage2,vx,vy,alpha,nOuterFPIterations,nInnerFPIterations,nCGIterations); if(IsDisplay) cout<<endl; } warpFL(warpI2,Im1,Im2,vx,vy); }
bool OpticalFlow::showFlow(const DImage& flow,const char* filename) { if(flow.nchannels()!=1) { cout<<"The flow must be a single channel image!"<<endl; return false; } Image<unsigned char> foo; foo.allocate(flow.width(),flow.height()); double Max = flow.max(); double Min = flow.min(); for(int i = 0;i<flow.npixels(); i++) foo[i] = (flow[i]-Min)/(Max-Min)*255; foo.imwrite(filename); }
//-------------------------------------------------------------------------------------------------------- // function to compute dx, dy and dt for motion estimation //-------------------------------------------------------------------------------------------------------- void OpticalFlow::getDxs(DImage &imdx, DImage &imdy, DImage &imdt, const DImage &im1, const DImage &im2) { // Im1 and Im2 are the smoothed version of im1 and im2 DImage Im1,Im2; double gfilter[5]= {0.05,0.2,0.5,0.2,0.05}; im1.imfilter_hv(Im1,gfilter,2,gfilter,2); im2.imfilter_hv(Im2,gfilter,2,gfilter,2); //Im1.copyData(im1); //Im2.copyData(im2); Im2.dx(imdx,true); Im2.dy(imdy,true); imdt.Subtract(Im2,Im1); imdx.setDerivative(); imdy.setDerivative(); imdt.setDerivative(); }
void OpticalFlow::warpFL(DImage &warpIm2, const DImage &Im1, const DImage &Im2, const DImage &Flow) { if(warpIm2.matchDimension(Im2)==false) warpIm2.allocate(Im2.width(),Im2.height(),Im2.nchannels()); ImageProcessing::warpImageFlow(warpIm2.data(),Im1.data(),Im2.data(),Flow.data(),Im2.width(),Im2.height(),Im2.nchannels()); }
//------------------------------------------------------------------------------------------------ // multi-grid belie propagation //------------------------------------------------------------------------------------------------ void BPFlow::generateCoarserLevel(BPFlow &bp) { //------------------------------------------------------------------------------------------------ // set the dimensions and parameters //------------------------------------------------------------------------------------------------ bp.Width=Width/2; if(Width%2==1) bp.Width++; bp.Height=Height/2; if(Height%2==1) bp.Height++; bp.Area=bp.Width*bp.Height; bp.s=s; bp.d=d; DImage foo; Im_s.smoothing(foo); foo.imresize(bp.Im_s,bp.Width,bp.Height); Im_d.smoothing(foo); foo.imresize(bp.Im_d,bp.Width,bp.Height); bp.IsDisplay=IsDisplay; bp.nNeighbors=nNeighbors; //------------------------------------------------------------------------------------------------ // allocate buffers //------------------------------------------------------------------------------------------------ for(int i=0;i<2;i++) { bp.pOffset[i]=new int[bp.Area]; bp.pWinSize[i]=new int[bp.Area]; ReduceImage(bp.pOffset[i],Width,Height,pOffset[i]); ReduceImage(bp.pWinSize[i],Width,Height,pWinSize[i]); for(int j = 0;j<bp.Area;j++) bp.pWinSize[i][j] = __max(bp.pWinSize[i][j],1); } //------------------------------------------------------------------------------------------------ // generate data term //------------------------------------------------------------------------------------------------ bp.nTotalMatches=bp.AllocateBuffer(bp.pDataTerm,bp.ptrDataTerm,bp.pWinSize[0],bp.pWinSize[1]); for(int i=0;i<bp.Height;i++) for(int j=0;j<bp.Width;j++) { int offset=i*bp.Width+j; for(int ii=0;ii<2;ii++) for(int jj=0;jj<2;jj++) { int y=i*2+ii; int x=j*2+jj; if(y<Height && x<Width) { int nStates=(bp.pWinSize[0][offset]*2+1)*(bp.pWinSize[1][offset]*2+1); for(int k=0;k<nStates;k++) bp.pDataTerm[offset].data()[k]+=pDataTerm[y*Width+x].data()[k]; } } } //------------------------------------------------------------------------------------------------ // generate range term //------------------------------------------------------------------------------------------------ bp.ComputeRangeTerm(gamma/2); }
/**The slant angle is assumed to be between 60 and -45 degrees (0 deg=vertical, * negative values are left-slanted, positive values right-slanted). * To determine slant: at each x-position, the longest runlength at each angle * is found and its squared value is added into the accumulator for that angle. * The histogram is smoothed, and the angle corresponding to the highest value * in the histogram is the returned angle (in degrees). * * Runlengths of less than rlThresh pixels are ignored. * * The image should be black(0) and white(255). The portion of the image * specified by x0,y0 - x1,y1 is considered to be the textline of interest. * If no coordinates are specified, then the entire image is used as the * textline. * * If weight is not NULL, it will be the sum of max runlengths (not squared) at * all 120 angles. Weights are used in determination of weighted average angle * for all textlines in getAllTextlinesSlantAngleDeg() before adjusting angles. * * If rgSlantHist is not NULL, the squared max RL values in the angle histogram * will be copied into the rgSlantHist array. It must already be allocated to * 120*sizeof(unsigned int). * * if imgAngleHist is not NULL, then the image is set to w=120 and h=y1-y0+1. * It is a (grayscale) graphical representation of what is in rgSlantHist. */ double DSlantAngle::getTextlineSlantAngleDeg(DImage &imgBW, int rlThresh, int x0,int y0,int x1,int y1, double *weight, unsigned int *rgSlantHist, DImage *imgAngleHist){ int *rgLineSlantAngles; int lineH; int slantOffset, slantAngle, angle; unsigned int rgSlantSums[120]; unsigned int rgSlantSumsTmp[120]; int runlen, maxrl; /* maximum slant runlen */ double slantDx; int w, h; D_uint8 *p8; double dblWeight = 0; w = imgBW.width(); h = imgBW.height(); p8 = imgBW.dataPointer_u8(); if(-1 == x1) x1 = w-1; if(-1 == y1) y1 = h-1; lineH = y1-y0+1; /* estimate the predominant slant angle (0=vertical, +right, -left) */ slantOffset = (int)(0.5+ (lineH / 2.0) / tan(DMath::degreesToRadians(30.))); for(int j = 0; j < 120; ++j){ rgSlantSums[j] = 0; rgSlantSumsTmp[j] = 0; } for(angle = -45; angle <= 60; angle += 1){ /* at each x-position, sum the maximum run length at that angle into the accumulator */ if(0 == angle) /* vertical, so tangent is infinity */ slantDx = 0.; else slantDx = -1.0 / tan(DMath::degreesToRadians(90-angle)); // for(j = slantOffset; j < (hdr.w-slantOffset); ++j){ for(int j = x0; j <= x1; ++j){ maxrl = 0; runlen = 0; for(int y = 0; y < lineH; ++y){ int x; x = (int)(0.5+ j + y * slantDx); if( (x>=x0) && (x <= x1)){ /* make sure we are within bounds */ int idxtmp; idxtmp = (y+y0)*w+x; // imgCoded[idxtmp*3] = 0; if(0 == p8[idxtmp]){ ++runlen; if(runlen > maxrl){ maxrl = runlen; } } else runlen = 0; } /* end if in bounds */ else{ runlen = 0; /* ignore runs that go off edge of image */ } } if(maxrl > rlThresh){ rgSlantSums[angle+45] += maxrl*maxrl; dblWeight += maxrl; } } /* end for j */ } /* end for angle */ //smooth the histogram rgSlantSumsTmp[0] = (rgSlantSums[0] + rgSlantSums[1]) / 2; for(int aa = 1; aa < 119; ++aa){ rgSlantSumsTmp[aa]=(rgSlantSums[aa-1]+rgSlantSums[aa]+rgSlantSums[aa+1])/3; } for(int aa = 0; aa < 120; ++aa){ rgSlantSums[aa] = rgSlantSumsTmp[aa]; } //use the histogram peak as the slant angle slantAngle = 0; for(angle = -45; angle <= 60; angle += 1){ if(rgSlantSums[angle+45] > rgSlantSums[slantAngle+45]){ slantAngle = angle; } } /* end for angle */ if(NULL != weight) (*weight) = dblWeight; if(NULL != rgSlantHist){ for(int aa = 0; aa < 120; ++aa){ rgSlantHist[aa] = rgSlantSums[aa]; } } if(NULL != imgAngleHist){//debug tool- return an image of the angle histogram //DProfile prof; int max = 0; int htmp; D_uint8 *p8ang; htmp = y1-y0+1; imgAngleHist->create(120,htmp,DImage::DImage_u8); imgAngleHist->clear(); p8ang = imgAngleHist->dataPointer_u8(); for(int i=0; i < 120; ++i){ if(rgSlantSums[i] > max) max = rgSlantSums[i]; } if(0==max) max = 1; // for(int y=0, idx=0; y < htmp; ++y){ // for(int x=0; x < 120; ++x, ++idx){ // if((rgSlantSums[x]/(double)max) >= ((htmp-y)/(double)htmp)) // p8ang[idx] = 0xee; // else // p8ang[idx] = 0x88; // } // } // printf("htmp=%d\n", htmp); for(int x=0; x < 120; ++x){ double pct; pct = 1.-rgSlantSums[x] / (double)max; imgAngleHist->drawLine(x,htmp-1,x,(int)(pct*(htmp-1)), 128); } } return (double)slantAngle; }
void* DSlantAngle::getSlant_thread_func(void *params){ SLANT_THREAD_PARMS *pparms; int numThreads; int w, h; D_uint8 *p8; int runlen, maxrl; /* maximum slant runlen */ double slantDx; int lineH; int slantOffset, slantAngle, angle; double dblWeight; DImage *pimg; int rlThresh; pparms = (SLANT_THREAD_PARMS*)params; numThreads = pparms->numThreads; pimg = pparms->pImgSrc; rlThresh = pparms->rlThresh; w = pimg->width(); h = pimg->height(); p8 = pimg->dataPointer_u8(); for(int i=0; i < 120; ++i) pparms->rgSlantSums[i] = 0; for(int tl=pparms->threadNum; tl < (pparms->numTextlines); tl+=numThreads){ int x0, y0, x1, y1; unsigned int rgSlantSums[120]; x0 = pparms->rgRects[tl].x; y0 = pparms->rgRects[tl].y; x1 = pparms->rgRects[tl].x + pparms->rgRects[tl].w - 1; y1 = pparms->rgRects[tl].y + pparms->rgRects[tl].h - 1; lineH = y1-y0+1; memset(rgSlantSums, 0, sizeof(int)*120); dblWeight = 0.; for(angle = -45; angle <= 60; angle += 1){ /* at each x-position, sum the maximum run length at that angle into the accumulator */ if(0 == angle) /* vertical, so tangent is infinity */ slantDx = 0.; else slantDx = -1.0 / tan(DMath::degreesToRadians(90-angle)); // for(j = slantOffset; j < (hdr.w-slantOffset); ++j){ for(int j = x0; j <= x1; ++j){ maxrl = 0; runlen = 0; for(int y = 0; y < lineH; ++y){ int x; x = (int)(0.5+ j + y * slantDx); if( (x>=x0) && (x <= x1)){ /* make sure we are within bounds */ int idxtmp; idxtmp = (y+y0)*w+x; // imgCoded[idxtmp*3] = 0; if(0 == p8[idxtmp]){ ++runlen; if(runlen > maxrl){ maxrl = runlen; } } else runlen = 0; } /* end if in bounds */ else{ runlen = 0; /* ignore runs that go off edge of image */ } } if(maxrl > rlThresh){ rgSlantSums[angle+45] += maxrl*maxrl; dblWeight += maxrl; } } /* end for j */ } /* end for angle */ for(int i=0; i < 120; ++i) pparms->rgSlantSums[i] += rgSlantSums[i]; if(NULL != (pparms->rgWeights)){ pparms->rgWeights[tl] = dblWeight; } if(NULL != (pparms->rgAngles)){ // need to independently figure out the angle for this particular textline unsigned int rgSlantSumsTmp[120]; //smooth the histogram rgSlantSumsTmp[0] = (rgSlantSums[0] + rgSlantSums[1]) / 2; for(int aa = 1; aa < 119; ++aa){ rgSlantSumsTmp[aa]=(rgSlantSums[aa-1]+rgSlantSums[aa]+rgSlantSums[aa+1])/3; } // for(int aa = 0; aa < 120; ++aa){ // rgSlantSums[aa] = rgSlantSumsTmp[aa]; // } //use the smoothed histogram peak as the slant angle slantAngle = 0; for(angle = -45; angle <= 60; angle += 1){ if(rgSlantSumsTmp[angle+45] > rgSlantSumsTmp[slantAngle+45]){ slantAngle = angle; } } /* end for angle */ pparms->rgAngles[tl] = slantAngle; } } }
/**Avg runlength in each column of img is projected onto the horizontal axis. Resulting data length will be equal to the width of img. If fNormalize is true, each profile value will be divided by image height, so the value is a fraction of the image height instead of a number of pixels. */ void DProfile::getHorizAvgRunlengthProfile(const DImage &img, D_uint32 rgbVal, bool fNormalize){ int w, h; unsigned int *rgRunlengths; unsigned int *rgNumRuns; w = img.width(); h = img.height(); // allocate the rgProf array if(NULL == rgProf){ rgProf = (double*)malloc(w * sizeof(double)); D_CHECKPTR(rgProf); len = w; } else{ if(len != w){ rgProf = (double*)realloc(rgProf,w*sizeof(double)); D_CHECKPTR(rgProf); len = w; } } rgRunlengths = (unsigned int*)malloc(sizeof(unsigned int)*w); D_CHECKPTR(rgRunlengths); rgNumRuns = (unsigned int*)malloc(sizeof(unsigned int)*w); D_CHECKPTR(rgNumRuns); memset(rgRunlengths, 0, sizeof(unsigned int)*w); memset(rgNumRuns, 0, sizeof(unsigned int)*w); memset(rgProf, 0, sizeof(double) * w); switch(img.getImageType()){ case DImage::DImage_u8: { D_uint8 *pu8; pu8=img.dataPointer_u8(); for(int y = 0, idx=0; y < h; ++y){ for(int x = 0; x < w; ++x, ++idx){ if((D_uint8)rgbVal == pu8[idx]){//increment run length for this col if(0 == rgRunlengths[x]) ++(rgNumRuns[x]); ++(rgRunlengths[x]); ++(rgProf[x]); } else{ rgRunlengths[x] = 0; } } } for(int x = 0; x < w; ++x){ //divide sum by number of runs to get avg if(rgNumRuns[x] > 0) rgProf[x] /= rgNumRuns[x]; } if(fNormalize){ for(int x = 0; x < w; ++x){ rgProf[x] /= h; } } } break; default: fprintf(stderr, "Not yet implemented!\n"); abort(); }//end switch(img.getImageType()) free(rgRunlengths); free(rgNumRuns); }
void main_Regular(int idx) { if(idx > 18 || idx < 0) return; int boarder_size = 16; int center_width = 256; int center_height = 256; int width = center_width+boarder_size*2; int height = center_height+boarder_size*2; bool cut_boarder = true; int data_index = idx; const static int BUF_LEN = 200; char out_flow_fold[BUF_LEN] = {0}; char out_par_fold[BUF_LEN] = {0}; int par_num = 0; int vort_num = 0; double max_vort = 1; double min_vort = 0.6; double max_vort_radius = 20; double min_vort_radius = 15; bool use_peroid_coord = false; double base_vel_u = 0; double base_vel_v = 0; int skip_frames = 0; int coarse_len = 16; ZQ_PIVMovingObject* mvobj = 0; DImage par_mask(width,height); switch(data_index) { case 0: strcpy_s(out_flow_fold, BUF_LEN,"flow0"); strcpy_s(out_par_fold, BUF_LEN,"par0"); srand(1000); par_num = 10000; vort_num = 40; max_vort = 1.8; min_vort = 1.2; max_vort_radius = 20; min_vort_radius = 20; use_peroid_coord = true; boarder_size = 64; width = center_width + 2*boarder_size; height = center_height + 2*boarder_size; coarse_len = 32; par_mask.allocate(width,height); for(int y = 0;y < height;y++) { for(int x = 0;x < width;x++) { if(x < coarse_len || x >= width - coarse_len) par_mask.data()[y*width+x] = 1; } } base_vel_u = 5; base_vel_v = 0; skip_frames = 20; break; case 1: strcpy_s(out_flow_fold, BUF_LEN,"flow1"); strcpy_s(out_par_fold, BUF_LEN,"par1"); srand(2000); par_num = 10000; vort_num = 40; max_vort = 1.6; min_vort = 0.8; max_vort_radius = 20; min_vort_radius = 20; use_peroid_coord = true; coarse_len = 48; par_mask.allocate(width,height); for(int y = 0;y < height;y++) { for(int x = 0;x < width;x++) { if(x >= width - coarse_len) par_mask.data()[y*width+x] = 1; } } base_vel_u = 5; base_vel_v = 0; skip_frames = 20; break; case 2: strcpy_s(out_flow_fold, BUF_LEN,"flow2"); strcpy_s(out_par_fold, BUF_LEN,"par2"); srand(2000); par_num = 10000; vort_num = 40; max_vort = 1.6; min_vort = 0.8; max_vort_radius = 20; min_vort_radius = 20; use_peroid_coord = true; coarse_len = 16; par_mask.allocate(width,height); for(int y = 0;y < height;y++) { for(int x = 0;x < width;x++) { int cy = y/coarse_len; int cx = x/coarse_len; if(cx%3 != 0) par_mask.data()[y*width+x] = 1; } } base_vel_u = 5; base_vel_v = 1; skip_frames = 20; break; case 3: strcpy_s(out_flow_fold, BUF_LEN,"flow3"); strcpy_s(out_par_fold, BUF_LEN,"par3"); srand(3000); par_num = 10000; vort_num = 40; max_vort = 1.6; min_vort = 0.8; max_vort_radius = 20; min_vort_radius = 20; use_peroid_coord = true; coarse_len = 16; par_mask.allocate(width,height); for(int y = 0;y < height;y++) { for(int x = 0;x < width;x++) { int cy = y/coarse_len; int cx = x/coarse_len; if(cx%2 == 0) par_mask.data()[y*width+x] = 1; } } base_vel_u = 5; base_vel_v = 1; skip_frames = 20; break; case 4: strcpy_s(out_flow_fold, BUF_LEN,"flow4"); strcpy_s(out_par_fold, BUF_LEN,"par4"); srand(4000); par_num = 10000; vort_num = 40; max_vort = 1.6; min_vort = 0.8; max_vort_radius = 20; min_vort_radius = 20; use_peroid_coord = true; coarse_len = 64; par_mask.allocate(width,height); for(int y = 0;y < height;y++) { for(int x = 0;x < width;x++) { int cy = y/coarse_len; int cx = x/coarse_len; if(cx%2 == 0) par_mask.data()[y*width+x] = 1; } } base_vel_u = 5; base_vel_v = 1; skip_frames = 20; break; case 5: strcpy_s(out_flow_fold, BUF_LEN,"flow5"); strcpy_s(out_par_fold, BUF_LEN,"par5"); srand(5000); par_num = 10000; vort_num = 40; max_vort = 1.6; min_vort = 0.8; max_vort_radius = 20; min_vort_radius = 20; use_peroid_coord = true; coarse_len = 32; par_mask.allocate(width,height); for(int y = 0;y < height;y++) { for(int x = 0;x < width;x++) { int cy = y/coarse_len; int cx = x/coarse_len; if(cx%2 == 0) par_mask.data()[y*width+x] = 1; } } base_vel_u = 5; base_vel_v = 1; skip_frames = 20; break; case 6: strcpy_s(out_flow_fold, BUF_LEN,"flow6"); strcpy_s(out_par_fold, BUF_LEN,"par6"); srand(6000); par_num = 10000; vort_num = 40; max_vort = 1.6; min_vort = 0.8; max_vort_radius = 20; min_vort_radius = 20; use_peroid_coord = true; coarse_len = 32; par_mask.allocate(width,height); for(int y = 0;y < height;y++) { for(int x = 0;x < width;x++) { int cy = y/coarse_len; int cx = x/coarse_len; if(cy%2 == 0) par_mask.data()[y*width+x] = 1; } } base_vel_u = 5; base_vel_v = 1; skip_frames = 20; break; case 7: strcpy_s(out_flow_fold, BUF_LEN,"flow7"); strcpy_s(out_par_fold, BUF_LEN,"par7"); srand(7000); par_num = 10000; vort_num = 20; max_vort = 1.8; min_vort = 1.2; max_vort_radius = 30; min_vort_radius = 20; use_peroid_coord = true; coarse_len = 64; par_mask.allocate(width,height); /*for(int y = 0;y < height;y++) { for(int x = 0;x < width;x++) { int cy = y/coarse_len; int cx = x/coarse_len; if((cy+cx)%2 == 0) par_mask.data()[y*width+x] = 1; } }*/ base_vel_u = 5; base_vel_v = 1; skip_frames = 20; break; case 8: boarder_size = 16; center_width = 256; center_height = 256; width = center_width+boarder_size*2; height = center_height+boarder_size*2; cut_boarder = true; strcpy_s(out_flow_fold, BUF_LEN,"flow8"); strcpy_s(out_par_fold, BUF_LEN,"par8"); srand(9000); par_num = 10000; vort_num = 30; max_vort = 1.6; min_vort = 1.2; max_vort_radius = 30; min_vort_radius = 20; use_peroid_coord = true; mvobj = new ZQ_PIVMovingObject(48,48,ZQ_PIVMovingObject::ZQ_PIV_MOVOB_CIRCLE_STATIC,"wenli.di2"); /*has_occupy = true; occupy = new bool[width*height]; memset(occupy,0,sizeof(bool)*width*height); for(int y = 0;y < height;y++) { for(int x = 0;x < width;x++) { double dis = sqrt((y-height*0.5)*(y-height*0.5)+(x-width*0.5)*(x-width*0.5)); if(dis < (height+width)*0.05) occupy[y*width+x] = true; } }*/ coarse_len = 32; par_mask.allocate(width,height); /*for(int y = 0;y < height;y++) { for(int x = 0;x < width;x++) { if(occupy[y*width+x]) par_mask.data()[y*width+x] = 1; } }*/ base_vel_u = 4; base_vel_v = 0; skip_frames = 20; break; case 9: boarder_size = 16; center_width = 256; center_height = 256; width = center_width+boarder_size*2; height = center_height+boarder_size*2; cut_boarder = true; strcpy_s(out_flow_fold, BUF_LEN,"flow9"); strcpy_s(out_par_fold, BUF_LEN,"par9"); srand(8000); par_num = 10000; vort_num = 30; max_vort = 1.4; min_vort = 1.0; max_vort_radius = 30; min_vort_radius = 20; use_peroid_coord = true; mvobj = new ZQ_PIVMovingObject(48,48, ZQ_PIVMovingObject::ZQ_PIV_MOVOB_RECT_UPDOWN,"wenli.di2"); coarse_len = 32; par_mask.allocate(width,height); base_vel_u = 4; base_vel_v = 0; skip_frames = 20; break; case 10: boarder_size = 16; center_width = 256; center_height = 256; width = center_width+boarder_size*2; height = center_height+boarder_size*2; cut_boarder = true; strcpy_s(out_flow_fold, BUF_LEN, "flow10"); strcpy_s(out_par_fold, BUF_LEN, "par10"); srand(10000); par_num = 10000; vort_num = 30; max_vort = 1.4; min_vort = 1.0; max_vort_radius = 30; min_vort_radius = 20; use_peroid_coord = true; mvobj = new ZQ_PIVMovingObject(48,48, ZQ_PIVMovingObject::ZQ_PIV_MOVOB_CIRCLE_CIRCULAR,"wenli.di2"); coarse_len = 32; par_mask.allocate(width,height); base_vel_u = 0; base_vel_v = 0; skip_frames = 20; break; case 11: boarder_size = 16; center_width = 256; center_height = 256; width = center_width+boarder_size*2; height = center_height+boarder_size*2; cut_boarder = true; strcpy_s(out_flow_fold, BUF_LEN,"flow11"); strcpy_s(out_par_fold, BUF_LEN, "par11"); srand(11000); par_num = 5000; vort_num = 20; max_vort = 1.6; min_vort = 0.8; max_vort_radius = 20; min_vort_radius = 20; use_peroid_coord = true; par_mask.allocate(width,height); base_vel_u = 5; base_vel_v = 0; skip_frames = 20; break; case 12: boarder_size = 16; center_width = 256; center_height = 256; width = center_width+boarder_size*2; height = center_height+boarder_size*2; cut_boarder = true; strcpy_s(out_flow_fold, BUF_LEN,"flow12"); strcpy_s(out_par_fold, BUF_LEN,"par12"); srand(1240); par_num = 5000; vort_num = 30; max_vort = 2.5; min_vort = 1.6; max_vort_radius = 20; min_vort_radius = 10; use_peroid_coord = true; par_mask.allocate(width,height); base_vel_u = 0; base_vel_v = 0; skip_frames = 20; break; case 13: boarder_size = 16; center_width = 256; center_height = 256; width = center_width+boarder_size*2; height = center_height+boarder_size*2; cut_boarder = true; strcpy_s(out_flow_fold, BUF_LEN,"flow13"); strcpy_s(out_par_fold, BUF_LEN,"par13"); srand(1300); par_num = 5000; vort_num = 10; max_vort = 1.5; min_vort = 0.6; max_vort_radius = 20; min_vort_radius = 20; use_peroid_coord = true; par_mask.allocate(width,height); base_vel_u = 1; base_vel_v = 1; skip_frames = 10; break; case 14: boarder_size = 16; center_width = 256; center_height = 256; width = center_width+boarder_size*2; height = center_height+boarder_size*2; cut_boarder = true; strcpy_s(out_flow_fold, BUF_LEN, "flow14"); strcpy_s(out_par_fold, BUF_LEN, "par14"); srand(14000); par_num = 5000; vort_num = 10; max_vort = 1.0; min_vort = 0.8; max_vort_radius = 20; min_vort_radius = 10; use_peroid_coord = true; mvobj = new ZQ_PIVMovingObject(48,48, ZQ_PIVMovingObject::ZQ_PIV_MOVOB_CIRCLE_STATIC,"wenli.di2"); par_mask.allocate(width,height); base_vel_u = 2; base_vel_v = 0; skip_frames = 20; break; case 15: boarder_size = 16; center_width = 256; center_height = 256; width = center_width+boarder_size*2; height = center_height+boarder_size*2; cut_boarder = true; strcpy_s(out_flow_fold, BUF_LEN,"flow15"); strcpy_s(out_par_fold, BUF_LEN,"par15"); srand(15000); par_num = 5000; vort_num = 20; max_vort = 1.0; min_vort = 0.8; max_vort_radius = 20; min_vort_radius = 10; use_peroid_coord = true; mvobj = new ZQ_PIVMovingObject(48,48, ZQ_PIVMovingObject::ZQ_PIV_MOVOB_RECT_STATIC,"wenli.di2"); par_mask.allocate(width,height); base_vel_u = 5; base_vel_v = 0; skip_frames = 50; break; case 16: // the same field as "case18" ,but more particles boarder_size = 16; center_width = 256; center_height = 256; width = center_width+boarder_size*2; height = center_height+boarder_size*2; cut_boarder = true; strcpy_s(out_flow_fold, BUF_LEN, "flow16"); strcpy_s(out_par_fold, BUF_LEN,"par16"); srand(11000); par_num = 20000; vort_num = 20; max_vort = 1.6; min_vort = 0.8; max_vort_radius = 20; min_vort_radius = 20; use_peroid_coord = true; par_mask.allocate(width,height); base_vel_u = 5; base_vel_v = 0; skip_frames = 20; break; case 17: // the same field as "case18" ,but less particles boarder_size = 16; center_width = 256; center_height = 256; width = center_width+boarder_size*2; height = center_height+boarder_size*2; cut_boarder = true; strcpy_s(out_flow_fold, BUF_LEN, "flow17"); strcpy_s(out_par_fold, BUF_LEN, "par17"); srand(11000); par_num = 2000; vort_num = 20; max_vort = 1.6; min_vort = 0.8; max_vort_radius = 20; min_vort_radius = 20; use_peroid_coord = true; par_mask.allocate(width,height); base_vel_u = 5; base_vel_v = 0; skip_frames = 20; break; case 18: // the same field as "case16" and "case17" boarder_size = 16; center_width = 256; center_height = 256; width = center_width+boarder_size*2; height = center_height+boarder_size*2; cut_boarder = true; strcpy_s(out_flow_fold, BUF_LEN,"flow18"); strcpy_s(out_par_fold, BUF_LEN,"par18"); srand(11000); par_num = 5000; vort_num = 20; max_vort = 1.6; min_vort = 0.8; max_vort_radius = 20; min_vort_radius = 20; use_peroid_coord = true; par_mask.allocate(width,height); base_vel_u = 5; base_vel_v = 0; skip_frames = 20; break; } /*suggest values*/ /* par_num = width*height/3; vort_num = 30; */ char cmdbuf[500]; sprintf_s(cmdbuf,"if not exist \"%s\" mkdir \"%s\"",out_par_fold,out_par_fold); system(cmdbuf); sprintf_s(cmdbuf,"if not exist \"%s\" mkdir \"%s\"",out_flow_fold,out_flow_fold); system(cmdbuf); DImage vor_img(width-1,height-1); DImage macu_img(width+1,height); DImage macv_img(width,height+1); DImage u_img(width,height); DImage v_img(width,height); DImage par_img(width,height); BaseType*& vort_pData = vor_img.data(); BaseType*& macu_pData = macu_img.data(); BaseType*& macv_pData = macv_img.data(); BaseType*& u_pData = u_img.data(); BaseType*& v_pData = v_img.data(); for(int vor_it = 0; vor_it < vort_num; vor_it++) { double intensity = (rand()%2-0.5)*2.0*(rand()%101/100.0*(max_vort-min_vort)+min_vort); double radius = rand()%101/100.0*(max_vort_radius-min_vort_radius)+min_vort_radius; double posx = rand()%width; double posy = rand()%height; ZQ_PIVSimulator::DrawOneParticle(vor_img,posx,posy,intensity,radius,true); } ZQ_PoissonSolver::ReconstructCurlField(width,height,vort_pData,macu_pData,macv_pData,100,false); ZQ_PoissonSolver::MACtoRegularGrid(width,height,macu_pData,macv_pData,u_pData,v_pData); if(use_peroid_coord) { ZQ_PoissonSolver::RegularGridtoMAC(width,height,u_pData,v_pData,macu_pData,macv_pData,true); ZQ_PoissonSolver::SolveOpenPoissonSOR_MACGrid(macu_pData,macv_pData,width,height,1000,false); ZQ_PoissonSolver::MACtoRegularGrid(width,height,macu_pData,macv_pData,u_pData,v_pData); } for(int i = 0;i < width*height;i++) { u_pData[i] += base_vel_u; v_pData[i] += base_vel_v; } ZQ_PIVSimulator piv_simu(width,height,mvobj); piv_simu.RandomInit(par_num,u_img,v_img,par_mask); int frame = 0; char buf[200]; DImage flow; DImage cut_u_img(center_width,center_height),cut_v_img(center_width,center_height); DImage cut_par_img(center_width,center_height); for(int i = 0;i < skip_frames;i++) { printf("skip frame [%3d/%3d]...\n",i,skip_frames); piv_simu.RunOneFrame(1.0,use_peroid_coord,false); } do { printf("frame [%3d] ...\n",frame); if(cut_boarder) { piv_simu.ExportVelocity(u_img,v_img); for(int h = 0; h < center_height;h++) { for(int w = 0;w < center_width;w++) { cut_u_img.data()[h*center_width+w] = u_img.data()[(h+boarder_size)*width+w+boarder_size]; cut_v_img.data()[h*center_width+w] = v_img.data()[(h+boarder_size)*width+w+boarder_size]; } } cv::Mat show_flow_img = ZQ_ImageIO::SaveFlowToColorImage(cut_u_img,cut_v_img,true,12,64,1); sprintf_s(buf,"%s\\flow_%d.png",out_flow_fold,frame); cv::imwrite(buf,show_flow_img); flow.assemble(cut_u_img,cut_v_img); sprintf_s(buf,"%s\\flow_%d.di2",out_flow_fold,frame); flow.saveImage(buf); par_img.reset(); piv_simu.ExportParticleImage(par_img); for(int h = 0;h < center_height;h++) { for(int w = 0;w < center_width;w++) { cut_par_img.data()[h*center_width+w] = par_img.data()[(h+boarder_size)*width+w+boarder_size]; } } cv::Mat show_par_img = ParImageToIplImage(cut_par_img); sprintf_s(buf,"%s\\par_%d.png",out_par_fold,frame); cv::imwrite(buf,show_par_img); cv::namedWindow("show"); cv::imshow("show", show_par_img); cv::waitKey(10); } else { piv_simu.ExportVelocity(u_img,v_img); cv::Mat show_flow_img = ZQ_ImageIO::SaveFlowToColorImage(u_img,v_img,true,12,64,1); sprintf_s(buf,"%s\\flow_%d.png",out_flow_fold,frame); cv::imwrite(buf,show_flow_img); flow.assemble(u_img,v_img); sprintf_s(buf,"%s\\flow_%d.di2",out_flow_fold,frame); flow.saveImage(buf); par_img.reset(); piv_simu.ExportParticleImage(par_img); cv::Mat show_par_img = ParImageToIplImage(par_img); sprintf_s(buf,"%s\\par_%d.png",out_par_fold,frame); cv::imwrite(buf,show_par_img); cv::namedWindow("show"); cv::imshow("show", show_par_img); cv::waitKey(10); } piv_simu.RunOneFrame(1.0,use_peroid_coord,true); frame++; } while (frame < 400); if(mvobj) delete mvobj; }
//--------------------------------------------------------------------------------------- // function to convert image to feature image //--------------------------------------------------------------------------------------- void OpticalFlow::im2feature(DImage &imfeature, const DImage &im) { int width=im.width(); int height=im.height(); int nchannels=im.nchannels(); if(nchannels==1) { imfeature.allocate(im.width(),im.height(),3); DImage imdx,imdy; im.dx(imdx,true); im.dy(imdy,true); _FlowPrecision* data=imfeature.data(); for(int i=0;i<height;i++) for(int j=0;j<width;j++) { int offset=i*width+j; data[offset*3]=im.data()[offset]; data[offset*3+1]=imdx.data()[offset]; data[offset*3+2]=imdy.data()[offset]; } } else if(nchannels==3) { DImage grayImage; im.desaturate(grayImage); imfeature.allocate(im.width(),im.height(),5); DImage imdx,imdy; grayImage.dx(imdx,true); grayImage.dy(imdy,true); _FlowPrecision* data=imfeature.data(); for(int i=0;i<height;i++) for(int j=0;j<width;j++) { int offset=i*width+j; data[offset*5]=grayImage.data()[offset]; data[offset*5+1]=imdx.data()[offset]; data[offset*5+2]=imdy.data()[offset]; data[offset*5+3]=im.data()[offset*3+1]-im.data()[offset*3]; data[offset*5+4]=im.data()[offset*3+1]-im.data()[offset*3+2]; } } else imfeature.copyData(im); }
//-------------------------------------------------------------------------------------------------------- // function to compute optical flow field using two fixed point iterations // Input arguments: // Im1, Im2: frame 1 and frame 2 // warpIm2: the warped frame 2 according to the current flow field u and v // u,v: the current flow field, NOTICE that they are also output arguments // //-------------------------------------------------------------------------------------------------------- void OpticalFlow::SmoothFlowSOR(const DImage &Im1, const DImage &Im2, DImage &warpIm2, DImage &u, DImage &v, double alpha, int nOuterFPIterations, int nInnerFPIterations, int nSORIterations) { DImage mask,imdx,imdy,imdt; int imWidth,imHeight,nChannels,nPixels; imWidth=Im1.width(); imHeight=Im1.height(); nChannels=Im1.nchannels(); nPixels=imWidth*imHeight; DImage du(imWidth,imHeight),dv(imWidth,imHeight); DImage uu(imWidth,imHeight),vv(imWidth,imHeight); DImage ux(imWidth,imHeight),uy(imWidth,imHeight); DImage vx(imWidth,imHeight),vy(imWidth,imHeight); DImage Phi_1st(imWidth,imHeight); DImage Psi_1st(imWidth,imHeight,nChannels); DImage imdxy,imdx2,imdy2,imdtdx,imdtdy; DImage ImDxy,ImDx2,ImDy2,ImDtDx,ImDtDy; DImage foo1,foo2; double prob1,prob2,prob11,prob22; double varepsilon_phi=pow(0.001,2); double varepsilon_psi=pow(0.001,2); //-------------------------------------------------------------------------- // the outer fixed point iteration //-------------------------------------------------------------------------- for(int count=0;count<nOuterFPIterations;count++) { // compute the gradient getDxs(imdx,imdy,imdt,Im1,warpIm2); // generate the mask to set the weight of the pxiels moving outside of the image boundary to be zero genInImageMask(mask,u,v); // set the derivative of the flow field to be zero du.reset(); dv.reset(); //-------------------------------------------------------------------------- // the inner fixed point iteration //-------------------------------------------------------------------------- for(int hh=0;hh<nInnerFPIterations;hh++) { // compute the derivatives of the current flow field if(hh==0) { uu.copyData(u); vv.copyData(v); } else { uu.Add(u,du); vv.Add(v,dv); } uu.dx(ux); uu.dy(uy); vv.dx(vx); vv.dy(vy); // compute the weight of phi Phi_1st.reset(); _FlowPrecision* phiData=Phi_1st.data(); double temp; const _FlowPrecision *uxData,*uyData,*vxData,*vyData; uxData=ux.data(); uyData=uy.data(); vxData=vx.data(); vyData=vy.data(); double power_alpha = 0.5; for(int i=0;i<nPixels;i++) { temp=uxData[i]*uxData[i]+uyData[i]*uyData[i]+vxData[i]*vxData[i]+vyData[i]*vyData[i]; //phiData[i]=power_alpha*pow(temp+varepsilon_phi,power_alpha-1); phiData[i] = 0.5/sqrt(temp+varepsilon_phi); //phiData[i] = 1/(power_alpha+temp); } // compute the nonlinear term of psi Psi_1st.reset(); _FlowPrecision* psiData=Psi_1st.data(); const _FlowPrecision *imdxData,*imdyData,*imdtData; const _FlowPrecision *duData,*dvData; imdxData=imdx.data(); imdyData=imdy.data(); imdtData=imdt.data(); duData=du.data(); dvData=dv.data(); double _a = 10000, _b = 0.1; if(nChannels==1) for(int i=0;i<nPixels;i++) { temp=imdtData[i]+imdxData[i]*duData[i]+imdyData[i]*dvData[i]; //if(temp*temp<0.04) // psiData[i]=1/(2*sqrt(temp*temp+varepsilon_psi)); //psiData[i] = _a*_b/(1+_a*temp*temp); // the following code is for log Gaussian mixture probability model temp *= temp; switch(noiseModel) { case GMixture: prob1 = GMPara.Gaussian(temp,0,0)*GMPara.alpha[0]; prob2 = GMPara.Gaussian(temp,1,0)*(1-GMPara.alpha[0]); prob11 = prob1/(2*GMPara.sigma_square[0]); prob22 = prob2/(2*GMPara.beta_square[0]); psiData[i] = (prob11+prob22)/(prob1+prob2); break; case Lap: if(LapPara[0]<1E-20) continue; //psiData[i]=1/(2*sqrt(temp+varepsilon_psi)*LapPara[0]); psiData[i]=1/(2*sqrt(temp+varepsilon_psi)); break; } } else for(int i=0;i<nPixels;i++) for(int k=0;k<nChannels;k++) { int offset=i*nChannels+k; temp=imdtData[offset]+imdxData[offset]*duData[i]+imdyData[offset]*dvData[i]; //if(temp*temp<0.04) // psiData[offset]=1/(2*sqrt(temp*temp+varepsilon_psi)); //psiData[offset] = _a*_b/(1+_a*temp*temp); temp *= temp; switch(noiseModel) { case GMixture: prob1 = GMPara.Gaussian(temp,0,k)*GMPara.alpha[k]; prob2 = GMPara.Gaussian(temp,1,k)*(1-GMPara.alpha[k]); prob11 = prob1/(2*GMPara.sigma_square[k]); prob22 = prob2/(2*GMPara.beta_square[k]); psiData[offset] = (prob11+prob22)/(prob1+prob2); break; case Lap: if(LapPara[k]<1E-20) continue; //psiData[offset]=1/(2*sqrt(temp+varepsilon_psi)*LapPara[k]); psiData[offset]=1/(2*sqrt(temp+varepsilon_psi)); break; } } // prepare the components of the large linear system ImDxy.Multiply(Psi_1st,imdx,imdy); ImDx2.Multiply(Psi_1st,imdx,imdx); ImDy2.Multiply(Psi_1st,imdy,imdy); ImDtDx.Multiply(Psi_1st,imdx,imdt); ImDtDy.Multiply(Psi_1st,imdy,imdt); if(nChannels>1) { ImDxy.collapse(imdxy); ImDx2.collapse(imdx2); ImDy2.collapse(imdy2); ImDtDx.collapse(imdtdx); ImDtDy.collapse(imdtdy); } else { imdxy.copyData(ImDxy); imdx2.copyData(ImDx2); imdy2.copyData(ImDy2); imdtdx.copyData(ImDtDx); imdtdy.copyData(ImDtDy); } // laplacian filtering of the current flow field Laplacian(foo1,u,Phi_1st); Laplacian(foo2,v,Phi_1st); for(int i=0;i<nPixels;i++) { imdtdx.data()[i] = -imdtdx.data()[i]-alpha*foo1.data()[i]; imdtdy.data()[i] = -imdtdy.data()[i]-alpha*foo2.data()[i]; } // here we start SOR // set omega double omega = 1.8; du.reset(); dv.reset(); for(int k = 0; k<nSORIterations; k++) for(int i = 0; i<imHeight; i++) for(int j = 0; j<imWidth; j++) { int offset = i * imWidth+j; double sigma1 = 0, sigma2 = 0, coeff = 0; double _weight; if(j>0) { _weight = phiData[offset-1]; sigma1 += _weight*du.data()[offset-1]; sigma2 += _weight*dv.data()[offset-1]; coeff += _weight; } if(j<imWidth-1) { _weight = phiData[offset]; sigma1 += _weight*du.data()[offset+1]; sigma2 += _weight*dv.data()[offset+1]; coeff += _weight; } if(i>0) { _weight = phiData[offset-imWidth]; sigma1 += _weight*du.data()[offset-imWidth]; sigma2 += _weight*dv.data()[offset-imWidth]; coeff += _weight; } if(i<imHeight-1) { _weight = phiData[offset]; sigma1 += _weight*du.data()[offset+imWidth]; sigma2 += _weight*dv.data()[offset+imWidth]; coeff += _weight; } sigma1 *= -alpha; sigma2 *= -alpha; coeff *= alpha; // compute du sigma1 += imdxy.data()[offset]*dv.data()[offset]; du.data()[offset] = (1-omega)*du.data()[offset] + omega/(imdx2.data()[offset] + alpha*0.05 + coeff)*(imdtdx.data()[offset] - sigma1); // compute dv sigma2 += imdxy.data()[offset]*du.data()[offset]; dv.data()[offset] = (1-omega)*dv.data()[offset] + omega/(imdy2.data()[offset] + alpha*0.05 + coeff)*(imdtdy.data()[offset] - sigma2); } } u.Add(du); v.Add(dv); if(interpolation == Bilinear) warpFL(warpIm2,Im1,Im2,u,v); else { Im2.warpImageBicubicRef(Im1,warpIm2,u,v); warpIm2.threshold(); } //Im2.warpImageBicubicRef(Im1,warpIm2,BicubicCoeff,u,v); // estimate noise level switch(noiseModel) { case GMixture: estGaussianMixture(Im1,warpIm2,GMPara); break; case Lap: estLaplacianNoise(Im1,warpIm2,LapPara); } } }
// k clusters per channel = k^3 clusters DPlane DColorCluster::do_clustering(DImage &input, int k, bool ignore_black) { int cluster_count = k*k*k; for(int i=0; i<cluster_count; i++) clusters.push_back(DRGBCluster()); DPlane result(input.rows(), input.cols()); int delta = 256/(k*2); for(int a=0, cl=0; a<k; a++) for(int b=0; b<k; b++) for(int c=0; c<k; c++, cl++) clusters[cl].set_mean( DTriple((a+1)*delta, (b+1)*delta, (c+1)*delta)); int changes=1000000000; bool done=false; while(!done) { changes=0; for(int i=0; i<input.rows(); i++) for(int j=0; j<input.cols(); j++) { if(ignore_black && input[0][i][j] == 0 && input[1][i][j] == 0 && input[2][i][j] == 0) { result[i][j] = 0; continue; } int closest_cluster=0; double min_dist=1000000000; DTriple sample(input[0][i][j], input[1][i][j], input[2][i][j]); for(int c=0; c<cluster_count; c++) if(clusters[c].distance_to(sample) < min_dist) { min_dist = clusters[c].distance_to(sample); closest_cluster = c; } clusters[closest_cluster].add_sample(sample); if(closest_cluster+1 != result[i][j]) { result[i][j] = closest_cluster+1; changes++; } } if( changes < input.rows() * input.cols() * 0.001) done=true; else for(int i=0; i<cluster_count; i++) { clusters[i].update_mean(); clusters[i].remove_all(); } printf("there were %d changes\n",changes); } return result; }
///Max filter imgSrc with current settings and store result in imgDst void DMaxFilter::filterImage_(DImage &imgDst, const DImage &imgSrc, bool fAlreadyPadded, DProgress *pProg){ DMaxFiltType filtType; DImage *pImgPad; int wKern, hKern; int numKernPxls; int wUnpad, hUnpad; #ifndef D_NOTHREADS MAX_HUANG_8_THREAD_PARAMS_T rgParms[MAX_MAXFILT_THREADS]; pthread_t rgThreadID[MAX_MAXFILT_THREADS]; #endif filtType = _maxFiltType; pImgPad = (DImage*)&imgSrc; if(!fAlreadyPadded){ pImgPad = new DImage(); imgSrc.padEdges_(*pImgPad, _radiusX, _radiusX, _radiusY, _radiusY, DImage::DImagePadReplicate); } wUnpad = pImgPad->width()-(_radiusX*2); hUnpad = pImgPad->height()-(_radiusY*2); wKern = _radiusX * 2 + 1; hKern = _radiusY * 2 + 1; if(NULL == rgKern){ rgKern = (unsigned char*)malloc(sizeof(unsigned char) * wKern * hKern); if(!rgKern){ fprintf(stderr, "DMaxFilter::filterImage_() out of memory\n"); exit(1); } rgRightEdge = (int*)malloc(sizeof(int)*hKern); if(!rgRightEdge){ fprintf(stderr, "DMaxFilter::filterImage_() out of memory\n"); exit(1); } if(DMaxFilt_circle == filtType){ fill_circle_kern_offsets(_radiusX, _radiusY, rgKern, rgRightEdge, &numKernPxls); } else{ fill_square_kern_offsets(_radiusX, _radiusY, rgKern, rgRightEdge, &numKernPxls); } } switch(imgSrc.getImageType()){ case DImage::DImage_u8: { imgDst.create(wUnpad, hUnpad, DImage::DImage_u8, 1, imgSrc.getAllocMethod()); #ifndef D_NOTHREADS for(int tnum = 1; tnum < _numThreads; ++tnum){ rgParms[tnum].pImgDst = &imgDst; rgParms[tnum].pImgSrc = pImgPad; rgParms[tnum].radiusX = _radiusX; rgParms[tnum].radiusY = _radiusY; rgParms[tnum].wKern = wKern; rgParms[tnum].hKern = hKern; rgParms[tnum].rgKern = rgKern; rgParms[tnum].numKernPxls = numKernPxls; rgParms[tnum].rgRightEdge = rgRightEdge; rgParms[tnum].pProg = NULL; rgParms[tnum].progStart = 0; rgParms[tnum].progMax = 1; rgParms[tnum].threadNumber = tnum; rgParms[tnum].numThreads = _numThreads; if(0 != pthread_create(&rgThreadID[tnum], NULL, DMaxFilter::DMaxFilter_Huang8threadWrap, &rgParms[tnum])){ fprintf(stderr, "DMaxFilter::filterImage_() failed to spawn " "thread #%d. Exiting.\n", tnum); exit(1); } } #endif maxFiltHuang_u8(imgDst, *pImgPad, _radiusX, _radiusY, wKern, hKern, rgKern, numKernPxls, rgRightEdge, pProg, 0, hUnpad+1, 0, _numThreads); #ifndef D_NOTHREADS for(int tnum = 1; tnum < _numThreads; ++tnum){ if(pthread_join(rgThreadID[tnum],NULL)) fprintf(stderr, "DMaxFilter::filterImage_() failed to join " "thread %d\n", tnum); } #endif if(NULL != pProg){ pProg->reportStatus(hUnpad+1, 0, hUnpad+1);//report progress complete } } break; case DImage::DImage_RGB: { DImage imgR, imgG, imgB; DImage imgRDst, imgGDst, imgBDst; imgRDst.create(wUnpad, hUnpad, DImage::DImage_u8, 1, imgSrc.getAllocMethod()); imgGDst.create(wUnpad, hUnpad, DImage::DImage_u8, 1, imgSrc.getAllocMethod()); imgBDst.create(wUnpad, hUnpad, DImage::DImage_u8, 1, imgSrc.getAllocMethod()); pImgPad->splitRGB(imgR, imgG, imgB); #ifndef D_NOTHREADS for(int tnum = 1; tnum < _numThreads; ++tnum){ rgParms[tnum].pImgDst = &imgRDst; rgParms[tnum].pImgSrc = &imgR; rgParms[tnum].radiusX = _radiusX; rgParms[tnum].radiusY = _radiusY; rgParms[tnum].wKern = wKern; rgParms[tnum].hKern = hKern; rgParms[tnum].rgKern = rgKern; rgParms[tnum].numKernPxls = numKernPxls; rgParms[tnum].rgRightEdge = rgRightEdge; rgParms[tnum].pProg = NULL; rgParms[tnum].progStart = 0; rgParms[tnum].progMax = 1; rgParms[tnum].threadNumber = tnum; rgParms[tnum].numThreads = _numThreads; if(0 != pthread_create(&rgThreadID[tnum], NULL, DMaxFilter::DMaxFilter_Huang8threadWrap, &rgParms[tnum])){ fprintf(stderr, "DMaxFilter::filterImage_() failed to spawn " "thread #%d. Exiting.\n",tnum); exit(1); } } #endif maxFiltHuang_u8(imgRDst, imgR, _radiusX, _radiusY, wKern, hKern, rgKern, numKernPxls, rgRightEdge, pProg, 0, 3 * hUnpad); #ifndef D_NOTHREADS for(int tnum = 1; tnum < _numThreads; ++tnum){ if(pthread_join(rgThreadID[tnum],NULL)) fprintf(stderr, "DMaxFilter::filterImage_() failed to join " "thread %d\n", tnum); } for(int tnum = 1; tnum < _numThreads; ++tnum){ rgParms[tnum].pImgDst = &imgGDst; rgParms[tnum].pImgSrc = &imgG; if(0 != pthread_create(&rgThreadID[tnum], NULL, DMaxFilter::DMaxFilter_Huang8threadWrap, &rgParms[tnum])){ fprintf(stderr, "DMaxFilter::filterImage_() failed to spawn " "thread #%d. Exiting.\n",tnum); exit(1); } } #endif maxFiltHuang_u8(imgGDst, imgG, _radiusX, _radiusY, wKern, hKern, rgKern, numKernPxls, rgRightEdge, pProg, hUnpad, 3 * hUnpad); #ifndef D_NOTHREADS for(int tnum = 1; tnum < _numThreads; ++tnum){ if(pthread_join(rgThreadID[tnum],NULL)) fprintf(stderr, "DMaxFilter::filterImage_() failed to join " "thread %d\n", tnum); } for(int tnum = 1; tnum < _numThreads; ++tnum){ rgParms[tnum].pImgDst = &imgBDst; rgParms[tnum].pImgSrc = &imgB; if(0 != pthread_create(&rgThreadID[tnum], NULL, DMaxFilter::DMaxFilter_Huang8threadWrap, &rgParms[tnum])){ fprintf(stderr, "DMaxFilter::filterImage_() failed to spawn " "thread #%d. Exiting.\n",tnum); exit(1); } } #endif maxFiltHuang_u8(imgBDst, imgB, _radiusX, _radiusY, wKern, hKern, rgKern, numKernPxls, rgRightEdge, pProg, 2 * hUnpad, 3 * hUnpad+1); #ifndef D_NOTHREADS for(int tnum = 1; tnum < _numThreads; ++tnum){ if(pthread_join(rgThreadID[tnum],NULL)) fprintf(stderr, "DMaxFilter::filterImage_() failed to join " "thread %d\n", tnum); } #endif if(NULL != pProg){ pProg->reportStatus(3*hUnpad+1,0,3*hUnpad+1);//report complete } imgDst.combineRGB(imgRDst, imgGDst, imgBDst); } break; case DImage::DImage_dbl_multi: { int w, h, wm1, hm1; // width, height of padded image double *pDst; double *pPad; double *rgWindowBuff; fprintf(stderr, "DMaxFilter::filterImage_() performing brute-force " "(slow) max filter on double image... NOT YET IMPLEMENTED!\n"); exit(1); // w = pImgPad->width(); // h = pImgPad->height(); // wm1=w-1; // hm1 = h-1; // imgDst.create(wUnpad, hUnpad, DImage::DImage_dbl_multi, // imgSrc.numChannels(), imgSrc.getAllocMethod()); // rgWindowBuff = (double*)malloc(sizeof(double)*wKern*hKern); // D_CHECKPTR(rgWindowBuff); // for(int chan = 0; chan < imgSrc.numChannels(); ++chan){ // pDst = imgDst.dataPointer_dbl(chan); // pPad = pImgPad->dataPointer_dbl(chan); // for(int y = 0, idxDst = 0; y < hUnpad; ++y){ // int idxPad; // idxPad = (y+_radiusY)*w+_radiusX; // for(int x=0; x < wUnpad; ++x, ++idxDst, ++idxPad){ // int count; // count = 0; // for(int dy = -_radiusY; dy <= _radiusY; ++dy){ // for(int dx = -_radiusX; dx <= _radiusX; ++dx){ // rgWindowBuff[count] = pPad[idxPad+(dy*w)+dx]; // ++count; // } // } // // find max // qsort((void*)rgWindowBuff, count, sizeof(double),compareDoubles); // pDst[idxDst] = rgWindowBuff[count / 2]; // }//end for(x... // }//end for(y... // }//end for(chan... // free(rgWindowBuff); }//end block in case DImage_dbl_multi break; default: //TODO: finish implementing this fprintf(stderr, "DMaxFilter::filterImage_() not yet implemented for " "some image types\n"); exit(1); break; } if(!fAlreadyPadded){ delete pImgPad; pImgPad = NULL; } }
/** imgDst will be 2*radius pixels less wide and high than imgSrc * because of the padding that is added before calling this function. * This function requires that imgDst.create() has already been called * with the proper w,h,imgType,etc. */ void DMaxFilter::maxFiltHuang_u8_square(DImage &imgDst, const DImage &imgSrc, int radiusX, int radiusY, int wKern, int hKern, D_uint8 *rgKern, int numKernPxls, DProgress *pProg, int progStart, int progMax, int threadNumber, int numThreads){ int rgHist[256]; int max; unsigned char valTmp; int idxDst; int idx3; D_uint8 *pTmp; // pointer to padded image data int wTmp, hTmp; // width, height of imgSrc int w, h; // width, height of imgDst D_uint8 *pDst; wTmp = imgSrc.width(); hTmp = imgSrc.height(); w = wTmp - radiusX*2; h = hTmp - radiusY*2; pDst = imgDst.dataPointer_u8(); pTmp = imgSrc.dataPointer_u8(); for(int y = threadNumber; y < h; y += numThreads){ // update progress report and check if user cancelled the operation if((NULL != pProg) && (0 == (y & 0x0000003f))){ if(0 != pProg->reportStatus(progStart + y, 0, progMax)){ // the operation has been cancelled pProg->reportStatus(-1, 0, progMax); // report cancel acknowledged return; } } // position window at the beginning of a new row and fill the kernel, hist memset(rgHist, 0, sizeof(int)*256); for(int kr = 0, kidx =0; kr < hKern; ++kr){ for(int kc = 0; kc < wKern; ++kc, ++kidx){ if(rgKern[kidx]){ // pixel is part of the kernel mask ++(rgHist[pTmp[(y+kr)*wTmp+kc]]);//add pixel val to histogram } } } // calculate max for first spot for(max = 255; (max > 0) && (0==rgHist[max]); --max){ // do nothing } // put the max in the spot we're at idxDst = y*w; pDst[idxDst] = (unsigned char)max; // remove pixels from leftmost column idx3 = y*wTmp+radiusX; for(int ky = 0; ky < hKern; ++ky){ valTmp = pTmp[idx3 - wKern]; --(rgHist[valTmp]); if((valTmp==max)&&(0 == rgHist[valTmp])){//update the max for(;(max>0)&&(0==rgHist[max]); --max){ //do nothing } } idx3 += wTmp; } for(int x=1; x < w; ++x){ ++idxDst; // add pixels from the right-hand side of kernel (after moving over one) idx3 = y*wTmp+x+radiusX; for(int ky = 0; ky < hKern; ++ky){ valTmp = pTmp[idx3 + wKern]; if(valTmp > max)//update the max max = valTmp; ++(rgHist[valTmp]); idx3 += wTmp; } // put the max value in the destination pixel pDst[idxDst] = (unsigned char)max; // remove pixels from leftmost column for next time through loop if(x < (w-1)){//don't need to remove left edge if going to a new row idx3 = y*wTmp+x+radiusX; for(int ky = 0; ky < hKern; ++ky){ valTmp = pTmp[idx3 - wKern]; --(rgHist[valTmp]); if((valTmp==max)&&(0 == rgHist[valTmp])){//update the max for(;(max>0)&&(0==rgHist[max]); --max){ //do nothing } } idx3 += wTmp; } // end for(ky... } // end if } // end for (x=1; ... }// end for(y=0... // report progress if(NULL != pProg){ pProg->reportStatus(progStart + h, 0, progMax); } }
BOOL CsMIShopDoc::OnOpenDocument(LPCTSTR lpszPathName) { if (!CDocument::OnOpenDocument(lpszPathName)) return FALSE; // open CVoxel object m_pVoxel = new CVoxel<short>(lpszPathName); m_pDrawLayerZ = new cv::Mat[m_pVoxel->m_nZ]; m_pDrawLayerY = new cv::Mat[m_pVoxel->m_nY]; m_pDrawLayerX = new cv::Mat[m_pVoxel->m_nX]; for (int i = 0; i < m_pVoxel->m_nZ; i++) m_pDrawLayerZ[i].create(m_pVoxel->m_nY,m_pVoxel->m_nX,CV_8UC1); for (int i = 0; i < m_pVoxel->m_nY; i++) m_pDrawLayerY[i].create(m_pVoxel->m_nX, m_pVoxel->m_nZ, CV_8UC1); for (int i = 0; i < m_pVoxel->m_nX; i++) m_pDrawLayerX[i].create(m_pVoxel->m_nZ,m_pVoxel->m_nY,CV_8UC1); m_iMaxValue = m_pVoxel->m_nMaxI; m_iMinValue = m_pVoxel->m_nMinI; //for(int z = 0; z < m_pVoxel->m_nZ; z++) //for(int y = 0; y < m_pVoxel->m_nY; y++) //for(int x = 0; x < m_pVoxel->m_nX; x++) //{ // if(m_pVoxel->m_pData[z*m_pVoxel->m_nY*m_pVoxel->m_nX + y*m_pVoxel->m_nX + x] > m_iMaxValue) // m_iMaxValue = m_pVoxel->m_pData[z*m_pVoxel->m_nY*m_pVoxel->m_nX + y*m_pVoxel->m_nX + x]; // if (m_pVoxel->m_pData[z*m_pVoxel->m_nY*m_pVoxel->m_nX + y*m_pVoxel->m_nX + x] < m_iMinValue) // m_iMinValue = m_pVoxel->m_pData[z*m_pVoxel->m_nY*m_pVoxel->m_nX + y*m_pVoxel->m_nX + x]; // //} #if 0 // TEST 3: to warp with thin-plate spline - layer separation #endif #if 0 // TEST 2: try to extract bone (which has no motion) int imgw = m_pVoxel->m_nX; int imgh = m_pVoxel->m_nY; int nfrm = m_pVoxel->m_nZ; // construct average image cv::Mat avg = cv::Mat::zeros(imgh, imgw, CV_32F); for ( int y = 0; y < m_pVoxel->m_nY; y++ ) { float *avgp = avg.ptr<float>(y); for ( int x = 0; x < m_pVoxel->m_nX; x++ ) { for ( int i = 0; i < m_pVoxel->m_nZ; i++ ) { avgp[x] += m_pVoxel->GetAt(x,y,i); } } } avg = avg/(float)nfrm; // save average image cv::Mat avg_8u; avg.convertTo(avg_8u, CV_8U); cv::imwrite("avg_img.png", avg_8u); // compute subtraction image for all frames for ( int i = 0; i < nfrm; i++ ) { cv::Mat frm_idx = m_pVoxel->VoxelZSlice2cvMat<short>(i); cv::Mat frm_idx_f; frm_idx.convertTo(frm_idx_f, CV_32F); cv::Mat frm_sub = cv::abs(frm_idx_f - avg); double minf, maxf; cv::minMaxIdx(frm_sub, &minf, &maxf); cv::Mat frm_sub_8u; frm_sub.convertTo(frm_sub_8u, CV_8U, 255.0/(maxf-minf), -minf); char path[MAX_PATH]; sprintf(path, "frm_sub_%04d.png", i); cv::imwrite(path, frm_sub_8u); } #endif // TEST 1: compare optical flow between consecutive and synchronized frames // 20140825 ****** OPTICAL FLOW FAILS TOTALLY FOR 2D+t CARDIAC X-RAY IMAGES ****** // #if 0 ////////////////////////////////////////////////////////// // 20140820 *** ASSUME VESSEL IMAGE HAS BEEN LOADED *** // // set the parameters // para(1)--alpha (1), the regularization weight // para(2)--ratio (0.5), the downsample ratio // para(3)--minWidth (40), the width of the coarsest level // para(4)--nOuterFPIterations (3), the number of outer fixed point iterations // para(5)--nInnerFPIterations (1), the number of inner fixed point iterations // para(6)--nSORIterations (20), the number of SOR iterations double alpha= 0.012; double ratio=0.75; int minWidth= 32; int nOuterFPIterations = 5;//5; int nInnerFPIterations = 1;//3; int nSORIterations= 20;//40; // compute optical flow between consecutive frames int n_src = 24; int n_dst = 36; DImage frm_src = m_pVoxel->VoxelZSlice2DImage(n_src); DImage frm_dst = m_pVoxel->VoxelZSlice2DImage(n_dst); DImage cvx,cvy,cwarpI2; OpticalFlow::Coarse2FineFlow(cvx,cvy,cwarpI2,frm_src,frm_dst, alpha,ratio,minWidth,nOuterFPIterations,nInnerFPIterations,nSORIterations); char str[MAX_PATH], str_dst[MAX_PATH]; sprintf(str, "frm%04d.png", n_src); frm_src.imwrite(str); sprintf(str, "frm%04d.png", n_dst); frm_dst.imwrite(str); sprintf(str, "warp_%04d_%04d.png", n_src, n_dst); cwarpI2.imwrite(str); DImage vimgc = OptFlowVec2Color_DImage(&cvx, &cvy); sprintf(str, "motvec_%04d_%04d.png", n_src, n_dst); vimgc.imwrite(str); //DImage nimgc = OptFlowVecNorm2DImage(&cvx, &cvy, 0.5); DImage nimgc = OptFlowVecNorm2DImage(&cvx, &cvy); sprintf(str, "motnorm_%04d_%04d.png", n_src, n_dst); nimgc.imwrite(str); #endif ////////////////////////////////////////////////////////// return TRUE; }
/**This function calculates the vertical profile (the length of * profile will be the same as the height of the image). However, * instead of projecting pixels straight across to the vertical axis, * the projection is taken using lines angled through the middle * (x=width/2) of the image. Linear interpolation is used for * sampling the image pixel values since the y-position on the * projection lines will normally be "between" two pixels for any * given x-position. The function is intended only for angles between * -45 and 45 degrees, since otherwise the slope will be too steep for * the assumption I am making (I am steping through the x-values and * calculating the y-values. If the slope is steeper, I should do the * opposite. As a "to-do," maybe we should just check the angle and * handle the two cases individually). */ void DProfile::getAngledVertProfile(const DImage &img, double ang, int fNormalize){ double m; int x; double y, val; int hm1; double xc; int numPixels; D_uint8 *pimg; int w, h; int initialOffset=0; int *rgYoffsets; double *rgBotWeights; int yTop; int yTopPrev=0; int imglen; if(DImage::DImage_u8 != img.getImageType()){ fprintf(stderr, "DProfile::getAngledVertProfile() currently only supports 8-bit " "grayscale images\n"); abort(); } w=img.width(); h=img.height(); pimg = img.dataPointer_u8(); if(NULL == rgProf){ rgProf = (double*)malloc(h * sizeof(double)); D_CHECKPTR(rgProf); len = h; } else{ if(len != h){ rgProf = (double*)realloc(rgProf,h*sizeof(double)); D_CHECKPTR(rgProf); len = h; } } // memset(rgProf, 0, sizeof(double) * h); rgYoffsets = (int*)malloc(sizeof(int)*w); D_CHECKPTR(rgYoffsets); rgBotWeights = (double*)malloc(sizeof(double)*w); D_CHECKPTR(rgBotWeights); m = 1 * tan(DMath::degreesToRadians(ang)); /* dy per dx=1 */ xc = w / 2.; // initialOffset is the y-offset of first pixel, rgYoffsets[i] for i=1...w-1 // are the relative offsets from rgYoffsets[i-1] of the top pixel // rgBotWeights[i] is the interpolation weight of the bottom pixel, while // 1.-rgBotWeights[i] is the interpolation weight of the top pixel. for(x = 0; x < w; ++x){ y = m * ((double)x - xc); yTop = (int)(floor(y)); rgBotWeights[x] = y - (double)(yTop); if(0 == x){ rgYoffsets[0] = 0; initialOffset = yTop; } else rgYoffsets[x] = (yTop - yTopPrev); yTopPrev = yTop; } hm1 = h - 1; imglen = w * hm1; for(int i = 0; i < h; ++i){ /* profile index */ int idx; rgProf[i] = 0.; numPixels = 0; idx = w * (i + initialOffset); for(x = 0; x < w; ++x, ++idx){ idx += (w*rgYoffsets[x]);// go to next row if needed if((idx <0) || (idx >= imglen)) // out of bounds continue; ++numPixels; val = rgBotWeights[x] * pimg[idx] + (1.-rgBotWeights[x]) * pimg[idx+w]; rgProf[i] += val; } if((numPixels > 0) && fNormalize) rgProf[i] /= numPixels; } free(rgYoffsets); free(rgBotWeights); }
//-------------------------------------------------------------------------------------------------------- // function to compute optical flow field using two fixed point iterations // Input arguments: // Im1, Im2: frame 1 and frame 2 // warpIm2: the warped frame 2 according to the current flow field u and v // u,v: the current flow field, NOTICE that they are also output arguments // //-------------------------------------------------------------------------------------------------------- void OpticalFlow::SmoothFlowSOR(const DImage &Im1, const DImage &Im2, DImage &warpIm2, DImage &u, DImage &v, double alpha, int nOuterFPIterations, int nInnerFPIterations, int nSORIterations) { // DImage mask,imdx,imdy,imdt; DImage imdx,imdy,imdt; int imWidth,imHeight,nChannels,nPixels; imWidth=Im1.width(); imHeight=Im1.height(); nChannels=Im1.nchannels(); nPixels=imWidth*imHeight; DImage du(imWidth,imHeight),dv(imWidth,imHeight); DImage uu(imWidth,imHeight),vv(imWidth,imHeight); DImage ux(imWidth,imHeight),uy(imWidth,imHeight); DImage vx(imWidth,imHeight),vy(imWidth,imHeight); DImage Phi_1st(imWidth,imHeight); DImage Psi_1st(imWidth,imHeight,nChannels); DImage imdxy,imdx2,imdy2,imdtdx,imdtdy; DImage ImDxy,ImDx2,ImDy2,ImDtDx,ImDtDy; DImage foo1,foo2; double varepsilon_phi=pow(0.001,2); double varepsilon_psi=pow(0.001,2); //-------------------------------------------------------------------------- // the outer fixed point iteration //-------------------------------------------------------------------------- for(int count=0;count<nOuterFPIterations;count++) { // compute the gradient getDxs(imdx,imdy,imdt,Im1,warpIm2); // generate the mask to set the weight of the pxiels moving outside of the image boundary to be zero // genInImageMask(mask,u,v); // set the derivative of the flow field to be zero du.reset(); dv.reset(); //-------------------------------------------------------------------------- // the inner fixed point iteration //-------------------------------------------------------------------------- for(int hh=0;hh<nInnerFPIterations;hh++) { // compute the derivatives of the current flow field if(hh==0) { uu.copyData(u); vv.copyData(v); } else { uu.Add(u,du); vv.Add(v,dv); } uu.dx(ux); uu.dy(uy); vv.dx(vx); vv.dy(vy); // compute the weight of phi Phi_1st.reset(); _FlowPrecision* phiData=Phi_1st.data(); double temp; const _FlowPrecision *uxData,*uyData,*vxData,*vyData; uxData=ux.data(); uyData=uy.data(); vxData=vx.data(); vyData=vy.data(); for(int i=0;i<nPixels;i++) { temp=uxData[i]*uxData[i]+uyData[i]*uyData[i]+vxData[i]*vxData[i]+vyData[i]*vyData[i]; phiData[i] = 0.5/sqrt(temp+varepsilon_phi); } // compute the nonlinear term of psi Psi_1st.reset(); _FlowPrecision* psiData=Psi_1st.data(); const _FlowPrecision *imdxData,*imdyData,*imdtData; const _FlowPrecision *duData,*dvData; imdxData=imdx.data(); imdyData=imdy.data(); imdtData=imdt.data(); duData=du.data(); dvData=dv.data(); if(nChannels==1) for(int i=0;i<nPixels;i++) { temp=imdtData[i]+imdxData[i]*duData[i]+imdyData[i]*dvData[i]; temp *= temp; psiData[i]=1/(2*sqrt(temp+varepsilon_psi)); } else for(int i=0;i<nPixels;i++) for(int k=0;k<nChannels;k++) { int offset=i*nChannels+k; temp=imdtData[offset]+imdxData[offset]*duData[i]+imdyData[offset]*dvData[i]; temp *= temp; psiData[offset]=1/(2*sqrt(temp+varepsilon_psi)); } // prepare the components of the large linear system ImDxy.Multiply(Psi_1st,imdx,imdy); ImDx2.Multiply(Psi_1st,imdx,imdx); ImDy2.Multiply(Psi_1st,imdy,imdy); ImDtDx.Multiply(Psi_1st,imdx,imdt); ImDtDy.Multiply(Psi_1st,imdy,imdt); if(nChannels>1) { ImDxy.collapse(imdxy); ImDx2.collapse(imdx2); ImDy2.collapse(imdy2); ImDtDx.collapse(imdtdx); ImDtDy.collapse(imdtdy); } else { imdxy.copyData(ImDxy); imdx2.copyData(ImDx2); imdy2.copyData(ImDy2); imdtdx.copyData(ImDtDx); imdtdy.copyData(ImDtDy); } // laplacian filtering of the current flow field Laplacian(foo1,u,Phi_1st); Laplacian(foo2,v,Phi_1st); for(int i=0;i<nPixels;i++) { imdtdx.data()[i] = -imdtdx.data()[i]-alpha*foo1.data()[i]; imdtdy.data()[i] = -imdtdy.data()[i]-alpha*foo2.data()[i]; } // here we start SOR // set omega double omega = 1.8; du.reset(); dv.reset(); for(int k = 0; k<nSORIterations; k++) for(int i = 0; i<imHeight; i++) for(int j = 0; j<imWidth; j++) { int offset = i * imWidth+j; double sigma1 = 0, sigma2 = 0, coeff = 0; double _weight; if(j>0) { _weight = phiData[offset-1]; sigma1 += _weight*du.data()[offset-1]; sigma2 += _weight*dv.data()[offset-1]; coeff += _weight; } if(j<imWidth-1) { _weight = phiData[offset]; sigma1 += _weight*du.data()[offset+1]; sigma2 += _weight*dv.data()[offset+1]; coeff += _weight; } if(i>0) { _weight = phiData[offset-imWidth]; sigma1 += _weight*du.data()[offset-imWidth]; sigma2 += _weight*dv.data()[offset-imWidth]; coeff += _weight; } if(i<imHeight-1) { _weight = phiData[offset]; sigma1 += _weight*du.data()[offset+imWidth]; sigma2 += _weight*dv.data()[offset+imWidth]; coeff += _weight; } sigma1 *= -alpha; sigma2 *= -alpha; coeff *= alpha; // compute du sigma1 += imdxy.data()[offset]*dv.data()[offset]; du.data()[offset] = (1-omega)*du.data()[offset] + omega/(imdx2.data()[offset] + /*alpha*0.05*/ + coeff)*(imdtdx.data()[offset] - sigma1); // compute dv sigma2 += imdxy.data()[offset]*du.data()[offset]; dv.data()[offset] = (1-omega)*dv.data()[offset] + omega/(imdy2.data()[offset] + /*alpha*0.05*/ + coeff)*(imdtdy.data()[offset] - sigma2); } } u.Add(du); v.Add(dv); if(interpolation == Bilinear){ warpFL(warpIm2,Im1,Im2,u,v); } else { Im2.warpImageBicubicRef(Im1,warpIm2,u,v); warpIm2.threshold(); } } }
//-------------------------------------------------------------------------------------------------------- // function to compute optical flow field using two fixed point iterations // Input arguments: // Im1, Im2: frame 1 and frame 2 // warpIm2: the warped frame 2 according to the current flow field u and v // u,v: the current flow field, NOTICE that they are also output arguments // //-------------------------------------------------------------------------------------------------------- void OpticalFlow::SmoothFlowPDE(const DImage &Im1, const DImage &Im2, DImage &warpIm2, DImage &u, DImage &v, double alpha, int nOuterFPIterations, int nInnerFPIterations, int nCGIterations) { DImage mask,imdx,imdy,imdt; int imWidth,imHeight,nChannels,nPixels; imWidth=Im1.width(); imHeight=Im1.height(); nChannels=Im1.nchannels(); nPixels=imWidth*imHeight; DImage du(imWidth,imHeight),dv(imWidth,imHeight); DImage uu(imWidth,imHeight),vv(imWidth,imHeight); DImage ux(imWidth,imHeight),uy(imWidth,imHeight); DImage vx(imWidth,imHeight),vy(imWidth,imHeight); DImage Phi_1st(imWidth,imHeight); DImage Psi_1st(imWidth,imHeight,nChannels); DImage imdxy,imdx2,imdy2,imdtdx,imdtdy; DImage ImDxy,ImDx2,ImDy2,ImDtDx,ImDtDy; DImage A11,A12,A22,b1,b2; DImage foo1,foo2; // compute bicubic interpolation coeff //DImage BicubicCoeff; //Im2.warpImageBicubicCoeff(BicubicCoeff); double prob1,prob2,prob11,prob22; // variables for conjugate gradient DImage r1,r2,p1,p2,q1,q2; double* rou; rou=new double[nCGIterations]; double varepsilon_phi=pow(0.001,2); double varepsilon_psi=pow(0.001,2); //-------------------------------------------------------------------------- // the outer fixed point iteration //-------------------------------------------------------------------------- for(int count=0;count<nOuterFPIterations;count++) { // compute the gradient getDxs(imdx,imdy,imdt,Im1,warpIm2); // generate the mask to set the weight of the pxiels moving outside of the image boundary to be zero genInImageMask(mask,u,v); // set the derivative of the flow field to be zero du.reset(); dv.reset(); //-------------------------------------------------------------------------- // the inner fixed point iteration //-------------------------------------------------------------------------- for(int hh=0;hh<nInnerFPIterations;hh++) { // compute the derivatives of the current flow field if(hh==0) { uu.copyData(u); vv.copyData(v); } else { uu.Add(u,du); vv.Add(v,dv); } uu.dx(ux); uu.dy(uy); vv.dx(vx); vv.dy(vy); // compute the weight of phi Phi_1st.reset(); _FlowPrecision* phiData=Phi_1st.data(); _FlowPrecision temp; const _FlowPrecision *uxData,*uyData,*vxData,*vyData; uxData=ux.data(); uyData=uy.data(); vxData=vx.data(); vyData=vy.data(); double power_alpha = 0.5; for(int i=0;i<nPixels;i++) { temp=uxData[i]*uxData[i]+uyData[i]*uyData[i]+vxData[i]*vxData[i]+vyData[i]*vyData[i]; //phiData[i]=power_alpha*pow(temp+varepsilon_phi,power_alpha-1); phiData[i] = 0.5/sqrt(temp+varepsilon_phi); //phiData[i] = 1/(power_alpha+temp); } // compute the nonlinear term of psi Psi_1st.reset(); _FlowPrecision* psiData=Psi_1st.data(); const _FlowPrecision *imdxData,*imdyData,*imdtData; const _FlowPrecision *duData,*dvData; imdxData=imdx.data(); imdyData=imdy.data(); imdtData=imdt.data(); duData=du.data(); dvData=dv.data(); double _a = 10000, _b = 0.1; if(nChannels==1) for(int i=0;i<nPixels;i++) { temp=imdtData[i]+imdxData[i]*duData[i]+imdyData[i]*dvData[i]; //if(temp*temp<0.04) // psiData[i]=1/(2*sqrt(temp*temp+varepsilon_psi)); //psiData[i] = _a*_b/(1+_a*temp*temp); // the following code is for log Gaussian mixture probability model temp *= temp; switch(noiseModel) { case GMixture: prob1 = GMPara.Gaussian(temp,0,0)*GMPara.alpha[0]; prob2 = GMPara.Gaussian(temp,1,0)*(1-GMPara.alpha[0]); prob11 = prob1/(2*GMPara.sigma_square[0]); prob22 = prob2/(2*GMPara.beta_square[0]); psiData[i] = (prob11+prob22)/(prob1+prob2); break; case Lap: if(LapPara[0]<1E-20) continue; psiData[i]=1/(2*sqrt(temp+varepsilon_psi)*LapPara[0]); break; } } else for(int i=0;i<nPixels;i++) for(int k=0;k<nChannels;k++) { int offset=i*nChannels+k; temp=imdtData[offset]+imdxData[offset]*duData[i]+imdyData[offset]*dvData[i]; //if(temp*temp<0.04) // psiData[offset]=1/(2*sqrt(temp*temp+varepsilon_psi)); //psiData[offset] = _a*_b/(1+_a*temp*temp); temp *= temp; switch(noiseModel) { case GMixture: prob1 = GMPara.Gaussian(temp,0,k)*GMPara.alpha[k]; prob2 = GMPara.Gaussian(temp,1,k)*(1-GMPara.alpha[k]); prob11 = prob1/(2*GMPara.sigma_square[k]); prob22 = prob2/(2*GMPara.beta_square[k]); psiData[offset] = (prob11+prob22)/(prob1+prob2); break; case Lap: if(LapPara[k]<1E-20) continue; psiData[offset]=1/(2*sqrt(temp+varepsilon_psi)*LapPara[k]); break; } } // prepare the components of the large linear system ImDxy.Multiply(Psi_1st,imdx,imdy); ImDx2.Multiply(Psi_1st,imdx,imdx); ImDy2.Multiply(Psi_1st,imdy,imdy); ImDtDx.Multiply(Psi_1st,imdx,imdt); ImDtDy.Multiply(Psi_1st,imdy,imdt); if(nChannels>1) { ImDxy.collapse(imdxy); ImDx2.collapse(imdx2); ImDy2.collapse(imdy2); ImDtDx.collapse(imdtdx); ImDtDy.collapse(imdtdy); } else { imdxy.copyData(ImDxy); imdx2.copyData(ImDx2); imdy2.copyData(ImDy2); imdtdx.copyData(ImDtDx); imdtdy.copyData(ImDtDy); } // filtering //imdx2.smoothing(A11,3); //imdxy.smoothing(A12,3); //imdy2.smoothing(A22,3); A11.copyData(imdx2); A12.copyData(imdxy); A22.copyData(imdy2); // add epsilon to A11 and A22 A11.Add(alpha*0.5); A22.Add(alpha*0.5); // form b //imdtdx.smoothing(b1,3); //imdtdy.smoothing(b2,3); b1.copyData(imdtdx); b2.copyData(imdtdy); // laplacian filtering of the current flow field Laplacian(foo1,u,Phi_1st); Laplacian(foo2,v,Phi_1st); _FlowPrecision *b1Data,*b2Data; const _FlowPrecision *foo1Data,*foo2Data; b1Data=b1.data(); b2Data=b2.data(); foo1Data=foo1.data(); foo2Data=foo2.data(); for(int i=0;i<nPixels;i++) { b1Data[i]=-b1Data[i]-alpha*foo1Data[i]; b2Data[i]=-b2Data[i]-alpha*foo2Data[i]; } // for debug only, displaying the matrix coefficients //A11.imwrite("A11.bmp",ImageIO::normalized); //A12.imwrite("A12.bmp",ImageIO::normalized); //A22.imwrite("A22.bmp",ImageIO::normalized); //b1.imwrite("b1.bmp",ImageIO::normalized); //b2.imwrite("b2.bmp",ImageIO::normalized); //----------------------------------------------------------------------- // conjugate gradient algorithm //----------------------------------------------------------------------- r1.copyData(b1); r2.copyData(b2); du.reset(); dv.reset(); for(int k=0;k<nCGIterations;k++) { rou[k]=r1.norm2()+r2.norm2(); //cout<<rou[k]<<endl; if(rou[k]<1E-10) break; if(k==0) { p1.copyData(r1); p2.copyData(r2); } else { double ratio=rou[k]/rou[k-1]; p1.Add(r1,p1,ratio); p2.Add(r2,p2,ratio); } // go through the large linear system foo1.Multiply(A11,p1); foo2.Multiply(A12,p2); q1.Add(foo1,foo2); Laplacian(foo1,p1,Phi_1st); q1.Add(foo1,alpha); foo1.Multiply(A12,p1); foo2.Multiply(A22,p2); q2.Add(foo1,foo2); Laplacian(foo2,p2,Phi_1st); q2.Add(foo2,alpha); double beta; beta=rou[k]/(p1.innerproduct(q1)+p2.innerproduct(q2)); du.Add(p1,beta); dv.Add(p2,beta); r1.Add(q1,-beta); r2.Add(q2,-beta); } //----------------------------------------------------------------------- // end of conjugate gradient algorithm //----------------------------------------------------------------------- }// end of inner fixed point iteration // the following procedure is merely for debugging //cout<<"du "<<du.norm2()<<" dv "<<dv.norm2()<<endl; // update the flow field u.Add(du,1); v.Add(dv,1); if(interpolation == Bilinear) warpFL(warpIm2,Im1,Im2,u,v); else { Im2.warpImageBicubicRef(Im1,warpIm2,u,v); warpIm2.threshold(); } //Im2.warpImageBicubicRef(Im1,warpIm2,BicubicCoeff,u,v); // estimate noise level switch(noiseModel) { case GMixture: estGaussianMixture(Im1,warpIm2,GMPara); break; case Lap: estLaplacianNoise(Im1,warpIm2,LapPara); } }// end of outer fixed point iteration delete rou; }
//-------------------------------------------------------------------------------------- // function to perfomr coarse to fine optical flow estimation //-------------------------------------------------------------------------------------- void OpticalFlow::Coarse2FineFlow(DImage &vx, DImage &vy, DImage &warpI2,const DImage &Im1, const DImage &Im2, double alpha, double ratio, int minWidth, int nOuterFPIterations, int nInnerFPIterations, int nCGIterations) { // first build the pyramid of the two images GaussianPyramid GPyramid1; GaussianPyramid GPyramid2; if(IsDisplay) cout<<"Constructing pyramid..."; GPyramid1.ConstructPyramid(Im1,ratio,minWidth); GPyramid2.ConstructPyramid(Im2,ratio,minWidth); if(IsDisplay) cout<<"done!"<<endl; // now iterate from the top level to the bottom DImage Image1,Image2,WarpImage2; // initialize noise // cout << GPyramid1.nlevels() << " pyramid levels\n"; for(int k=GPyramid1.nlevels()-1;k>=0;k--) { if(IsDisplay) cout<<"Pyramid level "<<k+1; int width=GPyramid1.Image(k).width(); int height=GPyramid1.Image(k).height(); im2feature(Image1,GPyramid1.Image(k)); im2feature(Image2,GPyramid2.Image(k)); // cout << "\t- level " << k+1 << " size " << width <<"x" << height <<endl; if(k==GPyramid1.nlevels()-1) // if at the top level { vx.allocate(width,height); vy.allocate(width,height); WarpImage2.copyData(Image2); } else { vx.imresize(width,height); vx.Multiplywith(1/ratio); vy.imresize(width,height); vy.Multiplywith(1/ratio); if(interpolation == Bilinear) warpFL(WarpImage2,Image1,Image2,vx,vy); else Image2.warpImageBicubicRef(Image1,WarpImage2,vx,vy); } SmoothFlowSOR(Image1,Image2,WarpImage2,vx,vy,alpha,nOuterFPIterations+k,nInnerFPIterations,nCGIterations+k*3); //GMPara.display(); if(IsDisplay) cout<<endl; } //warpFL(warpI2,Im1,Im2,vx,vy); Im2.warpImageBicubicRef(Im1,warpI2,vx,vy); warpI2.threshold(); }
//-------------------------------------------------------------------------------------------------------- // function to compute optical flow field using two fixed point iterations // Input arguments: // Im1, Im2: frame 1 and frame 2 // warpIm2: the warped frame 2 according to the current flow field u and v // u,v: the current flow field, NOTICE that they are also output arguments // //-------------------------------------------------------------------------------------------------------- void OpticalFlow::SmoothFlowPDE(const DImage &Im1, const DImage &Im2, DImage &warpIm2, DImage &u, DImage &v, double alpha, int nOuterFPIterations, int nInnerFPIterations, int nCGIterations) { DImage mask,imdx,imdy,imdt; int imWidth,imHeight,nChannels,nPixels; imWidth=Im1.width(); imHeight=Im1.height(); nChannels=Im1.nchannels(); nPixels=imWidth*imHeight; DImage du(imWidth,imHeight),dv(imWidth,imHeight); DImage uu(imWidth,imHeight),vv(imWidth,imHeight); DImage ux(imWidth,imHeight),uy(imWidth,imHeight); DImage vx(imWidth,imHeight),vy(imWidth,imHeight); DImage Phi_1st(imWidth,imHeight); DImage Psi_1st(imWidth,imHeight,nChannels); DImage imdxy,imdx2,imdy2,imdtdx,imdtdy; DImage ImDxy,ImDx2,ImDy2,ImDtDx,ImDtDy; DImage A11,A12,A22,b1,b2; DImage foo1,foo2; // variables for conjugate gradient DImage r1,r2,p1,p2,q1,q2; double* rou; rou=new double[nCGIterations]; double varepsilon_phi=pow(0.001,2); double varepsilon_psi=pow(0.001,2); //-------------------------------------------------------------------------- // the outer fixed point iteration //-------------------------------------------------------------------------- for(int count=0; count<nOuterFPIterations; count++) { // compute the gradient getDxs(imdx,imdy,imdt,Im1,warpIm2); // generate the mask to set the weight of the pxiels moving outside of the image boundary to be zero genInImageMask(mask,vx,vy); // set the derivative of the flow field to be zero du.reset(); dv.reset(); //-------------------------------------------------------------------------- // the inner fixed point iteration //-------------------------------------------------------------------------- for(int hh=0; hh<nInnerFPIterations; hh++) { // compute the derivatives of the current flow field if(hh==0) { uu.copyData(u); vv.copyData(v); } else { uu.Add(u,du); vv.Add(v,dv); } uu.dx(ux); uu.dy(uy); vv.dx(vx); vv.dy(vy); // compute the weight of phi Phi_1st.reset(); double* phiData=Phi_1st.data(); double temp; const double *uxData,*uyData,*vxData,*vyData; uxData=ux.data(); uyData=uy.data(); vxData=vx.data(); vyData=vy.data(); for(int i=0; i<nPixels; i++) { temp=uxData[i]*uxData[i]+uyData[i]*uyData[i]+vxData[i]*vxData[i]+vyData[i]*vyData[i]; phiData[i]=1/(2*sqrt(temp+varepsilon_phi)); } // compute the nonlinear term of psi Psi_1st.reset(); double* psiData=Psi_1st.data(); const double *imdxData,*imdyData,*imdtData; const double *duData,*dvData; imdxData=imdx.data(); imdyData=imdy.data(); imdtData=imdt.data(); duData=du.data(); dvData=dv.data(); double _a = 10000, _b = 0.1; if(nChannels==1) { for(int i=0; i<nPixels; i++) { temp=imdtData[i]+imdxData[i]*duData[i]+imdyData[i]*dvData[i]; //if(temp*temp<0.04) psiData[i]=1/(2*sqrt(temp*temp+varepsilon_psi)); //psiData[i] = _a*_b/(1+_a*temp*temp); } } else { for(int i=0; i<nPixels; i++) for(int k=0; k<nChannels; k++) { int offset=i*nChannels+k; temp=imdtData[offset]+imdxData[offset]*duData[i]+imdyData[offset]*dvData[i]; //if(temp*temp<0.04) psiData[offset]=1/(2*sqrt(temp*temp+varepsilon_psi)); //psiData[offset] = _a*_b/(1+_a*temp*temp); } } // prepare the components of the large linear system ImDxy.Multiply(Psi_1st,imdx,imdy); ImDx2.Multiply(Psi_1st,imdx,imdx); ImDy2.Multiply(Psi_1st,imdy,imdy); ImDtDx.Multiply(Psi_1st,imdx,imdt); ImDtDy.Multiply(Psi_1st,imdy,imdt); if(nChannels>1) { ImDxy.collapse(imdxy); ImDx2.collapse(imdx2); ImDy2.collapse(imdy2); ImDtDx.collapse(imdtdx); ImDtDy.collapse(imdtdy); } else { imdxy.copyData(ImDxy); imdx2.copyData(ImDx2); imdy2.copyData(ImDy2); imdtdx.copyData(ImDtDx); imdtdy.copyData(ImDtDy); } // filtering imdx2.smoothing(A11,3); imdxy.smoothing(A12,3); imdy2.smoothing(A22,3); // add epsilon to A11 and A22 A11.Add(alpha*0.1); A22.Add(alpha*0.1); // form b imdtdx.smoothing(b1,3); imdtdy.smoothing(b2,3); // laplacian filtering of the current flow field Laplacian(foo1,u,Phi_1st); Laplacian(foo2,v,Phi_1st); double *b1Data,*b2Data; const double *foo1Data,*foo2Data; b1Data=b1.data(); b2Data=b2.data(); foo1Data=foo1.data(); foo2Data=foo2.data(); for(int i=0; i<nPixels; i++) { b1Data[i]=-b1Data[i]-alpha*foo1Data[i]; b2Data[i]=-b2Data[i]-alpha*foo2Data[i]; } // for debug only, displaying the matrix coefficients //A11.imwrite("A11.bmp",ImageIO::normalized); //A12.imwrite("A12.bmp",ImageIO::normalized); //A22.imwrite("A22.bmp",ImageIO::normalized); //b1.imwrite("b1.bmp",ImageIO::normalized); //b2.imwrite("b2.bmp",ImageIO::normalized); //----------------------------------------------------------------------- // conjugate gradient algorithm //----------------------------------------------------------------------- r1.copyData(b1); r2.copyData(b2); du.reset(); dv.reset(); for(int k=0; k<nCGIterations; k++) { rou[k]=r1.norm2()+r2.norm2(); //cout<<rou[k]<<endl; if(rou[k]<1E-10) break; if(k==0) { p1.copyData(r1); p2.copyData(r2); } else { double ratio=rou[k]/rou[k-1]; p1.Add(r1,p1,ratio); p2.Add(r2,p2,ratio); } // go through the large linear system foo1.Multiply(A11,p1); foo2.Multiply(A12,p2); q1.Add(foo1,foo2); Laplacian(foo1,p1,Phi_1st); q1.Add(foo1,alpha); foo1.Multiply(A12,p1); foo2.Multiply(A22,p2); q2.Add(foo1,foo2); Laplacian(foo2,p2,Phi_1st); q2.Add(foo2,alpha); double beta; beta=rou[k]/(p1.innerproduct(q1)+p2.innerproduct(q2)); du.Add(p1,beta); dv.Add(p2,beta); r1.Add(q1,-beta); r2.Add(q2,-beta); } //----------------------------------------------------------------------- // end of conjugate gradient algorithm //----------------------------------------------------------------------- }// end of inner fixed point iteration // the following procedure is merely for debugging //cout<<"du "<<du.norm2()<<" dv "<<dv.norm2()<<endl; // update the flow field u.Add(du,1); v.Add(dv,1); warpFL(warpIm2,Im1,Im2,u,v); }// end of outer fixed point iteration delete rou; }
//-------------------------------------------------------------------------------------------------------- // function to do sanity check: imdx*du+imdy*dy+imdt=0 //-------------------------------------------------------------------------------------------------------- void OpticalFlow::SanityCheck(const DImage &imdx, const DImage &imdy, const DImage &imdt, double du, double dv) { if(imdx.matchDimension(imdy)==false || imdx.matchDimension(imdt)==false) { cout<<"The dimensions of the derivatives don't match!"<<endl; return; } const _FlowPrecision* pImDx,*pImDy,*pImDt; pImDx=imdx.data(); pImDy=imdy.data(); pImDt=imdt.data(); double error=0; for(int i=0;i<imdx.height();i++) for(int j=0;j<imdx.width();j++) for(int k=0;k<imdx.nchannels();k++) { int offset=(i*imdx.width()+j)*imdx.nchannels()+k; double temp=pImDx[offset]*du+pImDy[offset]*dv+pImDt[offset]; error+=fabs(temp); } error/=imdx.nelements(); cout<<"The mean error of |dx*u+dy*v+dt| is "<<error<<endl; }
//-------------------------------------------------------------------------------------- // function to perfomr coarse to fine optical flow estimation //-------------------------------------------------------------------------------------- void OpticalFlow::Coarse2FineFlow(DImage &vx, DImage &vy, DImage &warpI2,const DImage &Im1, const DImage &Im2, double alpha, double ratio, int minWidth, int nOuterFPIterations, int nInnerFPIterations, int nCGIterations) { // first build the pyramid of the two images GaussianPyramid GPyramid1; GaussianPyramid GPyramid2; if(IsDisplay) cout<<"Constructing pyramid..."; GPyramid1.ConstructPyramid(Im1,ratio,minWidth); GPyramid2.ConstructPyramid(Im2,ratio,minWidth); if(IsDisplay) cout<<"done!"<<endl; // now iterate from the top level to the bottom DImage Image1,Image2,WarpImage2; //GaussianMixture GMPara(Im1.nchannels()+2); // initialize noise switch(noiseModel){ case GMixture: GMPara.reset(Im1.nchannels()+2); break; case Lap: LapPara.allocate(Im1.nchannels()+2); for(int i = 0;i<LapPara.dim();i++) LapPara[i] = 0.02; break; } for(int k=GPyramid1.nlevels()-1;k>=0;k--) { if(IsDisplay) cout<<"Pyramid level "<<k; int width=GPyramid1.Image(k).width(); int height=GPyramid1.Image(k).height(); im2feature(Image1,GPyramid1.Image(k)); im2feature(Image2,GPyramid2.Image(k)); if(k==GPyramid1.nlevels()-1) // if at the top level { vx.allocate(width,height); vy.allocate(width,height); //warpI2.copyData(Image2); WarpImage2.copyData(Image2); } else { vx.imresize(width,height); vx.Multiplywith(1/ratio); vy.imresize(width,height); vy.Multiplywith(1/ratio); //warpFL(warpI2,GPyramid1.Image(k),GPyramid2.Image(k),vx,vy); if(interpolation == Bilinear) warpFL(WarpImage2,Image1,Image2,vx,vy); else Image2.warpImageBicubicRef(Image1,WarpImage2,vx,vy); } //SmoothFlowPDE(GPyramid1.Image(k),GPyramid2.Image(k),warpI2,vx,vy,alpha,nOuterFPIterations,nInnerFPIterations,nCGIterations); //SmoothFlowPDE(Image1,Image2,WarpImage2,vx,vy,alpha*pow((1/ratio),k),nOuterFPIterations,nInnerFPIterations,nCGIterations,GMPara); //SmoothFlowPDE(Image1,Image2,WarpImage2,vx,vy,alpha,nOuterFPIterations,nInnerFPIterations,nCGIterations); SmoothFlowSOR(Image1,Image2,WarpImage2,vx,vy,alpha,nOuterFPIterations+k,nInnerFPIterations,nCGIterations+k*3); //GMPara.display(); if(IsDisplay) cout<<endl; } //warpFL(warpI2,Im1,Im2,vx,vy); Im2.warpImageBicubicRef(Im1,warpI2,vx,vy); warpI2.threshold(); }
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { // check for proper number and size of arguments //errCheck(nrhs == 1,"Arguments: filePath"); //errCheck(nlhs == 1,"Outputs: skew"); std::string inDir = mxArrayToString(prhs[0]); std::string filePath = mxArrayToString(prhs[1]); std::string dirPath = mxArrayToString(prhs[2]); double slant = mxGetScalar(prhs[3]); bool VIZ=false; /*if (filePath.compare("wordimg_9")==0 || filePath.compare("wordimg_78")==0 ) VIZ=true; */ //DImage img(("tmp/"+filePath+".tif").c_str(),DImage::DFileFormat_tiff); Mat mat = imread(inDir+filePath, CV_LOAD_IMAGE_GRAYSCALE); //cout << "read image" <<endl; //TODO clean Mat initBin = Binarization::otsuBinarization(mat); if (VIZ) {Binarization::imshowB("otsu",initBin,255,0); waitKey();} Mat dilated = Binarization::dilate(initBin,3);//dilate the fg, shrinking the bg //cout << "dilated" <<endl; Mat dilatedFlip = dilated.clone(); for (int r=0; r<dilatedFlip.rows; r++) for (int c=0; c<dilatedFlip.cols; c++) { if (dilatedFlip.at<unsigned char>(r,c)==1) dilatedFlip.at<unsigned char>(r,c)=0; else dilatedFlip.at<unsigned char>(r,c)=1; } Mat prime; Mat bg_estimation = Binarization::inpainting(mat,dilatedFlip,&prime); //cout << "inpainted" <<endl; if (VIZ) {imshow("bg_estimation",bg_estimation); waitKey();} double average, std; Binarization::extract_feat(prime, NULL, &average, &std); bg_estimation = Binarization::inpainting(mat,dilatedFlip,NULL,&average,&std); //cout << "found avg" <<endl; DImage img; convertMatToDImage(mat,&img); //cout << "converted" <<endl; int pad=255; img = img.shearedH(slant,pad,true);//fill corners with black //cout << "sheared" <<endl; convertDImageToMat(img,&mat); //cout << "converted back" <<endl; if (VIZ) {imshow("sheared",mat); waitKey();} //fill corners Mat fillMaskFlipped(mat.rows,mat.cols,CV_8U,Scalar(1)); for (int r=fillMaskFlipped.rows-1; r>=0; r--) for (int c=0; c<fillMaskFlipped.cols; c++) { int flag = (abs(mat.at<unsigned char>(r,c)-pad)<3 || abs(mat.at<unsigned char>(r+1,c-1)-pad)<3 || abs(mat.at<unsigned char>(r-1,c+1)-pad)<3)?0:1; fillMaskFlipped.at<unsigned char>(r,c)=flag; } /* int space=1; //for (int r=fillMaskFlipped.rows-1; r>fillMaskFlipped.rows-1-space; r--) // for (int c=0; c<space; c++) // { // int flag = (abs(mat.at<unsigned char>(r,c)-pad)<3)?0:1; // fillMaskFlipped.at<unsigned char>(r,c)=flag; // } for (int r=fillMaskFlipped.rows-1; r>=0; r--) for (int c=0; c<space; c++) { int flag = (abs(mat.at<unsigned char>(r,c)-pad)<3)?0:1; fillMaskFlipped.at<unsigned char>(r,c)=flag; } for (int c=0; c<fillMaskFlipped.cols; c++) for (int r=fillMaskFlipped.rows-1; r>fillMaskFlipped.rows-1-space; r--) { int flag = (abs(mat.at<unsigned char>(r,c)-pad)<3)?0:1; fillMaskFlipped.at<unsigned char>(r,c)=flag; } for (int c=0; c<fillMaskFlipped.cols-space; c++) { bool cont=false; for (int r=fillMaskFlipped.rows-1; r>=space; r--) { int flag = (abs(mat.at<unsigned char>(r,c)-pad)<3)?0:1; if (flag==0 && !cont) cont=true; fillMaskFlipped.at<unsigned char>(r-space,c+space)=flag; //if (r==fillMaskFlipped.rows-1 && flag==0) //{ // for (int rf=r-space-1; rf<=fillMaskFlipped.rows-1; rf++) // fillMaskFlipped.at<unsigned char>(rf,c+space)=flag; //} //if (c==0 && flag==0) //{ // for (int cf=c+space-1; cf>=0; cf--) // fillMaskFlipped.at<unsigned char>(r-space,cf)=flag; //} } if (!cont) break; } //for (int c=fillMaskFlipped.cols-1; c>fillMaskFlipped.cols-1-space; c--) // for (int r=0; r<space; r++) // { // int flag = (abs(mat.at<unsigned char>(r,c)-pad)<3)?0:1; // fillMaskFlipped.at<unsigned char>(r,c)=flag; // } for (int c=fillMaskFlipped.cols-1; c>=0; c--) for (int r=0; r<space; r++) { int flag = (abs(mat.at<unsigned char>(r,c)-pad)<3)?0:1; fillMaskFlipped.at<unsigned char>(r,c)=flag; } for (int r=0; r<fillMaskFlipped.rows; r++) for (int c=fillMaskFlipped.cols-1; c>fillMaskFlipped.cols-1-space; c--) { int flag = (abs(mat.at<unsigned char>(r,c)-pad)<3)?0:1; fillMaskFlipped.at<unsigned char>(r,c)=flag; } for (int c=fillMaskFlipped.cols-1; c>=space; c--) { bool cont=false; for (int r=0; r<fillMaskFlipped.rows-space; r++) { int flag = (abs(mat.at<unsigned char>(r,c)-pad)<3)?0:1; if (flag==0 && !cont) cont=true; fillMaskFlipped.at<unsigned char>(r+space,c-space)=flag; //if (c==fillMaskFlipped.cols-1 && flag==0) //{ // for (int cf=c-space-1; cf<=fillMaskFlipped.cols-1; cf++) // fillMaskFlipped.at<unsigned char>(r+space,cf)=flag; //} //if (r==0 && flag==0) //{ // for (int rf=r+space-1; rf>=0; rf--) // fillMaskFlipped.at<unsigned char>(rf,c-space)=flag; //} } if (!cont) break; }*/ if (VIZ) { Binarization::imshowB("fillamsk",fillMaskFlipped,255,0); waitKey(); Mat showMask = mat.clone(); Mat showUnmask = mat.clone(); for (int r=fillMaskFlipped.rows-1; r>=0; r--) for (int c=0; c<fillMaskFlipped.cols; c++) { if (fillMaskFlipped.at<unsigned char>(r,c) == 0) showUnmask.at<unsigned char>(r,c)=255; else if (fillMaskFlipped.at<unsigned char>(r,c) == 1) showMask.at<unsigned char>(r,c)=255; } imshow("masked",showMask); waitKey(); imshow("unmasked",showUnmask); waitKey(); } mat = Binarization::inpainting(mat,fillMaskFlipped,NULL,&average,&std,VIZ); //cout << "filled" <<endl; /*for (int r=0; r<mat.rows; r++) for (int c=0; c<mat.cols; c++) { if (fillMaskFlipped.at<unsigned char>(r,c)==0 && fabs(mat.at<unsigned char>(r,c)-average)>std) mat.at<unsigned char>(r,c)=average; }*/ if (VIZ) {imshow("filled",mat); waitKey();} //img.save((dirPath+"/"+filePath+".png").c_str(), DImage::DFileFormat_png); imwrite(dirPath+"/"+filePath,mat); //cout << "write "<<dirPath<<"/"<<filePath<<".png"<<endl; }
/**Computes the projection profile of img onto an axis with angle axisAngDeg. Horizontal and vertical profiles (when axisAngDeg is 0 or 90 degress, respectively) are special-cased for speed by calling getImageVerticalProfile() or getImageHorizontalProfile(). I have seen inconsistent usage of the terms "vertical profile" and "horizontal profile" since some people describe the direction of projection instead of the direction of the axis onto which the image is projected. It seems more common, however, to use the direction of the axis. Therefore, when I say "vertical profile," I mean that the profile length is equal to the height of the image, and the Rth value in the profile array is the sum of the values in the Rth row of the image. Likewise, a horizontal profile has length equal to the image width, and each value is the projection of the corresponding image column onto the horizontal axis. For a horizontal profile, set axisAngDeg to 0. For a vertical profile, set axisAngDeg to 90. Note that angles increase clockwise since the y-coordinate of images increases from top to bottom. For RGB images and multi-channel float or double images, the sum of all channels is used (a single profile is calculated). If this is not what is desired, you could create separate images for each channel and take the profiles seperately. Complex images are not supported directly, so they must be converted into a different type before a profile can be taken. If fInterp is false (default), then the nearest image pixel value is used when the position the profile passes through is between pixels. If fInterp is true, bilinear interpolation is used to estimate the value that should go in the profile.*/ void DProfile::getImageProfile(const DImage &img, double axisAngDeg, bool fNormalize, bool fInterp){ int w, h; double wm1, hm1; int numPixels; double dblSum; double theta; double dblTmp; int alen;//length of anchor segment. The anchor segment is the //segment that passes through the center of the image and //is oriented perpendicular to axisAngDeg. The length of //the profile will be equal to alen. int olen;//length of offset segments. The offset segments are the //integration paths parallel to axisAngDeg (one segment per //profile value. double asx, asy;//start (x,y) of the anchor segment double adx, ady;//deltaX and deltaY of the anchor segment double ax, ay; // current anchor point (x,y along the anchor segment) double osx, osy;//starty x,y offset from ax,ay for an offset segment double odx, ody;//deltaX and deltaY of offset segments double ox, oy; // current offset point (x,y along the offset segment) if(DImage::DImage_cmplx == img.getImageType()){ fprintf(stderr, "DProfile::getImageProfile() does not support complex images\n"); abort(); } // if(((axisAngDeg > -0.00001) && (axisAngDeg < 0.00001)) || // ((axisAngDeg > 179.00001) && (axisAngDeg < 180.00001)) || // ((axisAngDeg > 359.00001) && (axisAngDeg < 360.00001))){ // getImageHorizontalProfile(img, fNormalize); // return; // } // if(((axisAngDeg > 89.00001) && (axisAngDeg < 90.00001)) || // ((axisAngDeg > 269.00001) && (axisAngDeg < 270.00001)) || // ((axisAngDeg < -269.00001) && (axisAngDeg > -270.00001)) || // ((axisAngDeg < -89.00001) && (axisAngDeg > -90.00001))){ // getImageVerticalProfile(img, fNormalize); // return; // } w = img.width(); h = img.height(); wm1 = w-1; hm1 = h-1; theta = DMath::degreesToRadians(axisAngDeg); //figure out how long rgProf should be and how wide the integration should be odx = cos(theta); ody = sin(theta); adx = -1. * ody; ady = odx; olen = (int)(2*DMath::distPointLine(0, 0, w/2., h/2., w/2.+adx, h/2.+ady)); dblTmp = 2*DMath::distPointLine(w, 0, w/2., h/2., w/2.+adx, h/2.+ady); if(dblTmp > olen) olen = (int)dblTmp; alen = (int)(2*DMath::distPointLine(0, 0, w/2., h/2., w/2.+odx, h/2.+ody)); dblTmp = 2*DMath::distPointLine(w, 0, w/2., h/2., w/2.+odx, h/2.+ody); if(dblTmp > alen) alen = (int)dblTmp; // printf("w=%d h=%d\n", w, h); // printf("adx=%.2f ady=%.2f alen=%d\n", adx, ady, alen); // printf("odx=%.2f ody=%.2f olen=%d\n", odx, ody, olen); // allocate the rgProf array if(NULL == rgProf){ rgProf = (double*)malloc(alen * sizeof(double)); D_CHECKPTR(rgProf); len = alen; } else{ if(len != alen){ rgProf = (double*)realloc(rgProf,alen*sizeof(double)); D_CHECKPTR(rgProf); len = alen; } } ax = asx = w/2.-(alen/2*adx); ay = asy = h/2.-(alen/2*ady); osx = -(olen/2*odx); osy = -(olen/2*ody); switch(img.getImageType()){ case DImage::DImage_u8: { D_uint8 *pu8; pu8=img.dataPointer_u8(); if(fInterp){ fprintf(stderr, "WARNING! DProfile::getImageProfile() may be buggy " "when fInterp is true\n"); for(int aa=0; aa < alen; ++aa){ int ix, iy; double w1, w2; //weight of left vs right pixels double w3, w4;//weight of top vs bottom pixels double left, right; int oidx; ox = ax+osx; oy = ay+osy; numPixels = 0; dblSum = 0.; for(int oo=0; oo < olen; ++oo){ if( (ox>=0) && (ox < wm1) && (oy>=0) && (oy<hm1)){ ix = (int)ox; iy = (int)oy; oidx = iy*w + ix; w2 = ox-ix; w1 = 1.-w2; w4 = oy-iy; w3 = 1.-w4; left = (pu8[oidx] * w3 + pu8[oidx+w] * w4); right = (pu8[oidx+1] * w3 + pu8[oidx+w+1] * w4); dblSum += left*w1 + right*w2; ++numPixels; } else if((ox==wm1) || (oy == hm1)){ // don't interpolate on the edges, just approximate ix = (int)ox; iy = (int)oy; oidx = iy*w + ix; dblSum += pu8[oidx]; ++numPixels; } ox += odx; oy += ody; } ax += adx; ay += ady; if(fNormalize && (numPixels>0)) rgProf[aa] = dblSum / numPixels; else rgProf[aa] = dblSum; } } else{ for(int aa=0; aa < alen; ++aa){ int ix, iy; int oidx; ox = ax+osx; oy = ay+osy; numPixels = 0; dblSum = 0.; for(int oo=0; oo < olen; ++oo){ if( (ox>=0) && (ox <w) && (oy>=0) && (oy<h)){ ix = (int)ox; iy = (int)oy; oidx = iy*w + ix; dblSum += pu8[oidx]; ++numPixels; } ox += odx; oy += ody; } ax += adx; ay += ady; if(fNormalize && (numPixels>0)) rgProf[aa] = dblSum / numPixels; else rgProf[aa] = dblSum; } } } break; default: fprintf(stderr, "Not yet implemented!\n"); abort(); }//end switch(img.getImageType()) }