コード例 #1
0
/*!
 * \brief attributes Fill _attributes with last computed items. Must be called after process.
 * \param _attributes Output attributes.*/
void ContourManager::attributes(Attributes & _attributes) const
{
    _attributes.flags = m_lastFlags;

    if (m_lastFlags & SFHierarchy)
        contours(_attributes.contours,_attributes.hierarchy);
    else
        contours(_attributes.contours);

    if (m_lastFlags & SFBoundings)
        boundingRects(_attributes.boundings);

    if (m_lastFlags & SFMassCenters)
        massCenters(_attributes.massCenters);
}//attributes
コード例 #2
0
ファイル: DrawContoursTest.cpp プロジェクト: joccccc/stromx
 void DrawContoursTest::testInPlace1()
 {
     m_operator->initialize();
     m_operator->activate();
     
     runtime::DataContainer img(new cvsupport::Image("lenna.jpg"));
     runtime::Data* contoursItem = 0;
     std::vector<runtime::Data*> contoursVector;
     contoursItem = new cvsupport::Matrix("contour_1.npy");
     contoursVector.push_back(contoursItem);
     contoursItem = new cvsupport::Matrix("contour_2.npy");
     contoursVector.push_back(contoursItem);
     runtime::DataContainer contours(new runtime::List(contoursVector));
     
     runtime::UInt8 ch1(255);
     runtime::UInt8 ch2(0);
     runtime::UInt8 ch3(0);
     runtime::Int32 thickness(-1);
     
     m_operator->setInputData(DrawContours::IMG, img);
     m_operator->setInputData(DrawContours::CONTOURS, contours);
     m_operator->setParameter(DrawContours::CH_1, ch1);
     m_operator->setParameter(DrawContours::CH_2, ch2);
     m_operator->setParameter(DrawContours::CH_3, ch3);
     m_operator->setParameter(DrawContours::THICKNESS, thickness);
     
     runtime::DataContainer imgResult = m_operator->getOutputData(DrawContours::IMG);
     
     runtime::ReadAccess imgAccess(imgResult);
     cvsupport::Image::save("DrawContoursTest_testInPlace1_img.png", imgAccess.get<runtime::Image>());
 }
