/* * This Function segments a worm. * It requires that certain information be present in the WormAnalysisData struct Worm * It requires Worm->Boundary be full * It requires that Params->NumSegments be greater than zero * */ int SegmentWorm(WormAnalysisData* Worm, WormAnalysisParam* Params){ if (cvSeqExists(Worm->Boundary) == 0){ printf("Error! No boundary found in SegmentWorm()\n"); return -1; } Worm->Segmented->NumSegments=Params->NumSegments; /***Clear Out any stale Segmented Information Already in the Worm Structure***/ ClearSegmentedInfo(Worm->Segmented); Worm->Segmented->Head=Worm->Head; Worm->Segmented->Tail=Worm->Tail; /*** It would be nice to check that Worm->Boundary exists ***/ /*** Clear Out Scratch Storage ***/ cvClearMemStorage(Worm->MemScratchStorage); /*** Slice the boundary into left and right components ***/ if (Worm->HeadIndex==Worm->TailIndex) printf("Error! Worm->HeadIndex==Worm->TailIndex in SegmentWorm()!\n"); CvSeq* OrigBoundA=cvSeqSlice(Worm->Boundary,cvSlice(Worm->HeadIndex,Worm->TailIndex),Worm->MemScratchStorage,1); CvSeq* OrigBoundB=cvSeqSlice(Worm->Boundary,cvSlice(Worm->TailIndex,Worm->HeadIndex),Worm->MemScratchStorage,1); if (OrigBoundA->total < Params->NumSegments || OrigBoundB->total < Params->NumSegments ){ printf("Error in SegmentWorm():\n\tWhen splitting the original boundary into two, one or the other has less than the number of desired segments!\n"); printf("OrigBoundA->total=%d\nOrigBoundB->total=%d\nParams->NumSegments=%d\n",OrigBoundA->total,OrigBoundB->total,Params->NumSegments); printf("Worm->HeadIndex=%d\nWorm->TailIndex=%d\n",Worm->HeadIndex,Worm->TailIndex); return -1; /** Andy make this return -1 **/ } cvSeqInvert(OrigBoundB); /*** Resample One of the Two Boundaries so that both are the same length ***/ //Create sequences to store the Normalized Boundaries CvSeq* NBoundA= cvCreateSeq(CV_SEQ_ELTYPE_POINT,sizeof(CvSeq),sizeof(CvPoint),Worm->MemScratchStorage); CvSeq* NBoundB=cvCreateSeq(CV_SEQ_ELTYPE_POINT,sizeof(CvSeq),sizeof(CvPoint),Worm->MemScratchStorage); //Resample L&R boundary to have the same number of points as min(L,R) if (OrigBoundA->total > OrigBoundB->total){ resampleSeq(OrigBoundA,NBoundA,OrigBoundB->total ); NBoundB=OrigBoundB; }else{ resampleSeq(OrigBoundB,NBoundB,OrigBoundA->total ); NBoundA=OrigBoundA; } //Now both NBoundA and NBoundB are the same length. /* * Now Find the Centerline * */ /*** Clear out Stale Centerline Information ***/ cvClearSeq(Worm->Centerline); /*** Compute Centerline, from Head To Tail ***/ FindCenterline(NBoundA,NBoundB,Worm->Centerline); /*** Smooth the Centerline***/ CvSeq* SmoothUnresampledCenterline = smoothPtSequence (Worm->Centerline, 0.5*Worm->Centerline->total/Params->NumSegments, Worm->MemScratchStorage); /*** Note: If you wanted to you could smooth the centerline a second time here. ***/ /*** Resample the Centerline So it has the specified Number of Points ***/ //resampleSeq(SmoothUnresampledCenterline,Worm->Segmented->Centerline,Params->NumSegments); resampleSeqConstPtsPerArcLength(SmoothUnresampledCenterline,Worm->Segmented->Centerline,Params->NumSegments); /** Save the location of the centerOfWorm as the point halfway down the segmented centerline **/ Worm->Segmented->centerOfWorm= CV_GET_SEQ_ELEM( CvPoint , Worm->Segmented->Centerline, Worm->Segmented->NumSegments / 2 ); /*** Remove Repeat Points***/ //RemoveSequentialDuplicatePoints (Worm->Segmented->Centerline); /*** Use Marc's Perpendicular Segmentation Algorithm * To Segment the Left and Right Boundaries and store them */ SegmentSides(OrigBoundA,OrigBoundB,Worm->Segmented->Centerline,Worm->Segmented->LeftBound,Worm->Segmented->RightBound); return 0; }
/* * Smooths, thresholds and finds the worms contour. * The original image must already be loaded into Worm.ImgOrig * The Smoothed image is deposited into Worm.ImgSmooth * The thresholded image is deposited into Worm.ImgThresh * The Boundary is placed in Worm.Boundary * */ void FindWormBoundary(WormAnalysisData* Worm, WormAnalysisParam* Params){ /** This function currently takes around 5-7 ms **/ /** * Before I forget.. plan to make this faster by: * a) using region of interest * b) decimating to make it smaller (maybe?) * c) resize * d) not using CV_GAUSSIAN for smoothing */ /** Smooth the Image **/ TICTOC::timer().tic("cvSmooth"); cvSmooth(Worm->ImgOrig,Worm->ImgSmooth,CV_GAUSSIAN,Params->GaussSize*2+1); TICTOC::timer().toc("cvSmooth"); /** Dilate and Erode **/ // cvDilate(Worm->ImgSmooth, Worm->ImgSmooth,NULL,3); // cvErode(Worm->ImgSmooth, Worm->ImgSmooth,NULL,2); /** Threshold the Image **/ TICTOC::timer().tic("cvThreshold"); cvThreshold(Worm->ImgSmooth,Worm->ImgThresh,Params->BinThresh,255,CV_THRESH_BINARY ); TICTOC::timer().toc("cvThreshold"); /** Dilate and Erode **/ if (Params->DilateErode==1){ TICTOC::timer().tic("DilateAndErode"); cvDilate(Worm->ImgThresh, Worm->ImgThresh,NULL,3); cvErode(Worm->ImgThresh, Worm->ImgThresh,NULL,2); TICTOC::timer().toc("DilateAndErode"); } /** Find Contours **/ CvSeq* contours; IplImage* TempImage=cvCreateImage(cvGetSize(Worm->ImgThresh),IPL_DEPTH_8U,1); cvCopy(Worm->ImgThresh,TempImage); TICTOC::timer().tic("cvFindContours"); cvFindContours(TempImage,Worm->MemStorage, &contours,sizeof(CvContour),CV_RETR_EXTERNAL,CV_CHAIN_APPROX_NONE,cvPoint(0,0)); TICTOC::timer().toc("cvFindContours"); CvSeq* rough; /** Find Longest Contour **/ TICTOC::timer().tic("cvLongestContour"); if (contours) LongestContour(contours,&rough); TICTOC::timer().toc("cvLongestContour"); cvReleaseImage(&TempImage); /** Smooth the Boundary **/ if (Params->BoundSmoothSize>0){ TICTOC::timer().tic("SmoothBoundary"); CvSeq* smooth=smoothPtSequence(rough,Params->BoundSmoothSize,Worm->MemStorage); Worm->Boundary=cvCloneSeq(smooth); TICTOC::timer().toc("SmoothBoundary"); } else { Worm->Boundary=cvCloneSeq(rough); } }