Exemplo n.º 1
0
bool consensus_skeleton(vector<NeuronTree> & nt_list, QList<NeuronSWC> & merge_result, int method_code,V3DPluginCallback2 &callback)
{


    double CLUSTERING_RANGE =10;
    //potentially, there are invalid neuron trees (massive node points, no node points, looping)
    remove_outliers(nt_list);
    int neuronNum = nt_list.size();

    //initialize the image volume to record/accumulate the  location votes from neurons
    MyBoundingBox bbUnion = neuron_trees_bb(nt_list);

    Point3D offset = {bbUnion.min_x ,bbUnion.min_y ,bbUnion.min_z };
    float closeness = 1.0;
    V3DLONG  sz_x = ceil((bbUnion.max_x - bbUnion.min_x ) / closeness) +1; //+0.5 to round up from float to V3DLONG
    V3DLONG  sz_y = ceil((bbUnion.max_y - bbUnion.min_y ) / closeness) +1;
    V3DLONG  sz_z = ceil((bbUnion.max_z - bbUnion.min_z ) / closeness) +1;
    V3DLONG  tol_sz = sz_x * sz_y * sz_z;
    cout << "image size = " << tol_sz<<": " <<sz_x<<"x "<<sz_y<<" x"<<sz_z<< endl;

    unsigned char * img1d = new unsigned char[tol_sz];
    for(V3DLONG i = 0; i < tol_sz; i++) img1d[i] = 0;

    //count
    for (int j =0; j < nt_list.size(); j++){
        NeuronTree nt = nt_list[j];
        for (int i =0; i < nt.listNeuron.size(); i++)
        {
            NeuronSWC node = nt.listNeuron.at(i);
            V3DLONG id_x = (node.x-offset.x) +0.5; //round up
            V3DLONG id_y = (node.y-offset.y) +0.5;
            V3DLONG id_z = (node.z-offset.z) +0.5;
            V3DLONG idx = id_z * (sz_x*sz_y) + id_y * sz_x + id_x;
            if (idx <tol_sz ){
                img1d[idx] ++ ;}
            else{
                cout <<"error idx" <<endl;
            }
        }
    }

    //for debug only
    Image4DSimple *image = new Image4DSimple();
    image->setData(img1d, sz_x, sz_y, sz_z, 1, V3D_UINT8);
    callback.saveImage(image, "./vote_count_image.v3draw");

    //non-maximum suppresion
     vector<Point3D>  node_list;
     vector<unsigned int>  vote_list;
     non_max_suppresion (img1d,sz_x,sz_y,sz_z,offset,node_list,vote_list,3);
     cout << "After non_max supression:"<< endl;
     cout << "number of nodes:"<< node_list.size() << endl;
     cout << "maximum votes:" << v_min(vote_list) << endl;
     cout << "minimum votes:" << v_max(vote_list) << endl;

     Image4DSimple *image2 = new Image4DSimple();
     image2->setData(img1d, sz_x, sz_y, sz_z, 1, V3D_UINT8);
     callback.saveImage(image2, "./nms_image.v3draw");


     // for debug: save node_list to check locations
     QList<NeuronSWC> locationTree;
     for (int i=0;i<node_list.size();i++)
     {
         NeuronSWC tmp;
         tmp.x = node_list[i].x;
         tmp.y = node_list[i].y;
         tmp.z = node_list[i].z;

         tmp.type = 2; //edge votes
         tmp.pn = -1;  //parent id, form the edge
         tmp.r = double(vote_list[i])/neuronNum*3; //*3 for visulaization
         tmp.n = i+1;

         locationTree.append(tmp);
     }
    export_listNeuron_2swc(locationTree, "./testlocation.swc");

    printf("(2). compute adjacency matrix (vote for edges).\n");


    double * adjMatrix;
    V3DLONG * plist;
    V3DLONG num_nodes = node_list.size();
    try{
        adjMatrix = new double[num_nodes*num_nodes];
        plist = new V3DLONG[num_nodes];
        for (V3DLONG i=0;i<num_nodes*num_nodes;i++) adjMatrix[i] = 0;
    }
    catch (...)
    {
        fprintf(stderr,"fail to allocate memory.\n");
        if (adjMatrix) {delete[] adjMatrix; adjMatrix=0;}
        if (plist) {delete[] plist; plist=0;}
        return false;
    }


    for (int i=0;i<neuronNum;i++)
    {
        QHash<V3DLONG, V3DLONG > nodeMap;
        for (V3DLONG j=0;j<nt_list[i].listNeuron.size();j++)
        {
            NeuronSWC s = nt_list[i].listNeuron.at(j);
            Point3D cur;
            cur.x = s.x;
            cur.y = s.y;
            cur.z = s.z;

            //find its nearest node
            V3DLONG node_id = -1;// this node does not exist
            double min_dis = CLUSTERING_RANGE; //threshold to ignore mapping  (too far away)
            for (V3DLONG ni = 0; ni <node_list.size(); ni++)
            {
                Point3D p = node_list[ni];
                double dis = PointDistance(p,cur);

                if (dis < min_dis){
                    min_dis = dis;
                    node_id = ni;
                }
            }
            if (node_id > -1){
                nodeMap.insert( j, node_id);
            }
        }
        //maps.push_back(nodeMap);


        for (V3DLONG j=0;j<nt_list[i].listNeuron.size();j++)
        {
            NeuronSWC cur = nt_list[i].listNeuron[j];
            // if (cur.pn<0) continue;
            V3DLONG n_id,pn_id;
            n_id = nodeMap[j];
            if (n_id > 0){
                V3DLONG pidx = cur.pn-1;//nt_list[i].hashNeuron.value(cur.pn);  // find the index in nueon_list

                pn_id = nodeMap[pidx];
                if (pn_id > 0){
                    adjMatrix[n_id*num_nodes + pn_id] += 1;
                    adjMatrix[pn_id*num_nodes + n_id] += 1;
                    //cout<<adjMatrix[n_id*num_nodes + pn_id] <<endl;

                }
            }
        }

    }


    if (method_code ==0 ){
        long rootnode =100;
        printf("(3). computing minimum-spanning tree.\n");

        //if (!mst_dij(adjMatrix, num_nodes, plist, rootnode))
        if (!mst_prim(adjMatrix, num_nodes, plist, rootnode))

        {
            fprintf(stderr,"Error in minimum spanning tree!\n");
            return false;
        }

        printf("(3). genearate consensus graph swc file by assign parents (form edges).\n");

       // code the edge votes into type for visualization
       //         graph: duplicate swc nodes are allowed to accomandate mutiple parents for the child node, no root id,
        merge_result.clear();
        for (V3DLONG i = 0;i <num_nodes;i ++)
        {
            V3DLONG p = plist[i];
            //cout <<p<<endl;
            unsigned int edgeVote = adjMatrix[i*num_nodes + p];

            NeuronSWC tmp;
            tmp.x = node_list[i].x;
            tmp.y = node_list[i].y;
            tmp.z = node_list[i].z;

            tmp.type = edgeVote; //edge votes
            tmp.pn = p + 1;  //parent id, form the edge
            tmp.r = double(vote_list[i])/double(neuronNum);
            tmp.n = i+1;

            merge_result.append(tmp);

        }
    }

//### output vertices ( node lcoations)
//    V3DLONG count = 0;
//    for (V3DLONG i=0;i<num_nodes;i++)
//    {
//            NeuronSWC tmp;
//            tmp.x = node_list[i].x;
//            tmp.y = node_list[i].y;
//            tmp.z = node_list[i].z;
//           // tmp.fea_val.push_back(vote_list[i]);  //location votes are coded into radius

//            tmp.type = 0; //vertices (soma)
//            tmp.pn = -1;  //parent id, no edge
//            tmp.r = double(vote_list[i])/double(neuronNum); //location votes are coded into radius
//            tmp.n = count +1; //id start from 1
//            merge_result.append(tmp);
//            count++;
//    }

//    //output edges, go through half of the symmetric matrix, not directed graph
//    for (V3DLONG row = 0;row <num_nodes;row ++)
//    {
//        for (V3DLONG col = row+1;col < num_nodes;col++){
//            unsigned int edgeVote = adjMatrix[row*num_nodes + col];
//            if (edgeVote > 1)
//            {
//                NeuronSWC tmp;
//                tmp.x = node_list[row].x;
//                tmp.y = node_list[row].y;
//                tmp.z = node_list[row].z;

//                tmp.type = edgeVote; //edge votes
//                tmp.pn = col + 1;  //parent id  , form the edge
//                tmp.r = double(vote_list[row])/double(neuronNum);
//                tmp.n = count+1;

//                merge_result.append(tmp);
//                count++;
//            }
//        }
//    }

    // alternative
  if  (method_code == 1){
        merge_result.clear();
        V3DLONG count = 0;
        for (V3DLONG i=0;i<num_nodes;i++)
        {
                NeuronSWC tmp;
                tmp.x = node_list[i].x;
                tmp.y = node_list[i].y;
                tmp.z = node_list[i].z;
               // tmp.fea_val.push_back(vote_list[i]);  //location votes are coded into radius

                tmp.type = 0; //vertices (soma)
                tmp.pn = -1;  //parent id, no edge
                tmp.r = double(vote_list[i])/double(neuronNum); //location votes are coded into radius
                tmp.n = count +1; //id start from 1
                merge_result.append(tmp);
                count++;
        }

        //output edges, go through half of the symmetric matrix, not directed graph
        for (V3DLONG row = 0;row <num_nodes;row ++)
        {
            for (V3DLONG col = row+1;col < num_nodes;col++){
                unsigned int edgeVote = adjMatrix[row*num_nodes + col];
                if (edgeVote > 0)
                {
                    if (merge_result[row].pn == -1)
                    {//exsiting isolated vertex, modify parent id
                        merge_result[row].type = edgeVote; //edge votes
                        merge_result[row].pn = col + 1;  //parent id  , form the edge
                        merge_result[row].r = double(vote_list[row])/double(neuronNum);
                    }
                    else{
                      //add new edge  , via duplication nodes with different parent id and edge votes
                        NeuronSWC tmp;
                        tmp.x = node_list[row].x;
                        tmp.y = node_list[row].y;
                        tmp.z = node_list[row].z;

                        tmp.type = edgeVote; //edge votes
                        tmp.pn = col + 1;  //parent id  , form the edge
                        tmp.r = double(vote_list[row])/double(neuronNum);
                        tmp.n = count+1;

                        merge_result.append(tmp);
                        count++;
                    }

                }
            }
        }


}
    if (adjMatrix) {delete[] adjMatrix; adjMatrix = 0;}
    if (plist) {delete[] plist; plist=0;}


    return true;
}
Exemplo n.º 2
0
//return a list of predictions ? Or a mask image? 
//  Also need numbers of cells, and centers of cells
//work on local maxima
//use different preprocessing, feature extraction etc.
//1d_dimension is ROIDImension + 1
//Note: be aware of the order x, y, z are passed to submethods.
unsigned char* CellClassifier::annotateAnImage(V3DPluginCallback &callback, v3dhandle win, Image4DSimple* image, int ch, int grid, int dimension_1d)
{

   	 std::vector <LocationSimple> detectedPos;
   	 LandmarkList markerList;
     long sx=image->sz0, sy=image->sz1, sz=image->sz2; 
     long pagesz=sx*sy;
     long channelsz=sx*sy*sz;

     //smoothed and get local maxima
     //sensitive gaussian filtering radius
     //  ??????? use distance transform image???????
     
     int Wx = dimension_1d, Wy = dimension_1d, Wz = dimension_1d;  
     unsigned char * filtered = gaussianfiltering(image->getRawData(), sx, sy, sz, Wx, Wy, Wz);
     
     unsigned char * flag_lm = check_localMaxima_ker(filtered, sx, sy, sz, 0);
     
     
     //unsigned char * flag_lm = check_localMaxima(callback, image, ch); //062110

     unsigned char *results = new unsigned char [channelsz]; //prediction results.
     if (!results)
     {
        printf("Fail to allocate memory.\n");
        return NULL;
     }
     unsigned char *clearFlag = new unsigned char [channelsz]; //prediction results.
     if (!clearFlag)
     {
        printf("Fail to allocate memory.\n");
        return NULL;
     }
 
     //get model from file
     //string modelfile = "test_svm_model.txt";
     struct svm_model * pmodel = pclassifier->loadSVMModel(); 

     int r = dimension_1d/2;
     int prediction;
     int total = 0, cellcount = 0;
 
     //use (a somehow more restrict) template matching for adding some candidates.
     bool candidateflag = false;
     long cubesize = dimension_1d*dimension_1d*dimension_1d;
     double sigmax = (dimension_1d-1)/4.0, sigmay = (dimension_1d-1)/4.0, sigmaz = (dimension_1d-1)/4.0;
     double *g_1d = genGaussianKernel1D(dimension_1d, dimension_1d, dimension_1d, sigmax, sigmay, sigmaz);
     double curcoeff;
     //double coeff_th = 0.66; //will use average coeff of positive ones from training!!!!
     
     //init results
     for(long iz = 0; iz < sz; iz++)
     {
        long offsetk = iz*sx*sy;
        for(long iy = 0; iy < sy; iy++)
        {
            long offsetj = iy*sx;
            for(long ix = 0; ix < sx; ix++)
            {
               long idx = offsetk + offsetj + ix;
               results[idx] = 0;
               clearFlag[idx] = 1; //will be cleared later
             }
        }    
     }     

     //start search     
     int denied = 0;
     for(long iz = r; iz < sz-r; iz++)
     {
        long offsetk = iz*sx*sy;
        for(long iy = r; iy < sy-r; iy++)
        {
            long offsetj = iy*sx;
            for(long ix = r; ix < sx-r; ix++)
            {
               long idx = offsetk + offsetj + ix;
 
               //debug:
               //if(ix == 61 && iy==39 && iz==17) cout << "the missed one is here!!" << (int) flag_lm[idx] << endl;
               //if(ix == 63 && iy ==43 && iz ==16) cout << "the valley one (#3) is here!!" << (int) flag_lm[idx] << endl;;
               //if(ix == 65 && iy ==43 && iz ==14) cout << "the valley start point is here!!" << (int) flag_lm[idx] << endl;;

               if(flag_lm[idx] == 255 && clearFlag[idx] == 1 ) //only work on local maxima (and not cleared)
               {
                 //classify to see if it is a center               
                 prediction = classifyAVoxel(image, ch, iz, iy, ix, dimension_1d, pmodel); 
                                       
                 if(prediction == 0)
                    denied ++;
                  
                 candidateflag  = false;

                 if (prediction == 1 || candidateflag)
                 {
                   //cellcount ++;             
                   //results[idx] =  255; 
                   //
                  double ncx, ncy, ncz;
  
                  unsigned char * currentCube =getACube(image, ch, iz, iy, ix, dimension_1d, dimension_1d*dimension_1d, pagesz, channelsz); //fixed a bug 060210
                  curcoeff = coeff(currentCube, g_1d, cubesize);
 
                   //debug
                  if(ix == 65 && iy ==43 && iz ==14) 
                    std::cout << "coeff at valley:" << curcoeff << std::endl ;         
 
                  delete[] currentCube;
                   //if(curcoeff < 0.45)
                   //{
                    //  std::cout << "coeff too low for (" << ix << " " << iy << " " << iz << ") " << " coef: " << curcoeff << endl;                               
                    //  continue;
                   //}

                   //converge toward center of mass, 
                   
                   //move the center using highest score (either matching or classifier). 
                   /*
                   getMatchingCenter(image, ix, iy, iz, r, ch, ncx, ncy, ncz, flag_lm);
                   double nncx, nncy, nncz;
                   //getMassCenter(image, ncx, ncy, ncz, r, ch, nncx, nncy, nncz, flag_lm);
                   getMassCenter(filtered, sx,sy,sz, ncx, ncy, ncz, r, ch, nncx, nncy, nncz, flag_lm);
                   int newx = (int) (nncx+0.5), newy = (int) (nncy+0.5), newz = (int) (nncz+0.5); //rounding
                   */
                   
                   getMassCenter(filtered, sx,sy,sz, ix, iy, iz, r, ch, ncx, ncy, ncz, flag_lm);
                   int newx = (int) (ncx+0.5), newy = (int) (ncy+0.5), newz = (int) (ncz+0.5); //rounding
                   
                   //make a final decision if, after moving, there is a close neighbor identified already on the new spot
                   if (nearACenter(newx, newy, newz, results, r, sx, sy, sz))
                   {
                     // std::cout << "#" << cellcount << ", there's 1 nearby. Skip. " ;                   
                      continue;
                   }

                   long foundidx = newz*sx*sy + newy*sx + newx;
 
                   //check if move to a lm , possible for valley area between cells.
                   //why this made the debug image has 20 down to 9 cells!!
                   /*if ( flag_lm[foundidx] == 0)
                   {
                      std::cout << "non-lm. Skip. " ;                   
                      continue;
                   }*/
 
                   //else: a cell is found, set that to 255
                   results[foundidx] =  255; 

                   //remove foreground around that center from image: based on radius? reestimate based on std?
                   //int testt=0; for(int lll =0; lll < channelsz; lll++) if (flag_lm[lll] ==255) testt ++;
                   //cout << "postive flags: " << testt << endl;
                   //will not consider its neighbors in the future.
                   clearSurrounding(image, ch, newx, newy, newz, r, clearFlag);
                   //testt=0; for(int lll =0; lll < channelsz; lll++) if (flag_lm[lll] ==255) testt ++;
                   //cout << "postive flags after: " << testt << endl;

                   //increase cell counter by 1.
                   LocationSimple pp(newx, newy, newz);
                   detectedPos.push_back(pp);
                   LocationSimple marker(newx +1, newy +1, newz +1); //convert back to 1-base
                   marker.radius = r;
                   markerList.push_back(marker);               
                   
                   cellcount ++;
                   
                  }
                   
               }//end local maxima
          }//end ix
        }//end iy
     }//end iz
     
     std::cout << "total number of cells:" << cellcount << std::endl;
     
     
     char buf[30]; 
     itoa(cellcount, buf, 10);
     string resstring = "total cells:";
     resstring.append(buf);
     QMessageBox::information(0, "debug", QString(resstring.c_str()));
     
     std::cout << "total denied local maximum:" << denied << std::endl;
     
     svm_destroy_model(pmodel);
     
     /* //results only
     Image4DSimple p4DImage;
     p4DImage.setData(results, sx, sy, sz, 1, image->datatype);
     v3dhandle newwin = callback.newImageWindow();
     callback.setImage(newwin, &p4DImage);
     callback.setImageName(newwin,  "prediction results image");
     callback.updateImageWindow(newwin);
     */
     
     //v3d does not allow me to use the same image data in a different (new) window?
     //I need to make a copy of the data first?
     unsigned char *newimage1d = new unsigned char [channelsz]; 
     if(!newimage1d)  
     { 
        std::cout << "not enough memory to create result window";
        return results;
     } 
     unsigned char* image1d = image->getRawData();  
     for(long n = 0; n < channelsz; n++)
        newimage1d[n] = image1d[ch*channelsz + n];
     
     //show resulting cell markers  in a new window   
     Image4DSimple newImage;
     newImage.setData(newimage1d, sx, sy, sz, 1, image->datatype);
     v3dhandle newwin = callback.newImageWindow();
     callback.setImage(newwin, &newImage);
 	 callback.setImageName(newwin, "cell_counted");
	 callback.updateImageWindow(newwin);
	 callback.setLandmark(newwin, markerList); 


    //de-alloc
     //should I close svm file here???
     if(filtered)  { std::cout << "clean up memory for filtered image." << endl;  delete[] filtered; }
     if(flag_lm)   { std::cout << "clean up memory for local maximum." << endl;  delete[] flag_lm;  }   
     if(clearFlag) { std::cout << "clean up memory for flags." << endl;  delete[] clearFlag; }
     
     return results;
    
}
Exemplo n.º 3
0
bool findedgeimg(V3DPluginCallback2 &callback, const V3DPluginArgList & input, V3DPluginArgList & output)
{
    cout<<"Welcome to Label edge of a mask image"<<endl;
    if (output.size() != 1) return false;

    int method_code = 0;
    if (input.size()>=2)
    {
        vector<char*> paras = (*(vector<char*> *)(input.at(1).p));
        if(paras.size() >= 1) method_code = atoi(paras.at(0));
    }

    char * inimg_file = ((vector<char*> *)(input.at(0).p))->at(0);
    char * outimg_file = ((vector<char*> *)(output.at(0).p))->at(0);
    cout<<"method_code = "<<method_code<<endl;
    cout<<"inimg_file = "<<inimg_file<<endl;
    cout<<"outimg_file = "<<outimg_file<<endl;

    Image4DSimple *image = callback.loadImage(inimg_file);
    if (!image || !image->valid())
    {
        cerr<<"load image "<<inimg_file<<" error!"<<endl;
        return false;
    }

    V3DLONG szx=image->getXDim(),
            szy=image->getYDim(),
            szz=image->getZDim(),
            szc=image->getCDim();
    V3DLONG N = image->getTotalUnitNumber();

    //create the output buffer
    unsigned char *outputData = 0;
    try
    {
        outputData = new unsigned char [N];
        for (V3DLONG tmpi=0; tmpi<N; ++tmpi) outputData[tmpi] = 0; //preset to be all 0
    }
    catch (...)
    {
        v3d_msg("Fail to allocate memory.");
        if (outputData) {
            delete []outputData;
            outputData=0;
        }
        return false;
    }

    Image4DSimple outputImage;
    outputImage.setData((unsigned char*)outputData, szx, szy, szz, szc, V3D_UINT8);
    Image4DProxy<Image4DSimple> outputIProxy(&outputImage);

    //now do computation
    {
        bool bset255 = (method_code==0) ? false : true;

        Image4DProxy<Image4DSimple> p(image);
        Image4DProxy_foreach(p, ix, iy, iz, ic)
        {
            double v = p.value_at(ix, iy, iz, ic);
            V3DLONG cx, cy, cz;

            bool bb=false;
            for (cz = iz-1; cz<iz+2; ++cz)
            {
                for (cy = iy-1; cy<iy+2; ++cy)
                {
                    for (cx = ix-1; cx<ix+2; ++cx)
                    {
                        if (!p.is_inner(cx, cy, cz, ic))
                            continue;
                        if (v!=p.value_at(cx, cy, cz, ic))
                        {
                            *outputIProxy.at(ix, iy, iz, ic) = (bset255) ? 255 : v;
                            bb = true;
                            break;
                        }
                    }
                    if (bb)	break;
                }
                if (bb) break;
            }

            //note that all value had been preset as 0, thus no need to set as the background color in case not an edge point
        }
    }