Example #1
0
int camDrawTextBitmap(CamImage *image, char *text, int x, int y, CamBitmapFont *font)
{
    CamImage imx=*image;
    CamROI roi;
    char *s=text;
    int n;

    CAM_CHECK_ARGS(camDrawTextBitmapFont,image->imageData!=NULL);
    CAM_CHECK_ARGS(camDrawTextBitmapFont,image->nChannels>=3);

    roi.coi=0;
    imx.roi=&roi;
    for (;*s;s++) {
        n=*s-font->first_char;
        if (n>=0) {
            if (n>=font->nb_chars) {
                n-='a'-'A';
            }
            if ((n>=0)&&(n<font->nb_chars)) {
                roi.xOffset=x;
                roi.yOffset=y;
                roi.width=font->letters[n].width;
                roi.height=font->letters[n].height;
                camCopy(&font->letters[n],&imx);
                x+=font->letters[n].width;
            }
        } else x+=font->height/2;
    }
    return 0;
}
// Binary images processing
// camMonadicArithm1U : source is n bits, dest is one bit
int camMonadicArithm1U(CamImage *source, CamImage *dest, CamArithmParams *params)
{
    int x,y;
    int width,height;
    CAM_PIXEL *srcptr,*cpsrcptr;
    CAM_BIT_BLOCK *dstptr,*cpdstptr;
    CAM_BIT_BLOCK bit_block,eol_block;
    int sol_offset,bit_offset;

    int c1=params->c1;
    int c2=params->c2;
    int c3=params->c3;

    CamInternalROIPolicyStruct iROI;

    CAM_CHECK_ARGS(camMonadicArithm,(source->depth&CAM_DEPTH_MASK)<=(sizeof(CAM_PIXEL)*8));
    CAM_CHECK_ARGS(camMonadicArithm,(source->depth&CAM_DEPTH_MASK)>=8);

    // ROI (Region Of Interest) management
    CAM_CHECK(camMonadicArithm,camInternalROIPolicy(source, dest, &iROI, 0));
    srcptr=(CAM_PIXEL*)iROI.srcptr;
    width=iROI.srcroi.width;
    height=iROI.srcroi.height;

    if (dest->roi) {
	sol_offset=dest->roi->xOffset%CAM_BIT_BLOCK_SIZE;
	dstptr=(CAM_BIT_BLOCK*)(dest->imageData+dest->roi->yOffset*dest->widthStep)+(dest->roi->xOffset/CAM_BIT_BLOCK_SIZE);
    } else {
	sol_offset=0;
	dstptr=(CAM_BIT_BLOCK*)dest->imageData;
    }

    switch(params->operation) {
    case CAM_ARITHM_ABS:
	camError("camMonadicArithm","CAM_ARITHM_ABS operation is not possible on binary images");
	break;
    case CAM_ARITHM_SELECT:
	if (c2) {
	    FOREACH_PIXEL {
		STORE_BIT((int)(*srcptr==c1));	    
	    } END_FOREACH_PIXEL
	} else {
	    FOREACH_PIXEL {
		STORE_BIT((int)(*srcptr!=c1));	    
	    } END_FOREACH_PIXEL
	}
	break;
    case CAM_ARITHM_THRESHOLD:
	if (c2) {
	    FOREACH_PIXEL {
		STORE_BIT((int)(*srcptr<c1));
	    } END_FOREACH_PIXEL
	} else {
Example #3
0
int camYUV2RGB(CamImage* source, CamImage *dest)
{
    unsigned char *srcptr,*dstptr;
    int x,y;
    int y1,u,v; 
    int c1,c2,c3,c4;
    int width, height;
    CamInternalROIPolicyStruct iROI;
    DECLARE_MASK_MANAGEMENT;  

    CAM_CHECK_ARGS2(camYUV2RGB,source->imageData!=NULL,"source image is not allocated");
    if (dest->imageData==NULL) {
        // Automatic allocation
        camAllocateRGBImage(dest,source->width,source->height);
    }
    CAM_CHECK(camYUV2RGB,camInternalROIPolicy(source, dest, &iROI, CAM_MASK_SUPPORT | CAM_IGNORE_COI_MISMATCH));
    CAM_CHECK_ARGS(camYUV2RGB,source->nChannels==3);
    CAM_CHECK_ARGS(camYUV2RGB,dest->nChannels==3);
    CAM_CHECK_ARGS(camYUV2RGB,dest->dataOrder==CAM_DATA_ORDER_PIXEL);
    CAM_CHECK_ARGS(camYUV2RGB,source->depth==CAM_DEPTH_8U);
    CAM_CHECK_ARGS(camYUV2RGB,dest->depth==CAM_DEPTH_8U);
    CAM_CHECK_ARGS(camYUV2RGB,(*((int*)source->colorModel)==*((int*)"YUV")));
    CAM_CHECK_ARGS(camYUV2RGB,(*((int*)dest->colorModel)==*((int*)"RGB")));
    CAM_CHECK_ARGS(camYUV2RGB,(*((int*)dest->channelSeq)==*((int*)"RGB")));
   
    width=iROI.srcroi.width;
    height=iROI.srcroi.height;
    INIT_MASK_MANAGEMENT;

    // Initialize tables if need be
    if (LUTYUV2RGB[0]==-1) camInitLUTYUV2RGB();
    
    if (source->dataOrder==CAM_DATA_ORDER_PIXEL) {
        for (y = 0; y < height; y ++) { 
            srcptr=(unsigned char*)(iROI.srcptr+y*source->widthStep);
            dstptr=(unsigned char*)(iROI.dstptr+y*dest->widthStep);
            BEGIN_MASK_MANAGEMENT(
		srcptr+=startx*3;
		dstptr+=startx*3;
	    )                                        

            for (x=startx;x<endx;x++) {
                
                y1 = to76309[*srcptr++];	
                u = *srcptr++;
                v = *srcptr++;
                
                c1 = LUTYUV2RGB[v];
                c2 = GU[u];
                c3 = GV[v];
                c4 = BU[u];
                
                *dstptr++ = clip[384+((y1 + c1)>>16)];  
                *dstptr++ = clip[384+((y1 - c2 - c3)>>16)];
                *dstptr++ = clip[384+((y1 + c4)>>16)];
            }
	    END_MASK_MANAGEMENT;
        }
    } else {
int camKeypointsMatchingKdTree(CamKeypoints *target, CamFPKdTreeNode *kdTreeRoot, CamKeypointsMatches *matches, int explore)
{
    int i, c, model, best, nbModels = 0;
    int bestDistance, secondBestDistance;
    CamKeypoint *point, *bestMatch;
    int results[MAX_NB_MODELS], best4Target[2048];

    CAM_CHECK_ARGS(camKeypointsMatchingKdTree, target->nbPoints <= 2048);
    CAM_CHECK_ARGS(camKeypointsMatchingKdTree, matches->allocated != 0);

    for (model = 0; model < MAX_NB_MODELS; model++) results[model] = 0;
    matches->nbMatches = 0;
    matches->nbOutliers = 0;

    for (c = 0; c < target->nbPoints; c++) {
	point = target->keypoint[c];
	bestMatch = camFindKeypointKdTree(point, kdTreeRoot, explore, &bestDistance, &secondBestDistance);
	//printf("%d %d %d\n", bestMatch->set->id, bestDistance, secondBestDistance);
	// Final test...
	if (secondBestDistance == -1 || bestDistance < 0.8 * secondBestDistance) {
	    if (bestMatch->set->id >= 0 && bestMatch->set->id < MAX_NB_MODELS) {
		results[bestMatch->set->id]++;
		if (bestMatch->set->id + 1 > nbModels) nbModels = bestMatch->set->id + 1;
	    }
    	    matches->pairs[matches->nbMatches].p1 = bestMatch;
    	    matches->pairs[matches->nbMatches].p2 = point;
    	    matches->pairs[matches->nbMatches].mark = bestDistance;
	    best4Target[matches->nbMatches] = bestMatch->set->id;
	    matches->nbMatches++;
	    if (matches->nbMatches == matches->allocated) break;
	}
    }

    best = 0;
    for (i = 1; i < nbModels; i++) {
	if (results[i] > results[best]) best = i;
    }

    c = 0;
    for (i = 0; i < matches->nbMatches; i++) {
	if (best4Target[i] == best) {
	    matches->pairs[c++] = matches->pairs[i];
	}
    }
    matches->nbMatches = results[best];
    return best;
}
int camKeypointsMatching(CamKeypoints *target, CamKeypoints **models, int nbM, CamKeypointsMatches *matches)
{
    int i, c, model, best, nbModels = 0;
    int distance, bestDistance, secondBestDistance, bestModel, secondBestModel;
    CamKeypoint *point, *bestMatch;
#define MAX_NB_MODELS 256
    int results[MAX_NB_MODELS], best4Target[2048];

    CAM_CHECK_ARGS(camKeypointsMatching, nbModels <= MAX_NB_MODELS);
    CAM_CHECK_ARGS(camKeypointsMatching, target->nbPoints <= 2048);
    CAM_CHECK_ARGS(camKeypointsMatching, matches->allocated != 0);

    for (model = 0; model < MAX_NB_MODELS; model++) results[model] = 0;
    matches->nbMatches = 0;
    matches->nbOutliers = 0;

    for (c = 0; c < target->nbPoints; c++) {
	point = target->keypoint[c];
	bestDistance = -1; bestModel = 0;

	for (model = 0; model < nbM; model++) {
	    for (i = 0; i < models[model]->nbPoints; i++) {
		distance = camKeypointsDistance(models[model]->keypoint[i], point);
		if (bestDistance == -1 || distance <= bestDistance) {
		    bestMatch = models[model]->keypoint[i];
		    secondBestDistance = bestDistance;
		    secondBestModel = bestModel;
		    bestDistance = distance;
		    bestModel = model;
		} else if (secondBestDistance == -1 || distance <= secondBestDistance) {
		    secondBestDistance = distance;
		    secondBestModel = model;
		}
	    }
	}

	//printf("%d %d %d\n", bestMatch->set->id, bestDistance, secondBestDistance);

	/*
	if (models[bestModel]->id == models[secondBestModel]->id) {
	    // Accept the point whatever it is
	    secondBestDistance = 2 * bestDistance;
	}
	*/

	/*
	    secondBestDistance = -1; secondBestModel = 0;

	    // We have to scan again for the second best
	    for (model = 0; model < nbM; model++) {
		if (models[model]->id == models[bestModel]->id) continue; // Skip the best model
		for (i = 0; i < models[model]->nbPoints; i++) {
		    distance = camKeypointsDistance(models[model]->keypoint[i], point);
		    if (secondBestDistance == -1 || distance <= secondBestDistance) {
			secondBestDistance = distance;
			secondBestModel = model;
		    }
		}
	    }
	}
	*/

	// Final test...
	if (bestDistance < 0.8 * secondBestDistance) {
	    if (bestMatch->set->id >= 0 && bestMatch->set->id < MAX_NB_MODELS) {
		results[bestMatch->set->id]++;
		if (bestMatch->set->id + 1 > nbModels) nbModels = bestMatch->set->id + 1;
	    }
    	    matches->pairs[matches->nbMatches].p1 = bestMatch;
    	    matches->pairs[matches->nbMatches].p2 = point;
    	    matches->pairs[matches->nbMatches].mark = bestDistance;
	    best4Target[matches->nbMatches] = bestMatch->set->id;
	    matches->nbMatches++;
	    if (matches->nbMatches == matches->allocated) break;
	}
    }

    best = 0;
    for (i = 1; i < nbModels; i++) {
	if (results[i] > results[best]) best = i;
    }

    c = 0;
    for (i = 0; i < matches->nbMatches; i++) {
	if (best4Target[i] == best) {
	    matches->pairs[c++] = matches->pairs[i];
	}
    }
    matches->nbMatches = results[best];
    return best;
}
Example #6
0
int camCopy(CamImage* source, CamImage* dest)
{
    int x,y,i,n,c,special=0;
    int width,height;
    CAM_PIXEL *srcptr,*cpsrcptr;
    CAM_PIXEL_DST *dstptr,*cpdstptr;
    CamROI roi,roi2,*tmp,*tmp2;
#ifdef CAM_SATURATE
    int valpix;
    int valmin=0, valmax=255;
#endif

    CamRun *run;
    int startx,endx;
    CamInternalROIPolicyStruct iROI;

    if (dest->imageData) {
        // Special cases : 
        // Grey to color conversion : source is one channel, and dest is several channels (3 or 4)
        if (((source->nChannels==1)||((source->roi)&&(source->roi->coi)))
            &&(dest->nChannels!=1)&&((dest->roi==NULL)||(dest->roi->coi==0))) special=1;
        // 3 to 4 channels conversion : RGB->RGBA. Adding an alpha channel
        else if ((source->nChannels==3)&&(dest->nChannels==4)&&
            ((source->roi==NULL)||(source->roi->coi==0))&&
            ((dest->roi==NULL)||(dest->roi->coi==0))) special=2;
        // 4 to 3 channels conversion : RGBA -> RGB. Removing an alpha channel
        else if ((source->nChannels==4)&&(dest->nChannels==3)&&
            ((source->roi==NULL)||(source->roi->coi==0))&&
            ((dest->roi==NULL)||(dest->roi->coi==0))) special=2;
    }
    if (special) {
        tmp=dest->roi;
        if (dest->roi) {
            roi=*tmp;
        } else {
            camSetMaxROI(&roi,dest);
        }
        dest->roi=&roi;
        roi.coi=1;
        n=dest->nChannels;
        if (n==4) n=3; // Doesn't copy to the alpha channel
        if (special==2) {
            tmp2=source->roi;
            if (source->roi) {
                roi2=*tmp2;
            } else {
                camSetMaxROI(&roi2,source);
            }
            source->roi=&roi2;
            roi2.coi=1;
        }
    } else n=1;

    for (c=0;c<n;c++) {
        
        // ROI (Region Of Interest) management
        CAM_CHECK(camCopy,camInternalROIPolicy(source, dest, &iROI, 1));
        CAM_CHECK_ARGS(camCopy,(source->depth&CAM_DEPTH_MASK)<=(sizeof(CAM_PIXEL)*8));
        CAM_CHECK_ARGS(camCopy,(source->depth&CAM_DEPTH_MASK)>=8);
        CAM_CHECK_ARGS(camCopy,(dest->depth&CAM_DEPTH_MASK)<=(sizeof(CAM_PIXEL_DST)*8));
        CAM_CHECK_ARGS(camCopy,(dest->depth&CAM_DEPTH_MASK)>=8);
        CAM_CHECK_ARGS(camCopy,(source->depth&CAM_DEPTH_SIGN)==(dest->depth&CAM_DEPTH_SIGN));
        
        width=iROI.srcroi.width;
        height=iROI.srcroi.height;
        srcptr=(CAM_PIXEL*)iROI.srcptr;
        dstptr=(CAM_PIXEL_DST*)iROI.dstptr;
        
        INIT_MASK_MANAGEMENT;

        if (source->dataOrder==CAM_DATA_ORDER_PIXEL) {
            if (dest->dataOrder==CAM_DATA_ORDER_PIXEL) {
                for (y=0;y<height;y++) {
                    cpsrcptr=srcptr; cpdstptr=dstptr;
                    BEGIN_MASK_MANAGEMENT( \
                        srcptr=cpsrcptr+startx*iROI.srcinc;\
                        dstptr=cpdstptr+startx*iROI.dstinc;\
                    )
                        
#if CAM_FAST==8
                        if ((iROI.srcinc==iROI.dstinc)&&(iROI.srcinc==iROI.nChannels)) {
                            memcpy(dstptr,srcptr,(endx-startx)*iROI.nChannels);
                        } else
#else
#if CAM_FAST==16
                        if ((iROI.srcinc==iROI.dstinc)&&(iROI.srcinc==iROI.nChannels)) {
                            memcpy(dstptr,srcptr,((endx-startx)*iROI.nChannels)<<1);
                        } else
#endif
#endif
                        {
                            for (x=startx;x<endx;x++) {
                                for (i=0;i<iROI.nChannels;i++) {
#ifdef CAM_SATURATE
                                    valpix=*(srcptr+i);
                                    if (valpix<valmin) valpix=valmin;
                                    else if (valpix>valmax) valpix=valmax;
                                    *(dstptr+i)=valpix;
#else
                                    *(dstptr+i)=(CAM_PIXEL_DST)*(srcptr+i);
#endif
                                }
                                srcptr+=iROI.srcinc;
                                dstptr+=iROI.dstinc;
                        }   }
                        
                    END_MASK_MANAGEMENT;

                    srcptr=(CAM_PIXEL*)(((char*)cpsrcptr)+source->widthStep);
                    dstptr=(CAM_PIXEL_DST*)(((char*)cpdstptr)+dest->widthStep);
                }
            } else {
                for (y=0;y<height;y++) {
                    cpsrcptr=srcptr; cpdstptr=dstptr;
                    BEGIN_MASK_MANAGEMENT( \
                            srcptr=cpsrcptr+startx*iROI.srcinc;\
                            dstptr=cpdstptr+startx; )
                        
                        for (x=startx;x<endx;x++) {
                            for (i=0;i<iROI.nChannels;i++) {
#ifdef CAM_SATURATE
                                valpix=*(srcptr+i);
                                if (valpix<valmin) valpix=valmin;
                                else if (valpix>valmax) valpix=valmax;
                                *(dstptr+i*iROI.dstpinc)=valpix;
#else
                                *(dstptr+i*iROI.dstpinc)=(CAM_PIXEL_DST)*(srcptr+i);
#endif
                            }
                            srcptr+=iROI.srcinc;
                            dstptr++;
                        }
                        
                    END_MASK_MANAGEMENT;
                    
                    srcptr=(CAM_PIXEL*)(((char*)cpsrcptr)+source->widthStep);
                    dstptr=(CAM_PIXEL_DST*)(((char*)cpdstptr)+dest->widthStep);
                }
            }
Example #7
0
// This function is buggy, since it doesn't fully implement a super sampling
// Still being worked on...
int camWarpingSuperSampling(CamImage *source, CamImage *dest, CamWarpingParams *params)
{
    int x,y,width,height;
    int xl,yl,xr,yr; // Position on the left and right side (source image)
    int incxl,incyl,incxr,incyr; // Increment on the left and right sides (source image)
    int dxl,dyl,dxr,dyr; // Delta for the left and right sides
    int xp,yp; // Position of the current point
    int xpp,ypp; // Position of the previous point
    int incxp,incyp; // Increment for the current point 
    int xpl[CAM_MAX_SCANLINE+1],ypl[CAM_MAX_SCANLINE+1]; // (x,y) points for the previous scanline
    CAM_PIXEL scanline[CAM_MAX_SCANLINE+1],valpix1,valpixp;
    CAM_PIXEL *dstptr,*srcptr1,*cpdstptr;
    int xptr1,yptr1=0xdead; // Special value. Generally inaccessible.
    int result,xx,yy;
    int perspective=params->perspective;
    int zul,zbl,zur,zbr,cl,cr,zl,zr; // Projection parameters
    int w1,w2,w3,w4,sum; // Weights for linear "square" interpolation
    CamPoint I;
    
    CAM_CHECK_ARGS(camWarpingSuperSampling,source->nChannels==1);
    CAM_CHECK_ARGS(camWarpingSuperSampling,dest->nChannels==1);
    CAM_CHECK_ARGS(camWarpingSuperSampling,(source->depth&CAM_DEPTH_MASK)<=(sizeof(CAM_PIXEL)*8));
    CAM_CHECK_ARGS(camWarpingSuperSampling,(source->depth&CAM_DEPTH_MASK)>=8);
    CAM_CHECK_ARGS(camWarpingSuperSampling,(dest->depth&CAM_DEPTH_MASK)<=(sizeof(CAM_PIXEL)*8));
    CAM_CHECK_ARGS(camWarpingSuperSampling,(dest->depth&CAM_DEPTH_MASK)>=8);

    // ROI (Region Of Interest) management
    if (dest->roi) {
	dstptr=(CAM_PIXEL*)(dest->imageData+dest->roi->yOffset*dest->widthStep+dest->roi->xOffset*sizeof(CAM_PIXEL));
	width=dest->roi->width;
	height=dest->roi->height;
    } else {
	dstptr=(CAM_PIXEL*)dest->imageData;
	width=dest->width;
	height=dest->height;
    }
    
    xl=params->p[0].x;
    yl=params->p[0].y;
    xr=params->p[1].x;
    yr=params->p[1].y;
    
    dxl=params->p[3].x-xl;
    dyl=params->p[3].y-yl;
    dxr=params->p[2].x-xr;
    dyr=params->p[2].y-yr;
    
    // perspective warping or not?
    if (perspective) {
	if (!camIntersectionSegments(params->p,&I)) {
	    perspective=0;
	} else {
	    // 32 bits fixed point
	    zul=(int)((((CAM_INT64)1)<<48)/(params->p[0].y-I.y));
	    zur=(int)((((CAM_INT64)1)<<48)/(params->p[1].y-I.y));
	    zbl=(int)((((CAM_INT64)1)<<48)/(params->p[3].y-I.y));
	    zbr=(int)((((CAM_INT64)1)<<48)/(params->p[2].y-I.y));
	    cl=(zul-zbl)/height; // 32 bits fixed point
	    cr=(zur-zbr)/height; // Should be positive valued
	}
    }
    if (!perspective) {
	incxl=dxl/height;
	incyl=dyl/height;
	incxr=dxr/height;
	incyr=dyr/height;
    } else {
	incxl=(int)((((CAM_INT64)dxl)<<16)/dyl);
	incxr=(int)((((CAM_INT64)dxr)<<16)/dyr);
    }

    // First scan-line
    // Let's go across each horizontal pixel
    xp=xl; yp=yl;
    incxp=(xr-xl)/width;
    incyp=(yr-yl)/width;
    for (x=0;x<=width;x++,xp+=incxp,yp+=incyp) {
	xpl[x]=xp;
	ypl[x]=yp;		
	// Let's retrieve the pixel at that position in the source image
	xx=xp>>16;
	yy=yp>>16;
	GET_PIXEL(xx,yy,1);
	scanline[x]=valpix1;
    }
    
    // For all destination pixels
    // Let's go across all the lines
    for (y=0;y<height;y++) {
	if (perspective) {
	    zl=zul-(int)(((CAM_INT64)y)*cl); // 32 bits fixed points
	    zr=zur-(int)(((CAM_INT64)y)*cr);
	    yl=I.y+(int)((((CAM_INT64)1)<<48)/zl);
	    yr=I.y+(int)((((CAM_INT64)1)<<48)/zr);
	    xl=params->p[0].x+(int)(((CAM_INT64)incxl)*(yl-params->p[0].y)>>16);
	    xr=params->p[1].x+(int)(((CAM_INT64)incxr)*(yr-params->p[1].y)>>16);
	} else {
	    // Go to the next line
	    xl+=incxl;
	    xr+=incxr;
	    yl+=incyl;
	    yr+=incyr;
	}
	cpdstptr=dstptr;
	xp=xl; yp=yl;
	incxp=(xr-xl)/width;
	incyp=(yr-yl)/width;
	// Let's retrieve the value of the first pixel in the source image
	xx=xp>>16;
	yy=yp>>16;
	GET_PIXEL(xx,yy,1);
	// And then across each horizontal pixel
	for (x=0;x<width;x++,dstptr++) {
	    // Manage the positions of pixels
	    xpp=xp;
	    ypp=yp;
	    xp+=incxp;
	    yp+=incyp;
	    // Manage the values of pixels
	    valpixp=valpix1;
	    // Let's retrieve the value of the current pixel in the source image
	    xx=xp>>16;
	    yy=yp>>16;
	    GET_PIXEL(xx,yy,1);
	    // OK. Now we do have our four source points
	    // These are pl[x], pl[x+1], pp and p
	    // (pl = previous line, pp = previous point, p = actual point)
	    // ((x,y) access trough xpl and ypl variables for pl)
	    // Their pixel values are respectively
	    // scanline[x], scanline[x+1], valpixp and valpix1
	    
	    // We can compute the interpolation between them
	    switch (params->interpolation) {
	    case 1: // linear "square" interpolation (slow but nice for resampling)
		w1=((0xffff-(xpl[x]&0xffff))>>8)*((0xffff-(ypl[x]&0xffff))>>8);
		w2=((xpl[x+1]&0xffff)>>8)*((0xffff-(ypl[x+1]&0xffff))>>8);
		w3=((0xffff-(xpp&0xffff))>>8)*((ypp&0xffff)>>8);
		w4=((xp&0xffff)>>8)*((yp&0xffff)>>8);
		sum=w1+w2+w3+w4;
		if (sum) {
    		    result=(((int)scanline[x])*w1+
			((int)scanline[x+1])*w2+
			((int)valpixp)*w3+
			((int)valpix1)*w4)/(w1+w2+w3+w4);
			break;
		}
	    case 0: // Very crude (but fast) interpolation scheme
	    default:
		result=((int)scanline[x]+
			(int)scanline[x+1]+
			(int)valpixp+
			(int)valpix1)>>2;
		break;
	    }
	    // Write the result to the destination image
	    *dstptr=(CAM_PIXEL)result;
	    
	    // Go to the next point
	    // Copy to pl (previous line) in order to prepare for the next horizontal scan
	    xpl[x]=xpp;
	    ypl[x]=ypp; 		
	    // And copy the value of the previous pixel into the scanline buffer
	    scanline[x]=valpixp;
	}
	// Copy to pl (previous line) to prepare for the next horizontal scan	
	xpl[x]=xp;
	ypl[x]=yp;
	// And copy the value of the last pixel into the scanline buffer
	scanline[x]=valpix1;
	
	// Move the destination pointer
	dstptr=(CAM_PIXEL*)(((char*)cpdstptr)+dest->widthStep);
    }
int camDilateCircle7(CamImage *source, CamImage *dest)
#endif // CAM_MM_DO_EROSION
#endif // CAM_MM_GRADIENT
#endif // CAM_MM_FINDLOCALMAXIMA
#endif // CAM_MM_OPT_CIRCLE7
{
    int i,x,y,ntb,nlb;
    int width,height;
    int top,left;
    int firsttime;
    int acc=0;

    CamInternalROIPolicyStruct iROI;
    
#ifdef CAM_MM_DO_EROSION
    int tabero[9];
    int valero[2];
#endif // CAM_MM_DO_EROSION

#ifdef CAM_MM_DO_DILATION
    int tabdil[9];
    int valdil[2];
#endif // CAM_MM_DO_DILATION

    CAM_PIXEL *srcptr,*dstptr,*tmpptr,*cpsrcptr,*cpdstptr;
    unsigned CAM_PIXEL *linesPtr[CAM_MM_NEIGHB];
    CAM_PIXEL linesBuffer[CAM_MM_NEIGHB][CAM_MAX_SCANLINE+CAM_MM_NEIGHB-1];

    DECLARE_MASK_MANAGEMENT;

#ifdef CAM_MM_FINDLOCALMAXIMA
    int valcenter, xp, yp, zp, found;
#ifdef CAM_MM_OPT_CIRCLE7
    const int lines2test = 5;
    const int start2test[] = {2, 1, 0, 0, 0};
    const int end2test[] = {4, 5, 4, 2, 1};
#else
#ifdef CAM_MM_OPT_CIRCLE5
    const int lines2test = 4;
    const int start2test[] = {1, 0, 0, 0};
    const int end2test[] = {3, 3, 1, 0};
#else
    const int lines2test = 2;
    const int start2test[] = {0, 0};
    const int end2test[] = {2, 0};
#endif // CAM_MM_OPT_CIRCLE5
#endif // CAM_MM_OPT_CIRCLE7

    // ROI (Region Of Interest) management
    CAM_CHECK(camFindLocalMaxima, camInternalROIPolicy(source, NULL, &iROI, 1));
    CAM_CHECK_ARGS(camFindLocalMaxima, iROI.nChannels==1);
    CAM_CHECK_ARGS2(camFindLocalMaxima, points != NULL, "points destination parameter should not be set to NULL");
#else
    CamMorphoMathsKernel params;
    CAM_CHECK(camMorphoMathsKernel,camInternalROIPolicy(source, dest, &iROI, 1));
    CAM_CHECK_ARGS(camMorphoMathsKernel,(source->depth==dest->depth));
    CAM_CHECK_ARGS(camMorphoMathsKernel,iROI.nChannels==1);

    if (source->depth == CAM_DEPTH_1U) {
	// Binary processing
#ifdef CAM_MM_DO_EROSION
#ifdef CAM_MM_OPT_SQUARE3
	for (y=0;y<3;y++) {
	    for (x=0;x<3;x++) {
		params.erosionStructElt[y][x]=1;
	    }
	}
	return camErode3x3(source,dest,&params);
#endif
#ifdef CAM_MM_OPT_CIRCLE5
	for (y=0;y<5;y++) {
	    for (x=0;x<5;x++) {
		params.erosionStructElt[y][x]=1;
	    }
	}
	params.erosionStructElt[0][0]=0;
	params.erosionStructElt[0][4]=0;
	params.erosionStructElt[4][0]=0;
	params.erosionStructElt[4][4]=0;
	return camErode5x5(source,dest,&params);
#endif
#ifdef CAM_MM_OPT_CIRCLE7
	for (y=0;y<7;y++) {
	    for (x=0;x<7;x++) {
		params.erosionStructElt[y][x]=camCircle7StructElt[y][x];
	    }
	}
	return camErode7x7(source,dest,&params);
#endif
#else
#ifdef CAM_MM_OPT_SQUARE3
	for (y=0;y<3;y++) {
	    for (x=0;x<3;x++) {
		params.dilationStructElt[y][x]=1;
	    }
	}
	return camDilate3x3(source,dest,&params);
#endif
#ifdef CAM_MM_OPT_CIRCLE5
	for (y=0;y<5;y++) {
	    for (x=0;x<5;x++) {
		params.dilationStructElt[y][x]=1;
	    }
	}
	params.dilationStructElt[0][0]=0;
	params.dilationStructElt[0][4]=0;
	params.dilationStructElt[4][0]=0;
	params.dilationStructElt[4][4]=0;
	return camDilate5x5(source,dest,&params);
#endif
#ifdef CAM_MM_OPT_CIRCLE7
	for (y=0;y<7;y++) {
	    for (x=0;x<7;x++) {
		params.dilationStructElt[y][x]=camCircle7StructElt[y][x];
	    }
	}
	return camDilate7x7(source,dest,&params);
#endif
#endif // CAM_MM_DO_EROSION
    }
#endif // CAM_MM_FINDLOCALMAXIMA

    CAM_CHECK_ARGS(camMorphoMathsKernel,(source->depth&CAM_DEPTH_MASK)<=(sizeof(CAM_PIXEL)*8));
    CAM_CHECK_ARGS(camMorphoMathsKernel,(source->depth&CAM_DEPTH_MASK)>=8);
#ifndef CAM_MM_FINDLOCALMAXIMA
    CAM_CHECK_ARGS(camMorphoMathsKernel,(dest->depth&CAM_DEPTH_MASK)<=(sizeof(CAM_PIXEL)*8));
    CAM_CHECK_ARGS(camMorphoMathsKernel,(dest->depth&CAM_DEPTH_MASK)>=8);
#endif

    width=iROI.srcroi.width;
    height=iROI.srcroi.height;
    if (source->roi) {
        left=iROI.srcroi.xOffset;
        top=iROI.srcroi.yOffset;
        nlb=left; if (nlb>CAM_MM_NEIGHB/2) nlb=CAM_MM_NEIGHB/2;
	ntb=top; if (ntb>CAM_MM_NEIGHB/2) ntb=CAM_MM_NEIGHB/2;
        srcptr=(CAM_PIXEL*)(source->imageData+iROI.srcchoffset+(top-ntb)*source->widthStep)+(left-nlb);
    } else {
        srcptr=(CAM_PIXEL*)(source->imageData+iROI.srcchoffset);
        left=0;
        top=0;
    }
    dstptr=(CAM_PIXEL*)iROI.dstptr;
    CAM_CHECK_ARGS(camMorphoMathsKernel,(width>CAM_MM_NEIGHB/2));
    CAM_CHECK_ARGS(camMorphoMathsKernel,(height>CAM_MM_NEIGHB/2));    
	
    // Mask management
    INIT_MASK_MANAGEMENT;

    // Initialize algorithm
    for (i=0;i<CAM_MM_NEIGHB;i++) {
	linesPtr[i]=linesBuffer[i];
    }
    
    // Initialize neighbourhood
    
    // Fill the top lines
    for (y=0;y+top<CAM_MM_NEIGHB/2;y++) {
        // Out of frame : fill with border color
        if (source->borderMode[CAM_SIDE_TOP_INDEX]==CAM_BORDER_REPLICATE) {
            cpsrcptr=srcptr;
            for (x=0;x<CAM_MM_NEIGHB/2;x++) {
                linesPtr[y][x]=*srcptr;
            }
            for (;x<width+CAM_MM_NEIGHB/2;x++) {
                linesPtr[y][x]=*srcptr;
                srcptr+=iROI.srcinc;
            }
            for (;x<width+CAM_MM_NEIGHB-1;x++) {
                linesPtr[y][x]=*(srcptr-iROI.srcinc);
            }
            srcptr=cpsrcptr;
        } else {
            for (x=0;x<width+CAM_MM_NEIGHB-1;x++) {
                linesPtr[y][x]=source->borderConst[CAM_SIDE_TOP_INDEX];
            }
        }
    }
    
    // Fill the next lines with image pixels
    for (;y<CAM_MM_NEIGHB-1;y++) {
        cpsrcptr=srcptr;
        for (x=0;x<CAM_MM_NEIGHB/2;x++) {
            if (left+x-CAM_MM_NEIGHB/2<0) {
                // Out of frame : fill with border color
                if (source->borderMode[CAM_SIDE_LEFT_INDEX]==CAM_BORDER_REPLICATE) {
                    linesPtr[y][x]=*srcptr;
                } else {
                    linesPtr[y][x]=source->borderConst[CAM_SIDE_LEFT_INDEX];
                }
            } else {
                // Get border pixels from the source frame
                linesPtr[y][x]=*srcptr;
                srcptr+=iROI.srcinc;
            }
        }
        for (;x<width+CAM_MM_NEIGHB/2;x++) {
            linesPtr[y][x]=*srcptr;
            srcptr+=iROI.srcinc;
        }
        for (;x<width+CAM_MM_NEIGHB-1;x++) {
            if (left+x-CAM_MM_NEIGHB/2<source->width) {
                // Get border pixels from the source frame
                linesPtr[y][x]=*srcptr;
                srcptr+=iROI.srcinc;
            } else {
                // Out of frame : fill with border color
                if (source->borderMode[CAM_SIDE_RIGHT_INDEX]==CAM_BORDER_REPLICATE) {
                    linesPtr[y][x]=*(srcptr-iROI.srcinc);
                } else {
                    linesPtr[y][x]=source->borderConst[CAM_SIDE_RIGHT_INDEX];
                }
            }
        }
        srcptr=(CAM_PIXEL*)(((char*)cpsrcptr)+source->widthStep);
    }

    // Now process the whole image
    // This is the main loop
    for (y=0;y<height;y++) {
	firsttime=1;

	cpsrcptr=srcptr;
        cpdstptr=dstptr;

        // Start a new line
        // Have we reached the bottom of the frame ?
        if (top+y+CAM_MM_NEIGHB/2>=source->height) {
            if (source->borderMode[CAM_SIDE_BOTTOM_INDEX]==CAM_BORDER_REPLICATE) {
                // Go up one line (in order to stay on the last line)
                cpsrcptr=(CAM_PIXEL*)(((char*)cpsrcptr)-source->widthStep);
                srcptr=cpsrcptr;
                for (x=0;x<CAM_MM_NEIGHB/2;x++) {
                    linesPtr[CAM_MM_NEIGHB-1][x]=*srcptr;
                }
                for (;x<width+CAM_MM_NEIGHB/2;x++) {
                    linesPtr[CAM_MM_NEIGHB-1][x]=*srcptr;
                    srcptr+=iROI.srcinc;
                }
                for (;x<width+CAM_MM_NEIGHB-1;x++) {
                    linesPtr[CAM_MM_NEIGHB-1][x]=*(srcptr-iROI.srcinc);
                }
            } else {
                for (x=0;x<width+CAM_MM_NEIGHB-1;x++) {
                    linesPtr[CAM_MM_NEIGHB-1][x]=source->borderConst[CAM_SIDE_BOTTOM_INDEX];
                }
            }
        } else {
            for (x=0;x<CAM_MM_NEIGHB/2;x++) {
                if (left+x-CAM_MM_NEIGHB/2<0) {
                    // Out of frame : fill with border color
                    if (source->borderMode[CAM_SIDE_LEFT_INDEX]==CAM_BORDER_REPLICATE) {
                        linesPtr[CAM_MM_NEIGHB-1][x]=*srcptr;
                    } else {
                        linesPtr[CAM_MM_NEIGHB-1][x]=source->borderConst[CAM_SIDE_LEFT_INDEX];
                    }
                } else {
                    // Get border pixels from the source frame
                    linesPtr[CAM_MM_NEIGHB-1][x]=*srcptr;
                    srcptr+=iROI.srcinc;
                }
            }

            // Fast transfer with memcpy
            if (iROI.srcinc==1) {
                memcpy(&linesPtr[CAM_MM_NEIGHB-1][x],srcptr,(source->width-left+CAM_MM_NEIGHB/2-x)<<(sizeof(CAM_PIXEL)-1));
                x=source->width-left+CAM_MM_NEIGHB/2;
            } else {
                for (;x<source->width-left+CAM_MM_NEIGHB/2;x++) {
                    // Get a pixel from the source frame
                    linesPtr[CAM_MM_NEIGHB-1][x]=*srcptr;
                    srcptr+=iROI.srcinc;
                }
            }
            for (;x<width+CAM_MM_NEIGHB-1;x++) {
                // Out of frame : fill with border color
                if (source->borderMode[CAM_SIDE_RIGHT_INDEX]==CAM_BORDER_REPLICATE) {
                    linesPtr[CAM_MM_NEIGHB-1][x]=*(srcptr+(source->width-1)*iROI.srcinc);
                } else {
                    linesPtr[CAM_MM_NEIGHB-1][x]=source->borderConst[CAM_SIDE_RIGHT_INDEX];
                }
            }
        }

	if (source->depth & CAM_DEPTH_SIGN) {
#define linesPtr ((signed CAM_PIXEL**) linesPtr)
	    BEGIN_MASK_MANAGEMENT(dstptr=cpdstptr+startx*iROI.dstinc;)

		// Process all the pixels in the line
		for (x=startx+CAM_MM_NEIGHB-1;x<endx+CAM_MM_NEIGHB-1;x++) {

#ifdef CAM_MM_DO_EROSION
		    {
#define tabX tabero
#define valX valero
#define XOP < 
#ifdef CAM_MM_OPT_CIRCLE7
#include "cam_morphomaths_code_circle7.c"
#else
#ifdef CAM_MM_OPT_CIRCLE5
#include "cam_morphomaths_code_circle5.c"
#else
#include "cam_morphomaths_code_square3.c"
#endif // CAM_MM_OPT_CIRCLE5
#endif // CAM_MM_OPT_CIRCLE7
#undef tabX
#undef valX
#undef XOP
		    }
#endif // CAM_MM_DO_EROSION

#ifdef CAM_MM_DO_DILATION
		    {
#define tabX tabdil
#define valX valdil
#define XOP > 
#ifdef CAM_MM_OPT_CIRCLE7
#include "cam_morphomaths_code_circle7.c"
#else
#ifdef CAM_MM_OPT_CIRCLE5
#include "cam_morphomaths_code_circle5.c"
#else
#include "cam_morphomaths_code_square3.c"
#endif // CAM_MM_OPT_CIRCLE5
#endif // CAM_MM_OPT_CIRCLE7
#undef tabX
#undef valX
#undef XOP
		    }
#endif // CAM_MM_DO_DILATION
		    firsttime=0;

#ifdef CAM_MM_FINDLOCALMAXIMA
		    valcenter = linesPtr[CAM_MM_NEIGHB / 2][x - CAM_MM_NEIGHB + 1 + CAM_MM_NEIGHB / 2];	
		    if (valdil[0] == valcenter && valcenter >= threshold && valcenter != 0) {
			// Check that it is the only point with this maximum (in the upper part)
			for (yp = 0, zp = 0, found = 0; yp < lines2test; yp++) {
			    for (xp = start2test[yp]; xp <= end2test[yp]; xp++) {
				if (linesPtr[yp][x - CAM_MM_NEIGHB + 1 + xp] == valcenter) {
				    found = 1;
				    break;
				}
			    }
			}
			if (!found) {
			    // Keep this point : this is a local maximum
			    if (points->nbPoints < points->allocated) {
				points->keypoint[points->nbPoints]->x = x - CAM_MM_NEIGHB + 1;
				points->keypoint[points->nbPoints]->y = y;
				points->keypoint[points->nbPoints]->scale = 0;
				points->keypoint[points->nbPoints]->angle = 0;
				points->keypoint[points->nbPoints]->value = valcenter;
				points->nbPoints++;
				acc += valdil[0];
			    } else {
				camInternalROIPolicyExit(&iROI);
				return 0;
			    }
			}
		    }
#else	
#ifdef CAM_MM_GRADIENT
		    acc+=(*dstptr=valdil[0]-valero[0]);
#else
#ifdef CAM_MM_DO_EROSION
		    acc+=(*dstptr=valero[0]);
#else
		    acc+=(*dstptr=valdil[0]);
#endif
#endif // CAM_MM_GRADIENT
		    dstptr+=iROI.dstinc;
#endif // CAM_MM_FINDLOCALMAXIMA
		}

	    END_MASK_MANAGEMENT;       
#undef linesPtr
	} else {
Example #9
0
int camFillColor(CamImage *image, int x, int y, int fillcolor, int tolerance)
{
    int first=0,last=0;
    int i,j,d,xp,yp;
    CAM_PIXEL *ptr,*ptrx;
    const int nx[4]={-1,0,+1,0},ny[4]={0,-1,0,+1};
    CAM_PIXEL pcolor[4],initcolor[4]; // 4 is the maximum number of channels
    CamInternalROIPolicyStruct iROI;
    int acc=1;

    int queuex[FIFO_SIZE];
    int queuey[FIFO_SIZE];

    // ROI (Region Of Interest) management
    CAM_CHECK(camFillColor,camInternalROIPolicy(image, NULL, &iROI, 0));
    
    CAM_CHECK_ARGS(camFillColor, ((iROI.nChannels==1)||(image->dataOrder==CAM_DATA_ORDER_PIXEL)));

    if ((x>=iROI.srcroi.xOffset)&&(y>=iROI.srcroi.yOffset)&&(x<iROI.srcroi.xOffset+iROI.srcroi.width)&&(y<iROI.srcroi.yOffset+iROI.srcroi.height)) {
        for (i=0;i<iROI.nChannels;i++) {
            pcolor[i]=(fillcolor>>(i*8))&0xff;	
        }
        ptr=ptrx=(CAM_PIXEL*)(image->imageData+iROI.srcchoffset+y*image->widthStep)+x*iROI.srcinc;
        if (tolerance>=0) {            
            for (i=0;i<iROI.nChannels;i++) {
                initcolor[i]=*ptrx++;	
            }
            FIFO_ADD(x,y);
            for (ptrx=ptr,i=0;i<iROI.nChannels;i++,ptrx++) {
                *ptrx=pcolor[i];
            }
            while (!FIFO_EMPTY()) {
                x=queuex[first];
                y=queuey[first];
                FIFO_NEXT();
                for (j=0;j<4;j++) {
                    xp=x+nx[j];
                    yp=y+ny[j];
                    if ((xp>=iROI.srcroi.xOffset)&&(yp>=iROI.srcroi.yOffset)&&(xp<iROI.srcroi.xOffset+iROI.srcroi.width)&&(yp<iROI.srcroi.yOffset+iROI.srcroi.height)) {
                        // Get the color at (xp,yp)
                        ptr=ptrx=(CAM_PIXEL*)(image->imageData+iROI.srcchoffset+yp*image->widthStep)+xp*iROI.srcinc;
                        // Is it the same color as the initial color?
                        // Compute distance between colors
                        d=0;
                        for (i=0;i<iROI.nChannels;i++,ptrx++) {
                            if (*ptrx>initcolor[i]) d+=*ptrx-initcolor[i];
                            else d+=initcolor[i]-*ptrx;
                        }
                        if (d<=tolerance) {
                            // Yes, then this pixel should be repainted and added to the queue
                            FIFO_ADD(xp,yp);
                            for (ptrx=ptr,i=0;i<iROI.nChannels;i++,ptrx++) {
                                *ptrx=pcolor[i];
                            }
                            acc++;
                        }	    
                    }
                }
            }
        } else {
            FIFO_ADD(x,y);
            for (ptrx=ptr,i=0;i<iROI.nChannels;i++,ptrx++) {
                *ptrx=pcolor[i];
            }
            while (!FIFO_EMPTY()) {
                x=queuex[first];
                y=queuey[first];
                FIFO_NEXT();
                for (j=0;j<4;j++) {
                    xp=x+nx[j];
                    yp=y+ny[j];
                    if ((xp>=iROI.srcroi.xOffset)&&(yp>=iROI.srcroi.yOffset)&&(xp<iROI.srcroi.xOffset+iROI.srcroi.width)&&(yp<iROI.srcroi.yOffset+iROI.srcroi.height)) {
                        // Get the color at (xp,yp)
                        ptr=ptrx=(CAM_PIXEL*)(image->imageData+iROI.srcchoffset+yp*image->widthStep)+xp*iROI.srcinc;
                        for (i=0;i<iROI.nChannels;i++,ptrx++) if (*ptrx!=pcolor[i]) break;
                        // Is it the same color as the fill color?
                        if (i!=iROI.nChannels) {
                            // Yes, then this pixel should be repainted and added to the queue
                            FIFO_ADD(xp,yp);
                            for (ptrx=ptr,i=0;i<iROI.nChannels;i++,ptrx++) {
                                *ptrx=pcolor[i];
                            }
                            acc++;
                        }	    
                    }
                }
            }
        }
    }

    return acc;
}
Example #10
0
int camDrawText16s(CamImage *image, char *text, int x, int y, int cwidth, int cheight, int orientation, int color)
{
    static const int characters_table[][16]={
        {1,1,1,1,1,1,1,1,0,0,1,0,0,0,1,0}, /* 0 */
        {1,0,0,0,1,1,0,0,0,1,0,0,0,1,0,0}, /* {0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0}, */
        {1,1,1,0,1,1,1,0,0,0,0,1,0,0,0,1},
        {1,1,1,1,1,1,0,0,0,0,0,1,0,0,0,0},
        {0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,1},
        {1,1,0,1,1,1,0,1,0,0,0,1,0,0,0,1},
        {1,1,0,1,1,1,1,1,0,0,0,1,0,0,0,1},
        {1,1,0,0,0,0,0,0,0,0,1,0,0,0,1,0},
        {1,1,1,1,1,1,1,1,0,0,0,1,0,0,0,1},
        {1,1,1,1,1,1,0,1,0,0,0,1,0,0,0,1}, /* 9 */
        {1,1,1,1,0,0,1,1,0,0,0,1,0,0,0,1}, /* A */
        {1,1,1,1,1,1,0,0,0,1,0,1,0,1,0,0},
        {1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0},
        {1,1,1,1,1,1,0,0,0,1,0,0,0,1,0,0},
        {1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1},
        {1,1,0,0,0,0,1,1,0,0,0,0,0,0,0,1},
        {1,1,0,1,1,1,1,1,0,0,0,1,0,0,0,0},
        {0,0,1,1,0,0,1,1,0,0,0,1,0,0,0,1},
        {0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0},
        {0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0},
        {0,0,0,0,0,0,1,1,0,0,1,0,1,0,0,1},
        {0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0},
        {0,0,1,1,0,0,1,1,1,0,1,0,0,0,0,0},
        {0,0,1,1,0,0,1,1,1,0,0,0,1,0,0,0},
        {1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0},
        {1,1,1,0,0,0,1,1,0,0,0,1,0,0,0,1},
        {1,1,1,1,1,1,1,1,0,0,0,0,1,0,0,0},
        {1,1,1,0,0,0,1,1,0,0,0,1,1,0,0,1},
        {1,1,0,1,1,1,0,1,0,0,0,1,0,0,0,1},
        {1,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0},
        {0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0},
        {0,0,0,0,0,0,1,1,0,0,1,0,0,0,1,0},
        {0,0,1,1,0,0,1,1,0,0,0,0,1,0,1,0},
        {0,0,0,0,0,0,0,0,1,0,1,0,1,0,1,0},
        {0,0,0,0,0,0,0,0,1,0,1,0,0,1,0,0},
        {1,1,0,0,1,1,0,0,0,0,1,0,0,0,1,0}, /* Z */
        {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
        
    static const int segments[16][4]={
        {0,0,1,0},{1,0,2,0},{2,0,2,1},{2,1,2,2},
        {1,2,2,2},{0,2,1,2},{0,1,0,2},{0,0,0,1},
        {0,0,1,1},{1,0,1,1},{2,0,1,1},{2,1,1,1},
        {2,2,1,1},{1,2,1,1},{0,2,1,1},{0,1,1,1}
    };
        
    int i,j,l;
    int xp[3],yp[3];
    const int *character;
    int special_character;
    char carac;
    
    CAM_CHECK_ARGS(camDrawText16s,image->imageData!=NULL);
    
    if (orientation) {
        xp[0]=0; xp[1]=2*cwidth/5; xp[2]=4*cwidth/5;
        yp[0]=cheight; yp[1]=cheight-cheight/3; yp[2]=cheight-2*cheight/3;
    } else {
        xp[0]=0; xp[1]=cwidth/3; xp[2]=2*cwidth/3;
        yp[0]=0; yp[1]=2*cheight/5; yp[2]=4*cheight/5;
    }
    
    l=strlen(text);
    
    for (i=0;i<l;i++) {
        if (orientation) {
            carac=text[l-1-i];
        } else {
            carac=text[i];
        }
        special_character=0;
        if ((carac>='0')&&(carac<='9')) {
            character=characters_table[carac-'0'];
        } else if ((carac>='A')&&(carac<='Z')) {
            character=characters_table[carac-'A'+10];
        } else if ((carac>='a')&&(carac<='z')) {
            character=characters_table[carac-'a'+10];
        } else if (carac==' ') {
            /* Space character */
            special_character=1;
        } else if (carac==':') {
            special_character=1;
            if (orientation) {
                camDrawLine(image,x+xp[1],y+yp[1],x+xp[1],y+yp[1],color);
                camDrawLine(image,x+xp[2],y+yp[1],x+xp[2],y+yp[1],color);
            } else {
                camDrawLine(image,x+xp[1],y+yp[1],x+xp[1],y+yp[1],color);
                camDrawLine(image,x+xp[1],y+yp[2],x+xp[1],y+yp[2],color);
            }
        } else if (carac=='.') {
            special_character=1;
            if (orientation) {
                camDrawLine(image,x+xp[2],y+yp[1],x+xp[2],y+yp[1],color);
            } else {
                camDrawLine(image,x+xp[1],y+yp[2],x+xp[1],y+yp[2],color);
            }
        } else if (carac=='=') {
            special_character=1;
            if (orientation) {
                camDrawLine(image,x+xp[1],y+yp[0],x+xp[1],y+yp[2],color);
                camDrawLine(image,x+xp[2],y+yp[0],x+xp[2],y+yp[2],color);
            } else {
                camDrawLine(image,x+xp[0],y+yp[1],x+xp[2],y+yp[1],color);
                camDrawLine(image,x+xp[0],y+yp[2],x+xp[2],y+yp[2],color);
            }
        } else if (carac=='-') {
            special_character=1;
            if (orientation) {
                camDrawLine(image,x+xp[1],y+yp[0],x+xp[1],y+yp[2],color);
            } else {
                camDrawLine(image,x+xp[0],y+yp[1],x+xp[2],y+yp[1],color);
            }
        }
        
        if (!special_character) {
            if (orientation) {
                for (j=0;j<16;j++) {
                    if (character[j]) {
                        camDrawLine(image,x+xp[segments[j][1]],y+yp[segments[j][0]],x+xp[segments[j][3]],y+yp[segments[j][2]],color);
                    }
                }
            } else {
                for (j=0;j<16;j++) {
                    if (character[j]) {
                        camDrawLine(image,x+xp[segments[j][0]],y+yp[segments[j][1]],x+xp[segments[j][2]],y+yp[segments[j][3]],color);
                    }
                }
            }
        }
        if (orientation) {
            y+=cheight;
        } else {
            x+=cwidth;
        }
    }
    return 1;
}
Example #11
0
int camAccumulateLine(CamImage *image, int x1, int y1, int x2, int y2, int accumulator)
{
    int dx, dy, xincr, yincr, x, y, xp, yp, i, j;
    int inc, error, correction, acc, temp, ptrincr, runl, runl2;
    CAM_PIXEL *ptrX;
    CamInternalROIPolicyStruct iROI;
#ifdef CAM_DEBUG
    int valmax=(1<<(sizeof(CAM_PIXEL)*8))-1;
    int value;
#endif

    // ROI (Region Of Interest) management
    CAM_CHECK(camAccumulateLine,camInternalROIPolicy(image, NULL, &iROI, 0));
    CAM_CHECK_ARGS(camAccumulateLine,iROI.nChannels==1);
    CAM_CHECK_ARGS2(camAccumulateLine,(image->depth&CAM_DEPTH_SIGN)==0,"Supports only unsigned images");
    /* Clipping */
    if (x1<x2) {
        x=x1; y=y1; xp=x2; yp=y2;
    } else {
        x=x2; y=y2; xp=x1; yp=y1;
    }
    if (x<iROI.srcroi.xOffset) {
        if (x==xp) return 1;
        y=y+(y-yp)*(iROI.srcroi.xOffset-x)/(x-xp);
        x=iROI.srcroi.xOffset;
        if (xp<iROI.srcroi.xOffset) return 1; /* The line is completely outside the ROI */
    }
    if (xp>=(iROI.srcroi.xOffset+iROI.srcroi.width)) {
        if (x==xp) return 1;
        yp=y+(y-yp)*((iROI.srcroi.xOffset+iROI.srcroi.width)-x-1)/(x-xp);
        xp=(iROI.srcroi.xOffset+iROI.srcroi.width)-1;
        if (x>=(iROI.srcroi.xOffset+iROI.srcroi.width)) return 1; /* The line is completely outside the ROI */
    }
    if (y<yp) {
        x1=x; y1=y; x2=xp; y2=yp;
    } else {
        x1=xp; y1=yp; x2=x; y2=y;
    }
    if (y1<iROI.srcroi.yOffset) {
        if (y1==y2) return 1;
        x1=x1+(x1-x2)*(iROI.srcroi.yOffset-y1)/(y1-y2);
        y1=iROI.srcroi.yOffset;
        if (y2<iROI.srcroi.yOffset) return 1; /* The line is completely outside the ROI */
    }
    if (y2>=(iROI.srcroi.yOffset+iROI.srcroi.height)) {
        if (y1==y2) return 1;
        x2=x1+(x1-x2)*((iROI.srcroi.yOffset+iROI.srcroi.height)-y1-1)/(y1-y2);
        y2=(iROI.srcroi.yOffset+iROI.srcroi.height)-1;
        if (y1>=(iROI.srcroi.yOffset+iROI.srcroi.height)) return 1; /* The line is completely outside the ROI */
    }
    
#define LINE
#ifdef CAM_DEBUG
#define SETPIXEL value=*ptrX; value+=accumulator; if ((value<0)||(value>valmax)) {camError("camAccumulateLane","Saturation"); return 0;} else *ptrX=(CAM_PIXEL)value;
#else
#define SETPIXEL *ptrX+=accumulator;
#endif
#define INITPOINTERS ptrX=((CAM_PIXEL*)(image->imageData+iROI.srcchoffset+y*image->widthStep))+x*iROI.srcinc
#include "cam_draw_code.c"
#undef INITPOINTERS
#undef SETPIXEL
#undef LINE
    return 1;
}
int camIntegralImage(CamImage *src, CamImage *dest)
{
    int x, y;
    int width, height;
    CAM_PIXEL *srcptr, *srctmpptr;
    unsigned long *dstptr, *dsttmpptr;
    CamInternalROIPolicyStruct iROI;
    unsigned long val;
#ifdef CAM_VECTORIZE
    int i;
    union i4vector v1, v2;
#endif

    CAM_CHECK_ARGS2(camIntegralImage, src->imageData != NULL, "source image is not allocated");
    if (dest->imageData==NULL) {
        // Automatic allocation
        camAllocateImage(dest, src->width, src->height, CAM_DEPTH_32U);
    }
    CAM_CHECK(camIntegralImage, camInternalROIPolicy(src, dest, &iROI, 0));
    CAM_CHECK_ARGS(camIntegralImage, iROI.nChannels == 1);
    CAM_CHECK_ARGS(camIntegralImage, (src->depth & CAM_DEPTH_MASK) >= 8);
    CAM_CHECK_ARGS(camIntegralImage, (src->depth & CAM_DEPTH_MASK) <= (sizeof(CAM_PIXEL) * 8));
    CAM_CHECK_ARGS(camIntegralImage, (dest->depth & CAM_DEPTH_MASK) == 32);
    CAM_CHECK_ARGS(camIntegralImage, !(src->depth & CAM_DEPTH_SIGN));

    /*
        // One pass algorithm
        width = iROI.srcroi.width;
        height = iROI.srcroi.height;
        srcptr = (CAM_PIXEL*)iROI.srcptr;
        dstptr = (unsigned long*)iROI.dstptr;
        srctmpptr = srcptr;
        dsttmpptr = dstptr;
        val = 0;
        for (x = 0; x < width; x++, srcptr += iROI.srcinc, dstptr++) {
    	val += *srcptr;
    	*dstptr = val;
        }
        srcptr = (CAM_PIXEL*)(((char*)srctmpptr) + src->widthStep);
        dstptr = (unsigned long*)(((char*)dsttmpptr) + dest->widthStep);
        for (y = 1; y < height; y++) {
    	srctmpptr = srcptr;
    	dsttmpptr = dstptr;
    	val = 0;
    	for (x = 0; x < width; x++, srcptr += iROI.srcinc, dstptr++) {
    	    val += *srcptr;
    	    *dstptr = val + *(unsigned long*)(((char*)dstptr) - dest->widthStep);
    	}
    	srcptr = (CAM_PIXEL*)(((char*)srctmpptr) + src->widthStep);
    	dstptr = (unsigned long*)(((char*)dsttmpptr) + dest->widthStep);
        }
    */

    // Two passes algorithm
    // First pass
    width = iROI.srcroi.width;
    height = iROI.srcroi.height;
    srcptr = (CAM_PIXEL*)iROI.srcptr;
    dstptr = (unsigned long*)iROI.dstptr;
    for (y = 0; y < height; y++) {
        srctmpptr = srcptr;
        dsttmpptr = dstptr;
        val = 0;
        for (x = 0; x < width; x++, srcptr += iROI.srcinc, dstptr++) {
            val += *srcptr;
            *dstptr = val;
        }
        srcptr = (CAM_PIXEL*)(((char*)srctmpptr) + src->widthStep);
        dstptr = (unsigned long*)(((char*)dsttmpptr) + dest->widthStep);
    }

#ifndef CAM_VECTORIZE
    // Second pass
    dstptr = (unsigned long*)iROI.dstptr;
    dstptr = (unsigned long*)(((char*)dstptr) + dest->widthStep);
    for (y = 1; y < height; y++) {
        dsttmpptr = dstptr;
        for (x = 0; x < width; x++, dstptr++) {
            *dstptr += *(unsigned long*)(((char*)dstptr) - dest->widthStep);
        }
        dstptr = (unsigned long*)(((char*)dsttmpptr) + dest->widthStep);
    }
#else
    // Second pass / SSE2 vectorized
    dstptr = (unsigned long*)iROI.dstptr;
    dstptr = (unsigned long*)(((char*)dstptr) + dest->widthStep);
    for (y = 1; y < height; y++) {
        dsttmpptr = dstptr;
        for (x = 0; x < width; x+=4) {
            // Add 4 pixels at once
            for (i = 0; i != 4; i++, dstptr++) {
                v1.i[i] = *dstptr;
                v2.i[i] = *(unsigned long*)(((char*)dstptr) - dest->widthStep);
            }
            v1.v = v1.v + v2.v;
            dstptr -= (iROI.dstinc<<2);
            for (i = 0; i != 4; i++, dstptr++) *dstptr = v1.i[i];

        }
        for (; x < width; x++, dstptr += iROI.dstinc) {
            *dstptr += *(unsigned long*)(((char*)dstptr) - dest->widthStep);
        }
        dstptr = (unsigned long*)(((char*)dsttmpptr) + dest->widthStep);
    }
#endif

    camInternalROIPolicyExit(&iROI);
    return 1;
}
int camMedianFilter(CamImage *source, CamImage *dest)
{
    int i,j,x,y,xp,yp;
    int width,height;
    int value,result;
    int left,top;
    CAM_PIXEL *srcptr,*dstptr,*tmpptr,*cpsrcptr,*cpdstptr;
    CAM_PIXEL *linesPtr[CAM_MF_NEIGHB];
    CAM_PIXEL linesBuffer[CAM_MF_NEIGHB][CAM_MAX_SCANLINE+CAM_MF_NEIGHB-1];
    
    // Data for sorting pixels in the neighbourhood
    int values[CAM_MF_NEIGHB*CAM_MF_NEIGHB];
    int next[CAM_MF_NEIGHB*CAM_MF_NEIGHB];
    int first,last,nb,prev;
    
    CamInternalROIPolicyStruct iROI;
    
    // ROI (Region Of Interest) management
    CAM_CHECK(camMedianFilter,camInternalROIPolicy(source, dest, &iROI, 1));
    CAM_CHECK_ARGS(camMedianFilter,iROI.nChannels==1);

    CAM_CHECK_ARGS(camMedianFilter,(source->depth&CAM_DEPTH_MASK)<=(sizeof(CAM_PIXEL)*8));
    CAM_CHECK_ARGS(camMedianFilter,(source->depth&CAM_DEPTH_MASK)>=8);
    CAM_CHECK_ARGS(camMedianFilter,(dest->depth&CAM_DEPTH_MASK)<=(sizeof(CAM_PIXEL)*8));
    CAM_CHECK_ARGS(camMedianFilter,(dest->depth&CAM_DEPTH_MASK)>=8);
    
    width=iROI.srcroi.width;
    height=iROI.srcroi.height;
    if (source->roi) {
        left=iROI.srcroi.xOffset;
        top=iROI.srcroi.yOffset;
        i=left; if (i>CAM_MF_NEIGHB/2) i=CAM_MF_NEIGHB/2;
        j=top; if (j>CAM_MF_NEIGHB/2) j=CAM_MF_NEIGHB/2;
        srcptr=(CAM_PIXEL*)(source->imageData+iROI.srcchoffset+(top-j)*source->widthStep)+(left-i);
    } else {
        srcptr=(CAM_PIXEL*)(source->imageData+iROI.srcchoffset);
        left=0;
        top=0;
    }
    dstptr=(CAM_PIXEL*)iROI.dstptr;
    CAM_CHECK_ARGS(camMedianFilter,(width>CAM_MF_NEIGHB/2));
    CAM_CHECK_ARGS(camMedianFilter,(height>CAM_MF_NEIGHB/2));    
	
    // Initialize algorithm
    for (i=0;i<CAM_MF_NEIGHB;i++) {
	linesPtr[i]=linesBuffer[i];
    }

    // Initialize neighbourhood
    
    // Fill the top lines
    for (y=0;y+top<CAM_MF_NEIGHB/2;y++) {
        // Out of frame : fill with border color
        if (source->borderMode[CAM_SIDE_TOP_INDEX]==CAM_BORDER_REPLICATE) {
            cpsrcptr=srcptr;
            for (x=0;x<CAM_MF_NEIGHB/2;x++) {
                linesPtr[y][x]=*srcptr;
            }
            for (;x<width+CAM_MF_NEIGHB/2;x++) {
                linesPtr[y][x]=*srcptr;
                srcptr+=iROI.srcinc;
            }
            for (;x<width+CAM_MF_NEIGHB-1;x++) {
                linesPtr[y][x]=*(srcptr-iROI.srcinc);
            }
            srcptr=cpsrcptr;
        } else {
            for (x=0;x<width+CAM_MF_NEIGHB-1;x++) {
                linesPtr[y][x]=source->borderConst[CAM_SIDE_TOP_INDEX];
            }
        }
    }
    
    // Fill the next lines with image pixels
    for (;y<CAM_MF_NEIGHB-1;y++) {
        cpsrcptr=srcptr;
        for (x=0;x<CAM_MF_NEIGHB/2;x++) {
            if (left+x-CAM_MF_NEIGHB/2<0) {
                // Out of frame : fill with border color
                if (source->borderMode[CAM_SIDE_LEFT_INDEX]==CAM_BORDER_REPLICATE) {
                    linesPtr[y][x]=*srcptr;
                } else {
                    linesPtr[y][x]=source->borderConst[CAM_SIDE_LEFT_INDEX];
                }
            } else {
                // Get border pixels from the source frame
                linesPtr[y][x]=*srcptr;
                srcptr+=iROI.srcinc;
            }
        }
        for (;x<width+CAM_MF_NEIGHB/2;x++) {
            linesPtr[y][x]=*srcptr;
            srcptr+=iROI.srcinc;
        }
        for (;x<width+CAM_MF_NEIGHB-1;x++) {
            if (left+x-CAM_MF_NEIGHB/2<source->width) {
                // Get border pixels from the source frame
                linesPtr[y][x]=*srcptr;
                srcptr+=iROI.srcinc;
            } else {
                // Out of frame : fill with border color
                if (source->borderMode[CAM_SIDE_RIGHT_INDEX]==CAM_BORDER_REPLICATE) {
                    linesPtr[y][x]=*(srcptr-iROI.srcinc);
                } else {
                    linesPtr[y][x]=source->borderConst[CAM_SIDE_RIGHT_INDEX];
                }
            }
        }
        srcptr=(CAM_PIXEL*)(((char*)cpsrcptr)+source->widthStep);
    }

    // Now process the whole image
    // This is the main loop
    for (y=0;y<height;y++) {
	cpsrcptr=srcptr;
        cpdstptr=dstptr;

        // Start a new line
        // Have we reached the bottom of the frame ?
        if (top+y+CAM_MF_NEIGHB/2>=source->height) {
            if (source->borderMode[CAM_SIDE_BOTTOM_INDEX]==CAM_BORDER_REPLICATE) {
                // Go up one line (in order to stay on the last line)
                cpsrcptr=(CAM_PIXEL*)(((char*)cpsrcptr)-source->widthStep);
                srcptr=cpsrcptr;
                for (x=0;x<CAM_MF_NEIGHB/2;x++) {
                    linesPtr[CAM_MF_NEIGHB-1][x]=*srcptr;
                }
                for (;x<width+CAM_MF_NEIGHB/2;x++) {
                    linesPtr[CAM_MF_NEIGHB-1][x]=*srcptr;
                    srcptr+=iROI.srcinc;
                }
                for (;x<width+CAM_MF_NEIGHB-1;x++) {
                    linesPtr[CAM_MF_NEIGHB-1][x]=*(srcptr-iROI.srcinc);
                }
            } else {
                for (x=0;x<width+CAM_MF_NEIGHB-1;x++) {
                    linesPtr[CAM_MF_NEIGHB-1][x]=source->borderConst[CAM_SIDE_BOTTOM_INDEX];
                }
            }
        } else {
            for (x=0;x<CAM_MF_NEIGHB/2;x++) {
                if (left+x-CAM_MF_NEIGHB/2<0) {
                    // Out of frame : fill with border color
                    if (source->borderMode[CAM_SIDE_LEFT_INDEX]==CAM_BORDER_REPLICATE) {
                        linesPtr[CAM_MF_NEIGHB-1][x]=*srcptr;
                    } else {
                        linesPtr[CAM_MF_NEIGHB-1][x]=source->borderConst[CAM_SIDE_LEFT_INDEX];
                    }
                } else {
                    // Get border pixels from the source frame
                    linesPtr[CAM_MF_NEIGHB-1][x]=*srcptr;
                    srcptr+=iROI.srcinc;
                }
            }

            // Fast transfer with memcpy
            if (iROI.srcinc==1) {
                memcpy(&linesPtr[CAM_MF_NEIGHB-1][x],srcptr,(source->width-left+CAM_MF_NEIGHB/2-x)<<(sizeof(CAM_PIXEL)-1));
                x=source->width-left+CAM_MF_NEIGHB/2;
            } else {
                for (;x<source->width-left+CAM_MF_NEIGHB/2;x++) {
                    // Get a pixel from the source frame
                    linesPtr[CAM_MF_NEIGHB-1][x]=*srcptr;
                    srcptr+=iROI.srcinc;
                }
            }
            for (;x<width+CAM_MF_NEIGHB-1;x++) {
                // Out of frame : fill with border color
                if (source->borderMode[CAM_SIDE_RIGHT_INDEX]==CAM_BORDER_REPLICATE) {
                    linesPtr[CAM_MF_NEIGHB-1][x]=*(srcptr+(source->width-1)*iROI.srcinc);
                } else {
                    linesPtr[CAM_MF_NEIGHB-1][x]=source->borderConst[CAM_SIDE_RIGHT_INDEX];
                }
            }
        }

	// Process all the pixels in the line
	for (x=CAM_MF_NEIGHB-1;x<width+CAM_MF_NEIGHB-1;x++) {

	    // Now, let's sort the pixels in the neighbourhood
	    first=0;
	    last=0;
	    nb=1;
	    i=x-CAM_MF_NEIGHB+1;
	    // Get the first pixel
	    value=linesPtr[0][i];
	    // And put it in the sorted list
	    values[0]=value;
	    next[0]=-1;

#define INSERT_VALUE(value)				\
	    values[nb]=value;				\
	    if (value>values[first]) {			\
		prev=first;				\
		j=next[first];				\
		while ((j!=-1)&&(value>values[j])) {	\
		    prev=j;				\
		    j=next[j];				\
		}					\
		if (j==-1) {				\
		    next[last]=nb;			\
		    last=nb;				\
		    next[nb]=-1;			\
		} else {				\
		    next[nb]=j;				\
		    next[prev]=nb;			\
		}					\
	    } else {					\
		next[nb]=first;				\
		first=nb;				\
	    }						\
	    nb++;			

    	    for (xp=1;xp<CAM_MF_NEIGHB;xp++) {
		value=linesPtr[0][i+xp];
		INSERT_VALUE(value);
	    }

	    for (yp=1;yp<CAM_MF_NEIGHB;yp++) {
		for (xp=0;xp<CAM_MF_NEIGHB;xp++) {
		    value=linesPtr[yp][i+xp];
		    INSERT_VALUE(value);
		}
	    }

	    // Retrieve the median value
	    j=first;
	    for (i=0;i<CAM_MF_NEIGHB*CAM_MF_NEIGHB/2;i++) {
		j=next[j];
	    }
	    result=values[j];

	    // Store the result in destination image
	    *dstptr=result;
            dstptr+=iROI.dstinc;
	}
	
	// Go to next line
	srcptr=(CAM_PIXEL*)(((char*)cpsrcptr)+source->widthStep);
	dstptr=(CAM_PIXEL*)(((char*)cpdstptr)+dest->widthStep);
	
	// Reset neighborhood line pointers
	tmpptr=linesPtr[0];
	for (i=0;i<CAM_MF_NEIGHB-1;i++) {
	    linesPtr[i]=linesPtr[i+1];
	}
	linesPtr[CAM_MF_NEIGHB-1]=tmpptr;
    }

    camInternalROIPolicyExit(&iROI);
    return 1;
}
Example #14
0
int
camKeypointsRecursiveDetector(CamImage *source, CamImage *integral, CamKeypoints *points, int nb_max_keypoints, int options)
{
	CamImage filter;
	CamInternalROIPolicyStruct iROI;
	CamROI *roi, roix;
	int i, width, height;
	CamKeypointShort *keypoints;
	int pnb_keypoints;
	int nb_keypoints = 0;
	unsigned int *abs_value_lines[2];
	int *value_lines[2];
	unsigned char *scale_lines[2];
	unsigned char *lmax_lines[2];
	unsigned int *lmax[2], nblmax[2];
	int widthStep;

	camPatchSizeParam = 16; //32 * 2 / 3; // Equivalent optimal value wrt SURF (the descriptor can partially lie outside screen)

	// Parameters checking
	CAM_CHECK(camKeypointsRecursiveDetector, camInternalROIPolicy(source, NULL, &iROI, 1));
	CAM_CHECK_ARGS(camKeypointsRecursiveDetector, (source->depth & CAM_DEPTH_MASK) >= 8);
	CAM_CHECK_ARGS(camKeypointsRecursiveDetector, points->allocated >= 0);
	CAM_CHECK_ARGS(camKeypointsRecursiveDetector, source->nChannels == 1 || ((source->nChannels == 3) && (source->dataOrder == CAM_DATA_ORDER_PLANE)));
	width = iROI.srcroi.width;
	height = iROI.srcroi.height;

	if (!integral)
	{
		// Compute integral image
		integral = (CamImage*)malloc(sizeof(CamImage));
		integral->imageData = NULL;
		roi = source->roi;
		camSetMaxROI(&roix, source);
		roix.coi = 1;
		source->roi = &roix;
		camIntegralImage(source, integral); // Computed on the whole frame, not only on ROI
		integral->roi = &iROI.srcroi;
		source->roi = roi;
	}
	widthStep = integral->widthStep / 4;

	// Allocate temp memory for keypoints
	keypoints = (CamKeypointShort*)malloc(CAM_MAX_KEYPOINTS * sizeof(CamKeypointShort));
	points->nbPoints = 0;
	// Allocate value and scale lines
	for (i = 0; i < 2; i++) {
		scale_lines[i] = (unsigned char*)malloc(width * sizeof(unsigned char));
		value_lines[i] = (int*)malloc(width * sizeof(int));
		abs_value_lines[i] = (unsigned int*)malloc(width * sizeof(unsigned int));
		lmax_lines[i] = (unsigned char*)malloc(width * sizeof(unsigned char));
		lmax[i] = (unsigned int*)malloc(width * sizeof(unsigned int));
		nblmax[i] = 0;
	}

	// Go !
	{
		int y;
		int max_scale_y;
		unsigned int *abs_current_value_line, *abs_previous_value_line;
		int *current_value_line, *previous_value_line;
		unsigned char *current_scale_line, *previous_scale_line;
		unsigned char *current_lmax_line, *previous_lmax_line;
		unsigned int *current_lmax, *previous_lmax;
		unsigned int current_nblmax, previous_nblmax;

		current_value_line = value_lines[0];
		previous_value_line = value_lines[1];
		abs_current_value_line = abs_value_lines[0];
		abs_previous_value_line = abs_value_lines[1];
		current_scale_line = scale_lines[0];
		previous_scale_line = scale_lines[1];
		current_lmax_line = lmax_lines[0];
		previous_lmax_line = lmax_lines[1];
		current_lmax = lmax[0];
		previous_lmax = lmax[1];
		// Fill the previous value line with a dummy value
		for (i = 0; i < width; i++) {
			abs_previous_value_line[i] = 0;
			previous_value_line[i] = 0;
			previous_scale_line[i] = 1;
			previous_lmax_line[i] = 0;
		}
		current_nblmax = 0;
		previous_nblmax = 0;

		for (y = 0; y < height; y++) {
			int x, v;
			// max_scale is the biggest scale we may apply. It must be more than 0, otherwise we can't do any image processing
			max_scale_y = (y + iROI.srcroi.yOffset) >> 1;
			// The preceding formula comes from :
			// - When iROI.yOffset is 0, max_scale should be 1 when y is 2 (1 pixel margin due to integral image)
			// - When iROI.yOffset is 0, max_scale should be 1 when y is 3 (1 pixel margin due to integral image)
			// - When iROI.yOffset is 0, max_scale should be 2 when y is 4 (1 pixel margin due to integral image)
			// Check max_scale with the bottom line
			v = (source->height - 1 - (y + iROI.srcroi.yOffset)) >> 1;
			// The preceding formula comes from "When iROI.yOffset is 0, max_scale should be 1 when y is equal to source->height - 3
			if (v < max_scale_y) max_scale_y = v;

			if (max_scale_y < 1) {
				// We can't compute anything for that line
				for (i = 0; i < width; i++) {
					current_value_line[i] = 0;
					current_scale_line[i] = 1;
				}
			} else {
				int scale_up = 1;
				int current_value = 0;
				unsigned int abs_current_value = 0;
				int current_scale = 1;
				unsigned int *ptr = ((unsigned int*)(integral->imageData + (y + iROI.srcroi.yOffset) * integral->widthStep)) + iROI.srcroi.xOffset;
				int s1, s2;

				for (x = 0; x < width; x++, ptr++) {
					int first_scale = current_scale;
					int max_scale = max_scale_y;
					// Check max_scale with the left side of the frame
					v = (x + iROI.srcroi.xOffset) >> 1;
					if (v < max_scale) max_scale = v;
					// Check max_scale with the right side of the frame
					v = (source->width -1 - (x + iROI.srcroi.xOffset)) >> 1;
					if (v < max_scale) max_scale = v;
					// We need a scale margin in order to compute the descriptor
					max_scale -= CAM_SCALE_MARGIN;

					// Choose the first scale to evaluate, depending on upper and left results
					if (abs_previous_value_line[x] > abs_current_value)
						first_scale = previous_scale_line[x];

					if (first_scale <= max_scale) {
						// Evaluate at first scale
						int scale = first_scale; // alias
						int yoffset = scale * widthStep;
						int value;
						#define CAM_RECURSIVE_PATTERN \
						{ \
						unsigned int *ptrAi = ptr - (yoffset + scale); \
						unsigned int *ptrDi = ptr + (yoffset + scale); \
						unsigned int *ptrBi = ptr - (yoffset - scale); \
						unsigned int *ptrCi = ptr + (yoffset - scale); \
						unsigned int valin = *ptrDi - *ptrBi - *ptrCi + *ptrAi; \
						unsigned int *ptrAo = ptr - ((yoffset + scale) << 1); \
						unsigned int *ptrDo = ptr + ((yoffset + scale) << 1); \
						unsigned int *ptrBo = ptr - ((yoffset - scale) << 1); \
						unsigned int *ptrCo = ptr + ((yoffset - scale) << 1); \
						unsigned int valout = *ptrDo - *ptrBo - *ptrCo + *ptrAo; \
						value = valout - (valin << 2); \
					}
					CAM_RECURSIVE_PATTERN;
					current_scale = scale;
					current_value = value;
					abs_current_value = abs(value);

					// Let's see if we go upscale or not...
					if (scale_up && scale < max_scale) {
						// OK. Let's test the upscale
						scale++;
						yoffset += widthStep;
						CAM_RECURSIVE_PATTERN;
						s1 = current_scale * current_scale; s2 = scale * scale;
						if (((CAM_INT64)abs(value)) * s1 > (CAM_INT64)abs_current_value * s2) {
							// Yes. That was a good hint
							current_scale = scale;
							current_value = value;
							abs_current_value = abs(value);
							// Let's test again at higher scale
							if (scale < max_scale) {
								scale++;
								yoffset += widthStep;
								CAM_RECURSIVE_PATTERN;
								s1 = current_scale * current_scale; s2 = scale * scale;
								if (((CAM_INT64)abs(value)) * s1 > (CAM_INT64)abs_current_value * s2) {
									// Even better
									current_scale = scale;
									current_value = value;
									abs_current_value = abs(value);
									// And we stop there, satisfied...
								}
							}
						} else {
							// Oh, oh... Apparently, that was not a good hint to go upscale...
							// Let's try to downscale then...
							scale -= 2;
							if (scale > 0 && scale <= max_scale) {
								yoffset -= widthStep << 1;
								CAM_RECURSIVE_PATTERN;
								s1 = current_scale * current_scale; s2 = scale * scale;
								if (((CAM_INT64)abs(value)) * s1 > (CAM_INT64)abs_current_value * s2) {
									// Yes. It's better
									scale_up = 0; // This is the hint for next time
									current_scale = scale;
									current_value = value;
									abs_current_value = abs(value);
								}
								// And we stop there, satisfied...
							}
						}
					} else {
						// OK. Let's test the downscale
						scale--;
						if (scale > 0 && scale <= max_scale) {
							yoffset -= widthStep;
							CAM_RECURSIVE_PATTERN;
							if (((CAM_INT64)abs(value)) * current_scale * current_scale > (CAM_INT64)abs_current_value * scale * scale) {
								// Yes. That was a good hint.
								current_scale = scale;
								current_value = value;
								abs_current_value = abs(value);
								// Let's test again at lower scale
								scale--;
								if (scale > 0 && scale <= max_scale) {
									yoffset -= widthStep;
									CAM_RECURSIVE_PATTERN;
									s1 = current_scale * current_scale; s2 = scale * scale;
									if (((CAM_INT64)abs(value)) * s1 > (CAM_INT64)abs_current_value * s2) {
										// Even better
										current_scale = scale;
										current_value = value;
										abs_current_value = abs(value);
										// And we stop there, satisfied...
									}
								}
							} else {
								// Oh, oh... Apparently, that was not a good hint to go downscale...
								// Let's try to upscale then...
								scale += 2;
								if (scale > 0 && scale <= max_scale) {
									yoffset += widthStep << 1;
									CAM_RECURSIVE_PATTERN;
									s1 = current_scale * current_scale; s2 = scale * scale;
									if (((CAM_INT64)abs(value)) * s1 > (CAM_INT64)abs_current_value * s2) {
										// Yes. It's better
										scale_up = 1; // This is the hint for next time
										current_scale = scale;
										current_value = value;
										abs_current_value = abs(value);
									}
									// And we stop there, satisfied...
								}
							}
						} else {
							// Oh, oh... Apparently, that was not a good hint to go downscale...
							// Let's try to upscale then...
							scale += 2;
							if (scale > 0 && scale <= max_scale) {
								yoffset += widthStep;
								CAM_RECURSIVE_PATTERN;
								s1 = current_scale * current_scale; s2 = scale * scale;
								if (((CAM_INT64)abs(value)) * s1 > (CAM_INT64)abs_current_value * s2) {
									// Yes. It's better
									scale_up = 1; // This is the hint for next time
									current_scale = scale;
									current_value = value;
									abs_current_value = abs(value);
								}
								// And we stop there, satisfied...
							}
						}
					}
					} else {
						// Skip this pixel and go back to small scale
						current_value = 0;
						abs_current_value = 0;
						current_scale = 1;
						scale_up = 1;
					}

					current_value = (current_value << 4) / (current_scale * current_scale);
					abs_current_value = abs(current_value);

					// Now, we do have the current_value, current_scale and abs_current_value
					// Let's check whether it is a local maximum or not
					{
						// If the current value is strictly greater than all the other values, then this is a local maximum and
						// the other pixels are marked as NOT being local maxima
						// If the current value is greater or equal to all neighbours, then this ia marked to be a local maximum
						// but the other pixels are kept as local maxima
						// If the current value is greater than any neighbour, this neighbour is marked as not being a local maximum
						int local_maximum = 1;
						if (x > 0) {
							// Compare to the left and upper-left pixel
							if (abs_current_value_line[x - 1] > abs_current_value)
								local_maximum = 0;
							else current_lmax_line[x - 1] = 0;
							if (abs_previous_value_line[x - 1] > abs_current_value)
								local_maximum = 0;
							else previous_lmax_line[x - 1] = 0;
						}
						// Compare to pixel above
						if (abs_previous_value_line[x] > abs_current_value)
							local_maximum = 0;
						else previous_lmax_line[x] = 0;
						if (x < width - 1) {
							// Compare to the upper right pixel
							if (abs_previous_value_line[x + 1] > abs_current_value)
								local_maximum = 0;
							else previous_lmax_line[x + 1] = 0;
						}
						if (local_maximum && abs_current_value > 0) {
							current_lmax[current_nblmax++] = x;
							current_lmax_line[x] = 1;
						}
					}

					// Record the data for next line evaluation
					current_value_line[x] = current_value;
					abs_current_value_line[x] = abs_current_value;
					current_scale_line[x] = current_scale;

					//if (y == 100) {
						//printf("y=%d x=%d value=%d abs=%d scale=%d\n", y, x, current_value, abs_current_value, current_scale);
						//}
				}
			}

			// Check the local maxima on the previous line, and record the keypoints IF they are local maxima
			for (i = 0; i != previous_nblmax; i++) {
				if (previous_lmax_line[previous_lmax[i]]) {
					int scale = previous_scale_line[previous_lmax[i]];
					if (scale >= CAM_MIN_SCALE) {
						// Yes, we have definitely a local maximum
						// Record the keypoint
						keypoints[nb_keypoints].x = previous_lmax[i];
						keypoints[nb_keypoints].y = y - 1;
						keypoints[nb_keypoints].scale = scale;
						keypoints[nb_keypoints].value = previous_value_line[previous_lmax[i]];
						nb_keypoints++;
					}
				}
			}

			// Switch previous and current lines
			{
				unsigned char *tmp;
				tmp = current_scale_line;
				current_scale_line = previous_scale_line;
				previous_scale_line = tmp;
			}{
				unsigned int *tmp;
				tmp = abs_current_value_line;
				abs_current_value_line = abs_previous_value_line;
				abs_previous_value_line = tmp;
			}{
				int *tmp;
				tmp = current_value_line;
				current_value_line = previous_value_line;
				previous_value_line = tmp;
			}{
				unsigned char *tmp;
				tmp = current_lmax_line;
				current_lmax_line = previous_lmax_line;
				previous_lmax_line = tmp;
			}{
				unsigned int *tmp;
				tmp = current_lmax;
				current_lmax = previous_lmax;
				previous_lmax = tmp;
			}
			previous_nblmax = current_nblmax;
			current_nblmax = 0;
		}
	}

	for (i = 0; i < 2; i++) {
		free(value_lines[i]);
		free(abs_value_lines[i]);
		free(scale_lines[i]);
		free(lmax_lines[i]);
		free(lmax[i]);
	}

	// Post-processing : remove keypoints in a given neighborhood (proportionnal to scale)
	for (i = 1; i < nb_keypoints; i++) {
		CamKeypointShort *keypoint = &keypoints[i];
		int j = i - 1;
		int neighborhood = keypoint->scale >> 2;
		while (j >= 0 && keypoints[j].y >= keypoint->y - neighborhood) {
			CamKeypointShort *keypoint2 = &keypoints[j];
			if (keypoint2->x >= keypoint->x - neighborhood && keypoint2->x <= keypoint->x + neighborhood) {
				// They are next to each other...
				if (abs(keypoint2->value) > abs(keypoint->value))
					keypoint->scale = 0; // Let's get rid of this one... It has a lower value
					else
						keypoint2->scale = 0;
			}
			j--;
		}
	}
	for (i = 0; i < nb_keypoints; i++)
		if (!keypoints[i].scale) keypoints[i].value = 0;

		if (options & CAM_UPRIGHT) {
			// Remove keypoints the descriptor of which would be outside the frame boundaries
			for (i = 0; i < nb_keypoints; i++) {
				if (keypoints[i].scale) {
					int scale = keypoints[i].scale; // Save the scale
					keypoints[i].scale = (scale << 2) + 1;
					if (!camKeypointDescriptorCheckBounds(&keypoints[i], integral))
						keypoints[i].value = 0;
					keypoints[i].scale = scale;
				}
			}
		}

		// Sort the features according to value
		qsort(keypoints, nb_keypoints, sizeof(CamKeypointShort), camSortKeypointsShort);
		for (i = 0; i < nb_keypoints; i++)
			if (keypoints[i].value == 0) break;
			nb_keypoints = i;

		if (nb_keypoints > nb_max_keypoints) nb_keypoints = nb_max_keypoints;

		/* Interpolation :
		* Maxima : solve([y1=a*(x1-p)^2+b,y2=a*(-p)^2+b,y3=a*(x3-p)^2+b],[a,b,p])
		* Maxima yields the following formula for parabolic interpolation
		2         2     2         2
		x1  y3 + (x3  - x1 ) y2 - x3  y1
		p = ------------------------------------
		2 x1 y3 + (2 x3 - 2 x1) y2 - 2 x3 y1

		*/
		// Scale super-resolution
		for (i = 0; i < nb_keypoints; i++) {
			CamKeypointShort *keypoint = &keypoints[i];
			#if 1
			int x = keypoint->x, y = keypoint->y;
			int v, max_scale;

			max_scale = (y + iROI.srcroi.yOffset) >> 1;
			v = (source->height - 1 - (y + iROI.srcroi.yOffset)) >> 1;
			if (v < max_scale) max_scale = v;
			v = (x + iROI.srcroi.xOffset) >> 1;
			if (v < max_scale) max_scale = v;
			v = (source->width -1 - (x + iROI.srcroi.xOffset)) >> 1;
			if (v < max_scale) max_scale = v;
			max_scale -= CAM_SCALE_MARGIN;

			if (keypoint->scale < max_scale) {
				unsigned int *ptr = ((unsigned int*)(integral->imageData + (y + iROI.srcroi.yOffset) * integral->widthStep)) + iROI.srcroi.xOffset + x;
				int scale = keypoint->scale - 1;
				int yoffset = scale * widthStep;
				int value, num, den, x1, x3, y1, y2, y3;
				x1 = -1;
				x3 = 1;
				y2 = keypoint->value;
				CAM_RECURSIVE_PATTERN;
				y1 = (value << 4) / (scale * scale);
				if (y1 > y2) keypoint->scale <<= 2; // This is a problem : this is not a local maximum in scale...
					else {
						int found = 0;
						scale = keypoint->scale + 1;
						do {
							yoffset = scale * widthStep;
							CAM_RECURSIVE_PATTERN;
							y3 = (value << 4) / (scale * scale);
							if (y3 <= y2) {
								num = (x1 * x1 * y3 + (x3 * x3 - x1 * x1) * y2 - x3 * x3 * y1);
								den = x1 * y3 + (x3 - x1) * y2 - x3 * y1;
								if (den == 0)
									keypoint->scale <<= 2;
								else {
									int p = (num << 1) / den; // shift only by 1, because den is shifted by 2
									keypoint->scale = p + ((scale - 1) << 2);
									found = 1;
								}
								break;
							}
							y1 = y2;
							y2 = y3;
							scale++;
						} while (scale <= max_scale);
						if (!found) keypoint->scale <<= 2;
					}
			}
			else
				#endif
				keypoint->scale <<= 2;
		}

		// Angle
		if (options & CAM_UPRIGHT) {
			for (i = 0; i < nb_keypoints; i++) {
				keypoints[i].angle = 0;
			}
		} else {
			camAllocateImage(&filter, CAM_ORIENTATION_STAMP_SIZE, CAM_ORIENTATION_STAMP_SIZE, CAM_DEPTH_16S);
			camBuildGaussianFilter(&filter, camSigmaParam);
			pnb_keypoints = nb_keypoints;
			if (pnb_keypoints > nb_max_keypoints) pnb_keypoints = nb_max_keypoints;
			for (i = 0; i < pnb_keypoints; i++) {
				nb_keypoints += camKeypointOrientation(source, &keypoints[i], &filter, &keypoints[nb_keypoints]);
			}
			camDeallocateImage(&filter);
		}

		// Sort again the features according to value
		qsort(keypoints, nb_keypoints, sizeof(CamKeypointShort), camSortKeypointsShort);

		// Keypoints allocation
		pnb_keypoints = nb_keypoints;
		if (pnb_keypoints > nb_max_keypoints) pnb_keypoints = nb_max_keypoints;
		if (points->allocated == 0) {
			camAllocateKeypoints(points, pnb_keypoints);
		} else if (points->allocated < pnb_keypoints) {
			camFreeKeypoints(points);
			camAllocateKeypoints(points, pnb_keypoints);
		}
		if (points->bag == NULL) {
			#ifdef __SSE2__
			points->bag = (CamKeypoint*)_mm_malloc(sizeof(CamKeypoint) * pnb_keypoints, 16);
			#else
			points->bag = (CamKeypoint*)malloc(sizeof(CamKeypoint) * pnb_keypoints);
			#endif
		}
		for (i = 0; i < pnb_keypoints; i++) {
			points->keypoint[i] = &points->bag[i];
			points->keypoint[i]->x = keypoints[i].x + iROI.srcroi.xOffset;
			points->keypoint[i]->y = keypoints[i].y + iROI.srcroi.yOffset;
			points->keypoint[i]->scale = keypoints[i].scale;
			points->keypoint[i]->value = keypoints[i].value;
			points->keypoint[i]->angle = keypoints[i].angle;
		}
		points->nbPoints = pnb_keypoints;
		free(keypoints);

		if (options & CAM_UPRIGHT) {
			camKeypointsDescriptor(points, integral, options);
		} else {
			camKeypointsDescriptor(points, source, options);
		}

		// Finally, set the points' set
		for (i = 0; i < points->nbPoints; i++) {
			points->keypoint[i]->set = points;
		}

		// Integral Image is now useless
		camInternalROIPolicyExit(&iROI);
		return 1;
}