コード例 #3
0
cv::Mat ManualTracker::generateMarkersForFrame(int fnum, cv::Size fsize)
{
    std::map<int, std::vector<double> > cells;
    cv::Mat markers(fsize, CV_32S, cv::Scalar::all(0));

    try {
        cells = (sp->getAllCells()).at(fnum);
    } catch (const std::out_of_range& oor) {
        std::cerr << "Out of Range error: " << oor.what() << '\n';
        return markers;
    }

    std::vector< std::vector<cv::Point2f> > contours(1);

    for (std::map<int, std::vector<double> >::iterator it=cells.begin();
         it!=cells.end(); ++it) {
        std::vector<double> curCell = it->second;
        cv::Point2f center(curCell[3], curCell[4]);
        cv::Size2f size(curCell[6], curCell[5]);
        cv::RotatedRect box(center, size, curCell[8]);
        cv::Point2f vertices[4];
        box.points(vertices);
        cv::Point2i intVertices[4];
        for (int i=0; i<4; i++) {
            intVertices[i].x = vertices[i].x;
            intVertices[i].y = vertices[i].y;
        }
        cv::fillConvexPoly(markers, intVertices, 4, curCell[0]);
    }

    return markers;
}
コード例 #4
0
ファイル: FrontierDetector.cpp プロジェクト: Nsteel/Apollo_13
FrontierDetector::FrontierDetector(const int freeColor, const int unknownColor, const int occupiedColor) :
        freeColor(freeColor), unknownColor(unknownColor), occupiedColor(occupiedColor){
        dilateRate = 0;
        blurKernel = 0;
        detectedFrontiers = contours();

}
コード例 #5
0
int FTVectoriser::points()
{
  int s = 0;
  for( size_t c = 0; c < contours(); ++c)
  {
    s += contourList[c]->size();
  }
  
  return s;
}
コード例 #6
0
ファイル: FrontierDetector.cpp プロジェクト: Nsteel/Apollo_13
void FrontierDetector::findFrontiers(){
        detectedFrontiers = contours();
        std::vector<cv::Vec4i> hierarchy = std::vector<cv::Vec4i>();

        //inflate edges to merge micro edges and small gaps
        if(config.frontier_inflate_frontiers) {
                cv::dilate(floating_edges, floating_edges, cv::Mat());
        }
        cv::findContours(floating_edges, detectedFrontiers, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);

}
コード例 #7
0
FTVectoriser::~FTVectoriser()
{
  for( size_t c = 0; c < contours(); ++c)
  {
    delete contourList[c];
  }

  contourList.clear();
  
  if( mesh)
    delete mesh;
}
コード例 #8
0
void FTVectoriser::MakeMesh( FTGL_DOUBLE zNormal)
{
  if( mesh)
  {
    delete mesh;
  }
    
  mesh = new FTMesh;
  
  GLUtesselator* tobj = gluNewTess();
  
  gluTessCallback( tobj, GLU_TESS_BEGIN_DATA,    (ftglCallback)ftglBegin);
  gluTessCallback( tobj, GLU_TESS_VERTEX_DATA,  (ftglCallback)ftglVertex);
  gluTessCallback( tobj, GLU_TESS_COMBINE_DATA,  (ftglCallback)ftglCombine);
  gluTessCallback( tobj, GLU_TESS_END_DATA,    (ftglCallback)ftglEnd);
  gluTessCallback( tobj, GLU_TESS_ERROR_DATA,    (ftglCallback)ftglError);
  
  
  if( contourFlag & ft_outline_even_odd_fill) // ft_outline_reverse_fill
  {
    gluTessProperty( tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD);
  }
  else
  {
    gluTessProperty( tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO);
  }
  
  
  gluTessProperty( tobj, GLU_TESS_TOLERANCE, 0);
  gluTessNormal( tobj, 0.0, 0.0, zNormal);
  gluTessBeginPolygon( tobj, mesh);
  
    for( size_t c = 0; c < contours(); ++c)
    {
      const FTContour* acontour = contourList[c];
      gluTessBeginContour( tobj);
      
        for( size_t p = 0; p < acontour->size(); ++p)
        {
          FTGL_DOUBLE* d = const_cast<FTGL_DOUBLE*>(&acontour->pointList[p].x);
          gluTessVertex( tobj, d, d);
        }
      gluTessEndContour( tobj);
    }
    
  gluTessEndPolygon( tobj);

  gluDeleteTess( tobj);
  
}
コード例 #9
0
void FTVectoriser::GetOutline( FTGL_DOUBLE* data)
{
  int i = 0;
  
  for( size_t c= 0; c < contours(); ++c)
  {
    const FTContour* acontour = contourList[c];
    
    for( size_t p = 0; p < acontour->size(); ++p)
    {
      data[i] = static_cast<FTGL_DOUBLE>(acontour->pointList[p].x / 64.0f); // is 64 correct?
      data[i + 1] = static_cast<FTGL_DOUBLE>(acontour->pointList[p].y / 64.0f);
      data[i + 2] = 0.0; // static_cast<FTGL_DOUBLE>(acontour->pointList[p].z / 64.0f);
      i += 3;
    }
  }
}
コード例 #10
0
ファイル: main.cpp プロジェクト: Ensiss/pima-embarque
void exemple(cv::VideoCapture capture)
{
	cv::Mat frame, copie;
	char key;
	
	while(key != 'q')
	{
        std::cout << "frame" << std::endl;
		std::vector<cv::Rect> triangles, squares;
		capture >> frame;
		copie = frame.clone();
		contours(copie);
		for(unsigned int i = 0; i < squares.size(); i++)
		{
			for(unsigned int j = 0; j < triangles.size(); j++)
			{
				if(contient(squares[i], triangles[j]))
                    std::cout << "Face détectée, coin haut gauche : " << squares[i].tl() << "coin bas droit : " << squares[i].br() << std::endl;
			}
		}
		key = cv::waitKey(1);
	}
	return;
}
コード例 #11
0
ファイル: PerimeterGenerator.cpp プロジェクト: 2bright/Slic3r
void
PerimeterGenerator::process()
{
    // other perimeters
    this->_mm3_per_mm           = this->perimeter_flow.mm3_per_mm();
    coord_t pwidth              = this->perimeter_flow.scaled_width();
    coord_t pspacing            = this->perimeter_flow.scaled_spacing();
    
    // external perimeters
    this->_ext_mm3_per_mm       = this->ext_perimeter_flow.mm3_per_mm();
    coord_t ext_pwidth          = this->ext_perimeter_flow.scaled_width();
    coord_t ext_pspacing        = this->ext_perimeter_flow.scaled_spacing();
    coord_t ext_pspacing2       = this->ext_perimeter_flow.scaled_spacing(this->perimeter_flow);
    
    // overhang perimeters
    this->_mm3_per_mm_overhang  = this->overhang_flow.mm3_per_mm();
    
    // solid infill
    coord_t ispacing            = this->solid_infill_flow.scaled_spacing();
    coord_t gap_area_threshold  = pwidth * pwidth;
    
    // Calculate the minimum required spacing between two adjacent traces.
    // This should be equal to the nominal flow spacing but we experiment
    // with some tolerance in order to avoid triggering medial axis when
    // some squishing might work. Loops are still spaced by the entire
    // flow spacing; this only applies to collapsing parts.
    // For ext_min_spacing we use the ext_pspacing calculated for two adjacent
    // external loops (which is the correct way) instead of using ext_pspacing2
    // which is the spacing between external and internal, which is not correct
    // and would make the collapsing (thus the details resolution) dependent on 
    // internal flow which is unrelated.
    coord_t min_spacing         = pspacing      * (1 - INSET_OVERLAP_TOLERANCE);
    coord_t ext_min_spacing     = ext_pspacing  * (1 - INSET_OVERLAP_TOLERANCE);
    
    // prepare grown lower layer slices for overhang detection
    if (this->lower_slices != NULL && this->config->overhangs) {
        // We consider overhang any part where the entire nozzle diameter is not supported by the
        // lower layer, so we take lower slices and offset them by half the nozzle diameter used 
        // in the current layer
        double nozzle_diameter = this->print_config->nozzle_diameter.get_at(this->config->perimeter_extruder-1);
        
        this->_lower_slices_p = offset(*this->lower_slices, scale_(+nozzle_diameter/2));
    }
    
    // we need to process each island separately because we might have different
    // extra perimeters for each one
    for (Surfaces::const_iterator surface = this->slices->surfaces.begin();
        surface != this->slices->surfaces.end(); ++surface) {
        // detect how many perimeters must be generated for this island
        signed short loop_number = this->config->perimeters + surface->extra_perimeters;
        loop_number--;  // 0-indexed loops
        
        Polygons gaps;
        
        Polygons last = surface->expolygon.simplify_p(SCALED_RESOLUTION);
        if (loop_number >= 0) {  // no loops = -1
            
            std::vector<PerimeterGeneratorLoops> contours(loop_number+1);    // depth => loops
            std::vector<PerimeterGeneratorLoops> holes(loop_number+1);       // depth => loops
            Polylines thin_walls;
            
            // we loop one time more than needed in order to find gaps after the last perimeter was applied
            for (signed short i = 0; i <= loop_number+1; ++i) {  // outer loop is 0
                Polygons offsets;
                if (i == 0) {
                    // the minimum thickness of a single loop is:
                    // ext_width/2 + ext_spacing/2 + spacing/2 + width/2
                    if (this->config->thin_walls) {
                        offsets = offset2(
                            last,
                            -(ext_pwidth/2 + ext_min_spacing/2 - 1),
                            +(ext_min_spacing/2 - 1)
                        );
                    } else {
                        offsets = offset(last, -ext_pwidth/2);
                    }
                    
                    // look for thin walls
                    if (this->config->thin_walls) {
                        Polygons diffpp = diff(
                            last,
                            offset(offsets, +ext_pwidth/2),
                            true  // medial axis requires non-overlapping geometry
                        );
                        
                        // the following offset2 ensures almost nothing in @thin_walls is narrower than $min_width
                        // (actually, something larger than that still may exist due to mitering or other causes)
                        coord_t min_width = ext_pwidth / 2;
                        ExPolygons expp = offset2_ex(diffpp, -min_width/2, +min_width/2);
                        
                        // the maximum thickness of our thin wall area is equal to the minimum thickness of a single loop
                        Polylines pp;
                        for (ExPolygons::const_iterator ex = expp.begin(); ex != expp.end(); ++ex)
                            ex->medial_axis(ext_pwidth + ext_pspacing2, min_width, &pp);
                        
                        double threshold = ext_pwidth * 2;
                        for (Polylines::const_iterator p = pp.begin(); p != pp.end(); ++p) {
                            if (p->length() > threshold) {
                                thin_walls.push_back(*p);
                            }
                        }
                        
                        #ifdef DEBUG
                        printf("  %zu thin walls detected\n", thin_walls.size());
                        #endif
                        
                        /*
                        if (false) {
                            require "Slic3r/SVG.pm";
                            Slic3r::SVG::output(
                                "medial_axis.svg",
                                no_arrows       => 1,
                                #expolygons      => \@expp,
                                polylines       => \@thin_walls,
                            );
                        }
                        */
                    }
                } else {
                    coord_t distance = (i == 1) ? ext_pspacing2 : pspacing;
                    
                    if (this->config->thin_walls) {
                        offsets = offset2(
                            last,
                            -(distance + min_spacing/2 - 1),
                            +(min_spacing/2 - 1)
                        );
                    } else {
                        offsets = offset(
                            last,
                            -distance
                        );
                    }
                    
                    // look for gaps
                    if (this->config->gap_fill_speed.value > 0 && this->config->fill_density.value > 0) {
                        // not using safety offset here would "detect" very narrow gaps
                        // (but still long enough to escape the area threshold) that gap fill
                        // won't be able to fill but we'd still remove from infill area
                        ExPolygons diff_expp = diff_ex(
                            offset(last, -0.5*distance),
                            offset(offsets, +0.5*distance + 10)  // safety offset
                        );
                        for (ExPolygons::const_iterator ex = diff_expp.begin(); ex != diff_expp.end(); ++ex) {
                            if (fabs(ex->area()) >= gap_area_threshold) {
                                Polygons pp = *ex;
                                gaps.insert(gaps.end(), pp.begin(), pp.end());
                            }
                        }
                    }
                }
                
                if (offsets.empty()) break;
                if (i > loop_number) break; // we were only looking for gaps this time
                
                last = offsets;
                for (Polygons::const_iterator polygon = offsets.begin(); polygon != offsets.end(); ++polygon) {
                    PerimeterGeneratorLoop loop(*polygon, i);
                    loop.is_contour = polygon->is_counter_clockwise();
                    if (loop.is_contour) {
                        contours[i].push_back(loop);
                    } else {
                        holes[i].push_back(loop);
                    }
                }
            }
            
            // nest loops: holes first
            for (signed short d = 0; d <= loop_number; ++d) {
                PerimeterGeneratorLoops &holes_d = holes[d];
                
                // loop through all holes having depth == d
                for (signed short i = 0; i < holes_d.size(); ++i) {
                    const PerimeterGeneratorLoop &loop = holes_d[i];
                    
                    // find the hole loop that contains this one, if any
                    for (signed short t = d+1; t <= loop_number; ++t) {
                        for (signed short j = 0; j < holes[t].size(); ++j) {
                            PerimeterGeneratorLoop &candidate_parent = holes[t][j];
                            if (candidate_parent.polygon.contains(loop.polygon.first_point())) {
                                candidate_parent.children.push_back(loop);
                                holes_d.erase(holes_d.begin() + i);
                                --i;
                                goto NEXT_LOOP;
                            }
                        }
                    }
                    
                    // if no hole contains this hole, find the contour loop that contains it
                    for (signed short t = loop_number; t >= 0; --t) {
                        for (signed short j = 0; j < contours[t].size(); ++j) {
                            PerimeterGeneratorLoop &candidate_parent = contours[t][j];
                            if (candidate_parent.polygon.contains(loop.polygon.first_point())) {
                                candidate_parent.children.push_back(loop);
                                holes_d.erase(holes_d.begin() + i);
                                --i;
                                goto NEXT_LOOP;
                            }
                        }
                    }
                    NEXT_LOOP: ;
                }
            }
        
            // nest contour loops
            for (signed short d = loop_number; d >= 1; --d) {
                PerimeterGeneratorLoops &contours_d = contours[d];
                
                // loop through all contours having depth == d
                for (signed short i = 0; i < contours_d.size(); ++i) {
                    const PerimeterGeneratorLoop &loop = contours_d[i];
                
                    // find the contour loop that contains it
                    for (signed short t = d-1; t >= 0; --t) {
                        for (signed short j = 0; j < contours[t].size(); ++j) {
                            PerimeterGeneratorLoop &candidate_parent = contours[t][j];
                            if (candidate_parent.polygon.contains(loop.polygon.first_point())) {
                                candidate_parent.children.push_back(loop);
                                contours_d.erase(contours_d.begin() + i);
                                --i;
                                goto NEXT_CONTOUR;
                            }
                        }
                    }
                    
                    NEXT_CONTOUR: ;
                }
            }
        
            // at this point, all loops should be in contours[0]
            
            ExtrusionEntityCollection entities = this->_traverse_loops(contours.front(), thin_walls);
            
            // if brim will be printed, reverse the order of perimeters so that
            // we continue inwards after having finished the brim
            // TODO: add test for perimeter order
            if (this->config->external_perimeters_first
                || (this->layer_id == 0 && this->print_config->brim_width.value > 0))
                    entities.reverse();
            
            // append perimeters for this slice as a collection
            if (!entities.empty())
                this->loops->append(entities);
        }
        
        // fill gaps
        if (!gaps.empty()) {
            /*
            if (false) {
                require "Slic3r/SVG.pm";
                Slic3r::SVG::output(
                    "gaps.svg",
                    expolygons => union_ex(\@gaps),
                );
            }
            */
            
            // where $pwidth < thickness < 2*$pspacing, infill with width = 2*$pwidth
            // where 0.1*$pwidth < thickness < $pwidth, infill with width = 1*$pwidth
            std::vector<PerimeterGeneratorGapSize> gap_sizes;
            gap_sizes.push_back(PerimeterGeneratorGapSize(pwidth, 2*pspacing, 2*pwidth));
            gap_sizes.push_back(PerimeterGeneratorGapSize(0.1*pwidth, pwidth, 1*pwidth));
            
            for (std::vector<PerimeterGeneratorGapSize>::const_iterator gap_size = gap_sizes.begin();
                gap_size != gap_sizes.end(); ++gap_size) {
                ExtrusionEntityCollection gap_fill = this->_fill_gaps(gap_size->min, 
                    gap_size->max, unscale(gap_size->width), gaps);
                this->gap_fill->append(gap_fill.entities);
                
                // Make sure we don't infill narrow parts that are already gap-filled
                // (we only consider this surface's gaps to reduce the diff() complexity).
                // Growing actual extrusions ensures that gaps not filled by medial axis
                // are not subtracted from fill surfaces (they might be too short gaps
                // that medial axis skips but infill might join with other infill regions
                // and use zigzag).
                coord_t dist = gap_size->width/2;
                Polygons filled;
                for (ExtrusionEntitiesPtr::const_iterator it = gap_fill.entities.begin();
                    it != gap_fill.entities.end(); ++it) {
                    Polygons f;
                    offset((*it)->as_polyline(), &f, dist);
                    filled.insert(filled.end(), f.begin(), f.end());
                }
                last = diff(last, filled);
                gaps = diff(gaps, filled);  // prevent more gap fill here
            }
        }
        
        // create one more offset to be used as boundary for fill
        // we offset by half the perimeter spacing (to get to the actual infill boundary)
        // and then we offset back and forth by half the infill spacing to only consider the
        // non-collapsing regions
        coord_t inset = 0;
        if (loop_number == 0) {
            // one loop
            inset += ext_pspacing2/2;
        } else if (loop_number > 0) {
            // two or more loops
            inset += pspacing/2;
        }
        
        // only apply infill overlap if we actually have one perimeter
        if (inset > 0)
            inset -= this->config->get_abs_value("infill_overlap", inset + ispacing/2);
        
        {
            ExPolygons expp = union_ex(last);
            
            // simplify infill contours according to resolution
            Polygons pp;
            for (ExPolygons::const_iterator ex = expp.begin(); ex != expp.end(); ++ex)
                ex->simplify_p(SCALED_RESOLUTION, &pp);
            
            // collapse too narrow infill areas
            coord_t min_perimeter_infill_spacing = ispacing * (1 - INSET_OVERLAP_TOLERANCE);
            expp = offset2_ex(
                pp,
                -inset -min_perimeter_infill_spacing/2,
                +min_perimeter_infill_spacing/2
            );
            
            // append infill areas to fill_surfaces
            for (ExPolygons::const_iterator ex = expp.begin(); ex != expp.end(); ++ex)
                this->fill_surfaces->surfaces.push_back(Surface(stInternal, *ex));  // use a bogus surface type
        }
    }
}
コード例 #12
0
void ContourManager::contours(ContourVector & _contours, Hierarchy & _hierarchy) const
{
    contours(_contours);
    _hierarchy = m_tempHierarchy;
}//contours
コード例 #13
0
ファイル: FrontierDetector.cpp プロジェクト: Nsteel/Apollo_13
FrontierDetector::FrontierDetector(const FrontierDetector& other) :
        freeColor(other.freeColor), unknownColor(other.unknownColor), occupiedColor(other.occupiedColor), config(other.config),
        dilateRate(other.dilateRate), blurKernel(other.blurKernel){
        detectedFrontiers = contours();
}
コード例 #14
0
int main(int argc, char **argv)
{
    struct GModule *module;
    struct Option *voutput_opt, *routput_opt, *color_output_opt, *ply_opt, *zrange_opt, *trim_opt, *rotate_Z_opt,
            *smooth_radius_opt, *region_opt, *raster_opt, *zexag_opt, *resolution_opt,
            *method_opt, *calib_matrix_opt, *numscan_opt, *trim_tolerance_opt,
            *contours_map, *contours_step_opt, *draw_opt, *draw_vector_opt, *draw_threshold_opt;
    struct Flag *loop_flag, *calib_flag, *equalize_flag;
    struct Map_info Map;
    struct line_pnts *Points;
    struct line_cats *Cats;
    int cat = 1;

    G_gisinit(argv[0]);

    module = G_define_module();
    G_add_keyword(_("vector"));
    G_add_keyword(_("scan"));
    G_add_keyword(_("points"));
    module->label = _("Imports a point cloud from Kinect v2");
    module->description = _("Imports a point cloud from Kinect v2");

    routput_opt = G_define_standard_option(G_OPT_R_OUTPUT);
    routput_opt->guisection = _("Output");
    routput_opt->required = NO;

    resolution_opt = G_define_option();
    resolution_opt->key = "resolution";
    resolution_opt->type = TYPE_DOUBLE;
    resolution_opt->required = NO;
    resolution_opt->answer = "0.002";
    resolution_opt->label = _("Raster resolution");
    resolution_opt->description = _("Recommended values between 0.001-0.003");
    resolution_opt->guisection = _("Output");

    color_output_opt = G_define_standard_option(G_OPT_R_BASENAME_OUTPUT);
    color_output_opt->key = "color_output";
    color_output_opt->description = _("Basename for color output");
    color_output_opt->guisection = _("Output");
    color_output_opt->required = NO;

    voutput_opt = G_define_standard_option(G_OPT_V_OUTPUT);
    voutput_opt->required = NO;
    voutput_opt->key = "vector";
    voutput_opt->guisection = _("Output");

    ply_opt = G_define_standard_option(G_OPT_F_OUTPUT);
    ply_opt->required = NO;
    ply_opt->key = "ply";
    ply_opt->description = _("Name of output binary PLY file");
    ply_opt->guisection = _("Output");

    zrange_opt = G_define_option();
    zrange_opt->key = "zrange";
    zrange_opt->type = TYPE_DOUBLE;
    zrange_opt->required = NO;
    zrange_opt->key_desc = "min,max";
    zrange_opt->label = _("Filter range for z data (min,max)");
    zrange_opt->description = _("Z is distance from scanner in cm");
    zrange_opt->guisection = _("Filter");

    trim_opt = G_define_option();
    trim_opt->key = "trim";
    trim_opt->type = TYPE_DOUBLE;
    trim_opt->required = NO;
    trim_opt->key_desc = "N,S,E,W";
    trim_opt->description = _("Clip box from center in cm");
    trim_opt->guisection = _("Filter");

    trim_tolerance_opt = G_define_option();
    trim_tolerance_opt->key = "trim_tolerance";
    trim_tolerance_opt->type = TYPE_DOUBLE;
    trim_tolerance_opt->required = NO;
    trim_tolerance_opt->description = _("Influences how much are model sides trimmed automatically, "
        " should be higher for rectangular models");
    trim_tolerance_opt->label = _("Trim tolerance between 0 and 1");
    trim_tolerance_opt->options = "0-1";
    trim_tolerance_opt->guisection = _("Filter");

    rotate_Z_opt = G_define_option();
    rotate_Z_opt->key = "rotate";
    rotate_Z_opt->type = TYPE_DOUBLE;
    rotate_Z_opt->required = NO;
    rotate_Z_opt->answer = "0";
    rotate_Z_opt->description = _("Rotate along Z axis");
    rotate_Z_opt->guisection = _("Georeferencing");

    smooth_radius_opt = G_define_option();
    smooth_radius_opt->key = "smooth_radius";
    smooth_radius_opt->type = TYPE_DOUBLE;
    smooth_radius_opt->required = NO;
    smooth_radius_opt->label = _("Smooth radius");
    smooth_radius_opt->description = _("Recommended values between 0.006-0.009");

    region_opt = G_define_option();
    region_opt->key = "region";
    region_opt->key_desc = "name";
    region_opt->required = NO;
    region_opt->multiple = NO;
    region_opt->type = TYPE_STRING;
    region_opt->description = _("Region of the resulting raster");
    region_opt->gisprompt = "old,windows,region";
    region_opt->guisection = _("Georeferencing");

    raster_opt = G_define_standard_option(G_OPT_R_MAP);
    raster_opt->key = "raster";
    raster_opt->required = NO;
    raster_opt->multiple = NO;
    raster_opt->description = _("Match resulting raster to this raster map");
    raster_opt->guisection = _("Georeferencing");

    zexag_opt = G_define_option();
    zexag_opt->key = "zexag";
    zexag_opt->type = TYPE_DOUBLE;
    zexag_opt->required = NO;
    zexag_opt->required = NO;
    zexag_opt->answer = "1";
    zexag_opt->description = _("Vertical exaggeration");
    zexag_opt->guisection = _("Georeferencing");

    method_opt = G_define_option();
    method_opt->key = "method";
    method_opt->multiple = NO;
    method_opt->required = NO;
    method_opt->type = TYPE_STRING;
    method_opt->options = "interpolation,mean,min,max";
    method_opt->answer = "mean";
    method_opt->description = _("Surface reconstruction method");

    calib_matrix_opt = G_define_option();
    calib_matrix_opt->key = "calib_matrix";
    calib_matrix_opt->multiple = YES;
    calib_matrix_opt->type = TYPE_DOUBLE;
    calib_matrix_opt->required = NO;
    calib_matrix_opt->description = _("Calibration matrix");
    calib_matrix_opt->guisection = _("Calibration");

    numscan_opt = G_define_option();
    numscan_opt->answer = "1";
    numscan_opt->key = "numscan";
    numscan_opt->type = TYPE_INTEGER;
    numscan_opt->description = _("Number of scans to intergrate");
    numscan_opt->required = NO;

    contours_map = G_define_standard_option(G_OPT_V_MAP);
    contours_map->key = "contours";
    contours_map->required = NO;
    contours_map->description = _("Name of contour vector map");

    contours_step_opt = G_define_option();
    contours_step_opt->key = "contours_step";
    contours_step_opt->description = _("Increment between contour levels");
    contours_step_opt->type = TYPE_DOUBLE;
    contours_step_opt->required = NO;

    equalize_flag = G_define_flag();
    equalize_flag->key = 'e';
    equalize_flag->description = _("Histogram equalized color table");

    loop_flag = G_define_flag();
    loop_flag->key = 'l';
    loop_flag->description = _("Keep scanning in a loop");

    calib_flag = G_define_flag();
    calib_flag->key = 'c';
    calib_flag->description = _("Calibrate");
    calib_flag->guisection = _("Calibration");

    draw_opt = G_define_option();
    draw_opt->key = "draw";
    draw_opt->description = _("Draw with laser pointer");
    draw_opt->type = TYPE_STRING;
    draw_opt->required = NO;
    draw_opt->options = "point,line,area";
    draw_opt->answer = "point";
    draw_opt->guisection = _("Drawing");

    draw_threshold_opt = G_define_option();
    draw_threshold_opt->key = "draw_threshold";
    draw_threshold_opt->description = _("Brightness threshold for detecting laser pointer");
    draw_threshold_opt->type = TYPE_INTEGER;
    draw_threshold_opt->required = YES;
    draw_threshold_opt->answer = "760";
    draw_threshold_opt->guisection = _("Drawing");

    draw_vector_opt = G_define_standard_option(G_OPT_V_OUTPUT);
    draw_vector_opt->key = "draw_output";
    draw_vector_opt->guisection = _("Drawing");
    draw_vector_opt->required = NO;

    G_option_required(calib_flag, routput_opt, voutput_opt, ply_opt, draw_vector_opt, NULL);
    G_option_requires(routput_opt, resolution_opt, NULL);
    G_option_requires(color_output_opt, resolution_opt, NULL);
    G_option_requires(contours_map, contours_step_opt, routput_opt, NULL);
    G_option_requires(equalize_flag, routput_opt, NULL);

    if (G_parser(argc, argv))
        exit(EXIT_FAILURE);

    // initailization of variables
    double resolution = 0.002;
    if (resolution_opt->answer)
        resolution = atof(resolution_opt->answer);
    double smooth_radius = 0.008;
    if (smooth_radius_opt->answer)
        smooth_radius = atof(smooth_radius_opt->answer);
    char* routput = NULL;
    if (routput_opt->answer)
        routput = routput_opt->answer;

    /* parse zrange */
    double zrange_min, zrange_max;
    if (zrange_opt->answer != NULL) {
        zrange_min = atof(zrange_opt->answers[0])/100;
        zrange_max = atof(zrange_opt->answers[1])/100;
    }

    /* parse trim */
    double clip_N, clip_S, clip_E, clip_W;
    if (trim_opt->answer != NULL) {
        clip_N = atof(trim_opt->answers[0])/100;
        clip_S = atof(trim_opt->answers[1])/100;
        clip_E = atof(trim_opt->answers[2])/100;
        clip_W = atof(trim_opt->answers[3])/100;
    }
    double trim_tolerance;
    if (trim_tolerance_opt->answer)
        trim_tolerance = atof(trim_tolerance_opt->answer);

    double angle = pcl::deg2rad(atof(rotate_Z_opt->answer) + 180);
    double zexag = atof(zexag_opt->answer);
    Eigen::Matrix4f transform_matrix;
    if (calib_matrix_opt->answer) {
        transform_matrix = read_matrix(calib_matrix_opt);
    }
    char *method = method_opt->answer;
    int numscan = atoi(numscan_opt->answer);
    char *color_output = color_output_opt->answer;
    char *voutput = voutput_opt->answer;
    char *ply = ply_opt->answer;
    char *contours_output = contours_map->answer;
    double contours_step;
    if (contours_output)
        contours_step = atof(contours_step_opt->answer);
    bool use_equalized = false;
    if (equalize_flag->answer)
        use_equalized = true;

    // drawing
    int vect_type;
    get_draw_type(draw_opt->answer, vect_type);
    int draw_threshold = atoi(draw_threshold_opt->answer);
    char* draw_output = NULL;
    if (draw_vector_opt->answer)
        draw_output = draw_vector_opt->answer;

    std::vector<double> draw_x;
    std::vector<double> draw_y;
    std::vector<double> draw_z;
    bool drawing = false;
    unsigned int last_detected_loop_count = 1e6;

    struct Map_info Map_draw;
    struct line_pnts *Points_draw;
    struct line_cats *Cats_draw;
    Points_draw = Vect_new_line_struct();
    Cats_draw = Vect_new_cats_struct();

    Points = Vect_new_line_struct();
    Cats = Vect_new_cats_struct();

    pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>(512, 424));
    pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_filtered_pass (new pcl::PointCloud<pcl::PointXYZRGB>(512, 424));

    struct bound_box bbox;
    struct Cell_head cellhd, window;
    double offset, scale;
    bool region3D = false;

    bool paused = false;

    update_input_region(raster_opt->answer, region_opt->answer, window, offset, region3D);


    K2G k2g(OPENGL);
    k2g.getCloud();
    cloud->sensor_orientation_.w() = 0.0;
    cloud->sensor_orientation_.x() = 1.0;
    cloud->sensor_orientation_.y() = 0.0;
    cloud->sensor_orientation_.z() = 0.0;
    int j = 0;
    // get terminating signals
    signal(SIGTERM, terminate);
    signal(SIGINT, terminate);
    signal(SIGUSR1, signal_read_new_input);
    while (j < 1) {
        if (signaled == 1) {
            break;
        }
        if (signal_new_input == 1) {
            signal_new_input = 0;
            read_new_input(routput, zrange_min, zrange_max, clip_N, clip_S, clip_E, clip_W,
                           trim_tolerance, angle, zexag, method, numscan, smooth_radius, resolution, use_equalized,
                           window, offset, region3D,
                           color_output, voutput, ply,
                           contours_output, contours_step,
                           vect_type, draw_threshold, draw_output, paused);
        }

        cloud = k2g.getCloud();
        if (paused) {
            continue;
        }
        if (!drawing) {
            for (int s = 0; s < numscan - 1; s++)
                *(cloud) += *(k2g.getCloud());
        }

        // remove invalid points
        std::vector<int> index_nans;

        pcl::removeNaNFromPointCloud(*cloud, *cloud, index_nans);

        // calibration
        if(calib_flag->answer) {
            calibrate(cloud);
            j++;
            continue;
        }
        // rotation of the point cloud based on calibration
        if (calib_matrix_opt->answer) {
            rotate_with_matrix(cloud, transform_matrix);
        }

        // trim Z
        if (zrange_opt->answer != NULL) {
            trim_Z(cloud, zrange_min, zrange_max);
        }

        // rotation Z
        rotate_Z(cloud, angle);

        // specify bounding box from center
        if (trim_opt->answer != NULL) {
            clipNSEW(cloud, clip_N, clip_S, clip_E, clip_W);
        }
        // drawing
        if (draw_output) {
            int maxbright = 0;
            int maxbright_idx = 0;
            for (int i=0; i < cloud->points.size(); i++) {
                Eigen::Vector3i rgbv = cloud->points[i].getRGBVector3i();
                int sum = rgbv[0] + rgbv[1] + rgbv[2];
                if (sum > maxbright) {
                    maxbright = sum;
                    maxbright_idx = i;
                }
            }
            if (maxbright >= draw_threshold) {
                drawing = true;
                draw_x.push_back(cloud->points[maxbright_idx].x);
                draw_y.push_back(cloud->points[maxbright_idx].y);
                draw_z.push_back(cloud->points[maxbright_idx].z);
                last_detected_loop_count = 0;
                continue;
            }
            else {
              last_detected_loop_count++;
              if (last_detected_loop_count <= 2) {
                  continue;
                }
            }
        }

        pcl::StatisticalOutlierRemoval<pcl::PointXYZRGB> sor;
        sor.setInputCloud(cloud);
        sor.setMeanK(20);
        sor.setStddevMulThresh(0.5);
        sor.filter(*cloud_filtered_pass);
        cloud_filtered_pass.swap (cloud);

        if (trim_tolerance_opt->answer != NULL) {
            double autoclip_N, autoclip_S, autoclip_E, autoclip_W;
            autotrim(cloud, autoclip_N, autoclip_S, autoclip_E, autoclip_W, trim_tolerance);
            if (autoclip_E > 0 || autoclip_N > 0 || autoclip_S > 0 || autoclip_W > 0)
                trimNSEW(cloud, autoclip_N, autoclip_S, autoclip_E, autoclip_W);
        }

        if (drawing) {
            // get Z scaling
            getMinMax(*cloud, bbox);
            if ((vect_type == GV_AREA && draw_x.size() > 2) ||
                (vect_type == GV_LINE && draw_x.size() > 1) ||
                (vect_type == GV_POINT && draw_x.size() > 0)) {
                save_vector(draw_output, Map_draw, Points_draw, Cats_draw,
                            bbox, window, draw_x, draw_y, draw_z, vect_type, offset, zexag);
            }
            else
                G_warning(_("Tolopogically incorrect vector feature"));
            drawing = false;
            draw_x.clear();
            draw_y.clear();
            draw_z.clear();
            last_detected_loop_count = 1e6;
        }
        if (voutput|| routput || ply || color_output) {
            if (smooth_radius_opt->answer)
                smooth(cloud, smooth_radius);

            // get Z scaling
            getMinMax(*cloud, bbox);
            scale = ((window.north - window.south) / (bbox.N - bbox.S) +
                     (window.east - window.west) / (bbox.E - bbox.W)) / 2;
        }
        // write to vector
        if (voutput|| (routput && strcmp(method, "interpolation") == 0)) {
            double z;
            if (voutput) {
                if (Vect_open_new(&Map, voutput, WITH_Z) < 0)
                    G_fatal_error(_("Unable to create temporary vector map <%s>"), voutput);
            }
            else {
                if (Vect_open_tmp_new(&Map, routput, WITH_Z) < 0)
                    G_fatal_error(_("Unable to create temporary vector map <%s>"), routput);
            }
            for (int i=0; i < cloud->points.size(); i++) {
                Vect_reset_line(Points);
                Vect_reset_cats(Cats);
                if (region3D)
                    z = (cloud->points[i].z + zrange_max) * scale / zexag + offset;
                else
                    z = (cloud->points[i].z - bbox.B) * scale / zexag + offset;
                Vect_append_point(Points, cloud->points[i].x,
                                  cloud->points[i].y,
                                  z);
                Vect_cat_set(Cats, 1, cat);
                Vect_write_line(&Map, GV_POINT, Points, Cats);
            }
            if (strcmp(method, "interpolation") == 0) {
                // interpolate
                Vect_rewind(&Map);
                interpolate(&Map, routput, 20, 2, 50, 40, -1,
                            &bbox, resolution);
            }
            Vect_close(&Map);
        }

        if (routput || color_output) {
            if (routput) {
                if (strcmp(method, "interpolation") != 0) {
                    binning(cloud, routput, &bbox, resolution,
                            scale, zexag, region3D ? -zrange_max : bbox.B, offset, method);
                }
                Rast_get_cellhd(routput, "", &cellhd);
            }
            if (color_output) {
                binning_color(cloud, color_output, &bbox, resolution);
                Rast_get_cellhd(get_color_name(color_output, "r"), "", &cellhd);
            }

            // georeference horizontally
            window.rows = cellhd.rows;
            window.cols = cellhd.cols;
            G_adjust_Cell_head(&window, 1, 1);
            cellhd.north = window.north;
            cellhd.south = window.south;
            cellhd.east = window.east;
            cellhd.west = window.west;
            if (routput)
                Rast_put_cellhd(routput, &cellhd);
            if (color_output) {
                char* output_r = get_color_name(color_output, "r");
                char* output_g = get_color_name(color_output, "g");
                char* output_b = get_color_name(color_output, "b");
                Rast_put_cellhd(output_r, &cellhd);
                Rast_put_cellhd(output_g, &cellhd);
                Rast_put_cellhd(output_b, &cellhd);
            }
            set_default_color(routput);
            if (contours_output) {
                contours(routput, contours_output, atof(contours_step_opt->answer));
            }
            if (use_equalized) {
                equalized(routput);
            }
        }
        // write to PLY
        if (ply) {
            pcl::PLYWriter writer;
            for (int i=0; i < cloud->points.size(); i++) {
                if (region3D)
                    cloud->points[i].z = (cloud->points[i].z + zrange_max) * scale / zexag + offset;
                else
                    cloud->points[i].z = (cloud->points[i].z - bbox.B) * scale / zexag + offset;
                cloud->points[i].x = (cloud->points[i].x - bbox.W) * scale + window.west;
                cloud->points[i].y = (cloud->points[i].y - bbox.S) * scale + window.south;

            }
            writer.write<pcl::PointXYZRGB>(ply, *cloud, true, true);
        }

        if (!loop_flag->answer)
            j++;
    }

    k2g.shutDown();

    return EXIT_SUCCESS;
}