Example #1
0
/*!
* \return
* \brief	
* \param	obj
* \param	dstErr
*/
static WlzObject *WlzObjToConvexPolygon3d(
  WlzObject	*obj,
  WlzErrorNum	*dstErr)
{
  WlzObject	*polygon=NULL, *obj1, *obj2;
  WlzDomain	domain, *domains, *new_domains;
  WlzValues	values;
  int		p;
  WlzErrorNum	errNum=WLZ_ERR_NONE;


  /* the object and domain have been checked therefore can create the
     new straight away and fill each plane appropriately */
  if((domain.p = WlzMakePlaneDomain(WLZ_PLANEDOMAIN_POLYGON,
				    obj->domain.p->plane1,
				    obj->domain.p->lastpl,
				    obj->domain.p->line1,
				    obj->domain.p->lastln,
				    obj->domain.p->kol1,
				    obj->domain.p->lastkl,
				    &errNum)) != NULL){
    domain.p->voxel_size[0] = obj->domain.p->voxel_size[0];
    domain.p->voxel_size[1] = obj->domain.p->voxel_size[1];
    domain.p->voxel_size[2] = obj->domain.p->voxel_size[2];
    values.core = NULL;
    polygon = WlzMakeMain(WLZ_3D_DOMAINOBJ, domain, values, NULL, NULL,
			  &errNum);
  }

  if( errNum == WLZ_ERR_NONE ){
    domains = obj->domain.p->domains;
    new_domains = domain.p->domains;
    values.core = NULL;
    for(p=obj->domain.p->plane1; p <= obj->domain.p->lastpl;
	p++, domains++, new_domains++){
      if( (*domains).core ){
	obj1 = WlzMakeMain(WLZ_2D_DOMAINOBJ, *domains, values,
			   NULL, NULL, NULL);
	if((obj2 = WlzObjToConvexPolygon(obj1, &errNum)) != NULL){
	  *new_domains = WlzAssignDomain(obj2->domain, NULL);
	  WlzFreeObj(obj2);
	}
	else {
	  WlzFreeObj(polygon);
	  polygon = NULL;
	  break;
	}
	WlzFreeObj(obj1);
      }
      else {
	(*new_domains).core = NULL;
      }
    }
  }

  if( dstErr ){
    *dstErr = errNum;
  }
  return polygon;
}
Example #2
0
/*!
* \return	New convex hull values.
* \ingroup	WlzConvexHull
* \brief	Fill in parameters of the convex hull into the values table.
* \param	cvh			Given convex hull.
* \param	obj			Given object.
* \param	dstErr			Destination error pointer, may be NULL.
*/
static WlzConvHullValues *WlzMakeConvexHullValues3d(
  WlzObject *cvh,
  WlzObject *obj,
  WlzErrorNum *dstErr)
{
  WlzValues		rtnvalues, *valuess, values;
  WlzObject		*obj1, *obj2;
  WlzDomain		*domains1, *domains2;
  WlzPixelV		bckgrnd;
  int			p;
  WlzErrorNum		errNum=WLZ_ERR_NONE;

  /* this is only called after a successful call to WlzObjToConvexPolygon
     therefore the given convex hull object and object have been checked
     and match */
  rtnvalues.c = NULL;
  bckgrnd.type = WLZ_GREY_UBYTE;
  bckgrnd.v.ubv = 0;

  /* make a voxeltable and calculate the convex hull values for each plane */
  if((rtnvalues.vox = WlzMakeVoxelValueTb(WLZ_VOXELVALUETABLE_CONV_HULL,
					  cvh->domain.p->plane1,
					  cvh->domain.p->lastpl,
					  bckgrnd, NULL, &errNum)) != NULL){
    domains1 = cvh->domain.p->domains;
    domains2 = obj->domain.p->domains;
    valuess = rtnvalues.vox->values;
    for(p=cvh->domain.p->plane1; p <= cvh->domain.p->lastpl;
	p++, domains1++, domains2++, valuess++){
      if( (*domains1).core != NULL ){
	values.core = NULL;
	obj1 = WlzMakeMain(WLZ_2D_POLYGON, *domains1, values,
			   NULL, NULL, NULL);
	obj2 = WlzMakeMain(WLZ_2D_DOMAINOBJ, *domains2, values,
			   NULL, NULL, NULL);
	if((values.c = WlzMakeConvexHullValues(obj1, obj2, &errNum)) != NULL){
	  *valuess = WlzAssignValues(values, NULL);
	}
	else {
	  WlzFreeObj(obj2);
	  WlzFreeObj(obj1);
	  WlzFreeVoxelValueTb(rtnvalues.vox);
	  rtnvalues.vox = NULL;
	  break;
	}
	WlzFreeObj(obj2);
	WlzFreeObj(obj1);
      }
    }
  }


  if( dstErr ){
    *dstErr = errNum;
  }
  return rtnvalues.c;
}
Example #3
0
void write_reference_object_cb(
Widget	w,
XtPointer	client_data,
XtPointer	call_data)
{
  XmFileSelectionBoxCallbackStruct *cbs =
    (XmFileSelectionBoxCallbackStruct *) call_data;
  WlzEffFormat	image_type = (WlzEffFormat) client_data;

  /* set hour glass cursor */
  HGU_XmSetHourGlassCursor(globals.topl);

  /* write the reference object */
  if( globals.origObjType == WLZ_2D_DOMAINOBJ ){
    WlzObject *tmpObj;

    tmpObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, 
			 globals.orig_obj->domain.p->domains[0],
			 globals.orig_obj->values.vox->values[0],
			 NULL, NULL, NULL);
    HGU_XmWriteExtFFObject(tmpObj, w, cbs, &image_type);
    WlzFreeObj(tmpObj);
  }
  else {
    HGU_XmWriteExtFFObject(globals.orig_obj, w, cbs, &image_type);
  }

  /* set hour glass cursor */
  HGU_XmUnsetHourGlassCursor(globals.topl);
  return;
}
Example #4
0
/*!
* \return	Woolz error code.
* \ingroup	WlzBinaryOps
* \brief	For each value in the given 3D distance object the count in
* 		the given distance histogram (array) is incremented. This
* 		is done by forming 2D objects for each plane and calling
* 		WlzRCCCompDistHist2D().
* \param	maxDist			Maximum distance value.
* \param	dHist			Distance histogram (array).
* \param	dObj			Given 3D distance object.
*/
static WlzErrorNum	WlzRCCCompDistHist3D(
			  int maxDist,
			  int *dHist,
			  WlzObject *dObj)
{
  int		n,
  		p;
  WlzVoxelValues *pVal;
  WlzPlaneDomain *pDom;
  WlzErrorNum   errNum = WLZ_ERR_NONE;

  pVal = dObj->values.vox;
  pDom = dObj->domain.p;
  n = pDom->lastpl - pDom->plane1 + 1;
  for(p = 0; p < n; ++p)
  {
    if(pDom->domains[p].core != NULL)
    {
      WlzObject	*dObj2;

      dObj2 = WlzMakeMain(WLZ_2D_DOMAINOBJ, pDom->domains[p], pVal->values[p],
			  NULL, NULL, &errNum);
      errNum = WlzRCCCompDistHist2D(maxDist, dHist, dObj2);
      (void )WlzFreeObj(dObj2);
      if(errNum != WLZ_ERR_NONE)
      {
        break;
      }
    }
  }
  return(errNum);
}
Example #5
0
/*!
* \return	Integer array with values and coordinates from 3D object.
* \ingroup	WlzValueUtils
* \brief	Allocates a new array (4 ints per value: 0 = value,
* 		1 = x coordinate, 2 = y coordinate and 3 = z coordinate.
* \param	obj			Given object which must be a valid
* 					3D domain object with integer values.
* \param	dstNAry			Destination pointer for the number of
* 					values, must not be NULL.
* \param	dstErr			Destination error pointer, may be NULL.
*/
static int	*WlzCompDispMakeValAry3D(WlzObject *obj, int *dstNAry,
				         WlzErrorNum *dstErr)
{
  int		idO,
  		idP,
		nAry;
  int		*ary,
  		*array = NULL;
  WlzObject	*obj2D;
  WlzPlaneDomain *pDom;
  WlzErrorNum	errNum = WLZ_ERR_NONE;

  if((nAry = WlzVolume(obj, &errNum)) <= 0)
  {
    errNum = WLZ_ERR_DOMAIN_DATA;
  }
  if(errNum == WLZ_ERR_NONE)
  {
    if((array = AlcMalloc(nAry * 4 * sizeof(int))) == NULL)
    {
      errNum = WLZ_ERR_MEM_ALLOC;
    }
  }
  if(errNum == WLZ_ERR_NONE)
  {
    ary = array;
    pDom = obj->domain.p;
    for(idP = pDom->plane1; (errNum == WLZ_ERR_NONE) && (idP <= pDom->lastpl);
        ++idP)
    {
      idO = idP - pDom->plane1;
      obj2D = WlzMakeMain(WLZ_2D_DOMAINOBJ,
			  *(obj->domain.p->domains + idO),
			  *(obj->values.vox->values + idO),
			  NULL, NULL, &errNum);
      if(errNum == WLZ_ERR_NONE)
      {
	errNum = WlzCompDispSetAry(&ary, obj2D, idP, 3);
	WlzFreeObj(obj2D);
      }
    }
  }
  if(errNum != WLZ_ERR_NONE)
  {
    AlcFree(ary);
    ary = NULL;
  }
  else
  {
    *dstNAry = nAry;
    if(dstErr != NULL)
    {
      *dstErr = errNum;
    }
  }
  return(array);
}
Example #6
0
/*!
* \return	Woolz error code.
* \ingroup	WlzBoundary
* \brief	decomposes a boundary into it's component polygons.
* \param	bndObj		Given boundary.
* \param	dstNumObjs	Destination pointer for the number of polygons.
* \param	dstObjArray	Destination pointer for the array of polygons.
*/
WlzErrorNum WlzBoundaryToPolyObjArray(
  WlzObject	*bndObj,
  int		*dstNumObjs,
  WlzObject	***dstObjArray)
{
  WlzErrorNum	errNum=WLZ_ERR_NONE;
  WlzDomain	domain;
  WlzValues	values;
  WlzObject	*obj, **objs;
  WlzPolygonDomain	**polyArray;
  int 		i, numPolys;

  /* check inputs */
  if( bndObj == NULL ){
    errNum = WLZ_ERR_OBJECT_NULL;
  }
  else if((dstNumObjs == NULL) || (dstObjArray == NULL)){
    errNum = WLZ_ERR_PARAM_NULL;
  }
  else {
    /* generate array of poly domains */
    errNum = WlzBoundObjToPolyDomArray(bndObj, &numPolys, &polyArray);
  }

  /* convert to polygon objects */
  if( errNum == WLZ_ERR_NONE ){
    if((objs = (WlzObject **) AlcMalloc(sizeof(WlzObject *)*numPolys)) == NULL){
      errNum = WLZ_ERR_MEM_ALLOC;
      for(i=0; i < numPolys; i++){
	WlzFreePolyDmn(polyArray[i]);
      }
      AlcFree(polyArray);
      numPolys = 0;
    }
    else {
      for(i=0; i < numPolys; i++){
	domain.poly = polyArray[i];
	values.core = NULL;
	obj = WlzMakeMain(WLZ_2D_POLYGON, domain, values,
			  NULL, NULL, &errNum);
	objs[i] = WlzAssignObject(obj, NULL);
	WlzFreePolyDmn(polyArray[i]);
      }
      AlcFree(polyArray);
    }
  }
  
  *dstNumObjs = numPolys;
  *dstObjArray = objs;
  return errNum;
}
/*!
* \return	Woolz error code.
* \ingroup	WlzArithmetic
* \brief	Increments all values of the firstobject which are within
* 		the domain of the second object. The domain of the first
* 		object must cover that of the second.
*		Because this is a static object it is assumed that the
*		two 2D objects are known to be valid.
* \param	gObj		First object.
* \param	dObj		Second object.
*/
static WlzErrorNum WlzGreyIncValuesInDomain2D(WlzObject *gObj, WlzObject *dObj)
{
  WlzObject	*tObj;
  WlzErrorNum	errNum = WLZ_ERR_NONE;

  tObj = WlzAssignObject(
         WlzMakeMain(WLZ_2D_DOMAINOBJ, dObj->domain, gObj->values, NULL, NULL,
	             &errNum), NULL);
  if(errNum == WLZ_ERR_NONE)
  {
    errNum = WlzGreyIncValues2D(tObj);
    (void )WlzFreeObj(tObj);
  }
  return(errNum);
}
/*!
* \return	New grey value domain object with incrementing values.
* \ingroup	WlzValuesUtils
* \brief	Creates a new 2D domain object with integer values that
* 		increment throughout the object in scan order. Object
* 		values are set by incrementing the given value in place.
* \param	in			Input domain object.
* \param	val			Pointer to current value, this is
* 					incremented in place.
* \param	dstErr			Destination error pointer, may be NULL.
*/
static WlzObject *WlzGreyNewIncValues2D(WlzObject *in, int *val,
					WlzErrorNum *dstErr)
{
  WlzObject     *out = NULL;
  WlzObjectType	gTT;
  WlzPixelV	bgd;
  WlzValues	values;
  WlzErrorNum   errNum = WLZ_ERR_NONE;

  bgd.type = WLZ_GREY_INT;
  bgd.v.inv = 0;
  values.core = NULL;
  gTT = WlzGreyTableType(WLZ_GREY_TAB_RAGR, WLZ_GREY_INT, &errNum);
  if(errNum == WLZ_ERR_NONE)
  {
    values.v = WlzNewValueTb(in, gTT, bgd, &errNum);
  }
  if(errNum == WLZ_ERR_NONE)
  {
    out = WlzMakeMain(in->type, in->domain, values, in->plist, NULL, &errNum);
  }
  if(errNum == WLZ_ERR_NONE)
  {
    errNum = WlzGreySetIncValuesItr(out, val);
  }
  if(errNum != WLZ_ERR_NONE)
  {
    if(out != NULL)
    {
      (void )WlzFreeObj(out);
      out = NULL;
    }
    else if(values.core != NULL)
    {
      (void )WlzFreeValues(values);
    }
  }
  if(dstErr != NULL)
  {
    *dstErr = errNum;
  }
  return(out);
}
Example #9
0
void read_reference_object_cb(
  Widget	w,
  XtPointer	client_data,
  XtPointer	call_data)
{
  XmFileSelectionBoxCallbackStruct *cbs =
    (XmFileSelectionBoxCallbackStruct *) call_data;
  WlzEffFormat		image_type;
  WlzObject		*obj;
  String		icsfile;
  WlzDomain	domain;
  WlzValues	values;
  WlzObject	*newObj;
  WlzErrorNum		errNum=WLZ_ERR_NONE;

  /* set hour glass cursor */
  HGU_XmSetHourGlassCursor(globals.topl);

  /* read the new reference object
     note the switch is to allow direct read
     given the image type to include the model
     input options */
  if( client_data ){
    image_type = (WlzEffFormat) client_data;
    if((icsfile = HGU_XmGetFileStr(globals.topl, cbs->value,
				   cbs->dir))){
      obj = WlzEffReadObj(NULL, icsfile, image_type, 0, 0, 0, &errNum);
      AlcFree(icsfile);
    }
    else {
      obj = NULL;
    }
  }
  else {
    obj = HGU_XmReadExtFFObject(read_obj_dialog, cbs,
			       &image_type, &errNum);
  }
  if( obj == NULL){
    HGU_XmUserError(globals.topl,
		    "Read Reference Object:\n"
		    "    No reference object read - either the\n"
		    "    selected file is empty or it is not the\n"
		    "    correct object type - please check the\n"
		    "    file or make a new selection",
   		    XmDIALOG_FULL_APPLICATION_MODAL);
    /* set hour glass cursor */
    HGU_XmUnsetHourGlassCursor(globals.topl);
    return;
  }

  if( obj->values.core == NULL ){
    HGU_XmUserError(globals.topl,
		    "Read Reference Object:\n"
		    "    The reference object must have a grey-\n"
		    "    value table. Please select an alternate\n"
		    "    object",
		    XmDIALOG_FULL_APPLICATION_MODAL);
    WlzFreeObj( obj );
    /* set hour glass cursor */
    HGU_XmUnsetHourGlassCursor(globals.topl);
    return;
  }

  /* install the new reference object */
  switch( obj->type ){

  case WLZ_2D_DOMAINOBJ:
    if((domain.p = WlzMakePlaneDomain(WLZ_PLANEDOMAIN_DOMAIN, 0, 0,
				      obj->domain.i->line1,
				      obj->domain.i->lastln,
				      obj->domain.i->kol1,
				      obj->domain.i->lastkl,
				      &errNum))){
      domain.p->domains[0] = WlzAssignDomain(obj->domain, NULL);
      if((values.vox = WlzMakeVoxelValueTb(WLZ_VOXELVALUETABLE_GREY,
					   0, 0, WlzGetBackground(obj, NULL),
					   NULL, &errNum))){
	values.vox->values[0] = WlzAssignValues(obj->values, NULL);
	newObj = WlzMakeMain(WLZ_3D_DOMAINOBJ, domain, values,
			     obj->plist, NULL, &errNum);
	WlzFreeObj(obj);
	obj = newObj;
      }
    }
    globals.origObjType = WLZ_2D_DOMAINOBJ;
    break;

  case WLZ_3D_DOMAINOBJ:
    globals.origObjType = WLZ_3D_DOMAINOBJ;
    break;

  default:
    HGU_XmUserError(globals.topl,
		    "Read Reference Object:\n"
		    "    The reference object must be a 2- or 3-D\n"
		    "    grey-level image. Please select an alternate\n"
		    "    object",
		    XmDIALOG_FULL_APPLICATION_MODAL);
    WlzFreeObj( obj );
    /* set hour glass cursor */
    HGU_XmUnsetHourGlassCursor(globals.topl);
    return;
  }
  globals.origObjExtType = image_type;

  /* set title and reference file list */
  if((icsfile = HGU_XmGetFileStr(globals.topl, cbs->value, cbs->dir)))
  {
    Widget	cascade;
    HGU_XmFileListAddFile(globals.fileList, icsfile, image_type);
    HGU_XmFileListWriteResourceFile(globals.fileList,
				    globals.resourceFile);
    if((cascade = XtNameToWidget(globals.topl,
				 "*file_menu*_pulldown*Recent"))){
      HGU_XmFileListResetMenu(globals.fileList, cascade, referenceFileListCb);
    }
    if( XmStringGetLtoR(cbs->value, XmSTRING_DEFAULT_CHARSET, &icsfile) )
    {
      set_topl_title(icsfile);
      globals.file = icsfile;
    }
  }
  MAPaintLogData("ReferenceFile", globals.file, 0, NULL);

  /* clear feedback object and install new reference object */
  if( errNum == WLZ_ERR_NONE ){
    if( globals.fb_obj ){
      WlzFreeObj(globals.fb_obj);
      globals.fb_obj = NULL;
    }
    install_paint_reference_object( obj );
  }

  /* set hour glass cursor */
  HGU_XmUnsetHourGlassCursor(globals.topl);

  if( errNum != WLZ_ERR_NONE ){
    MAPaintReportWlzError(globals.topl, "read_reference_object_cb", errNum);
  }
  return;
}
Example #10
0
int main(int	argc,
	 char	**argv)
{

  WlzObject	*inObj, *outObj;
  WlzDomain	domain;
  WlzValues	values;
  FILE		*inFP, *outFP, *bibFP;
  char		*outFile, *bibFile;
  char 		optList[] = "b:f:o:hv";
  int		option;
  WlzErrorNum	errNum=WLZ_ERR_NONE;
  BibFileRecord	*bibfileRecord;
  BibFileError	bibFileErr;
  int		verboseFlg=0;
  WlzMeshTransform *meshTr = NULL;
  WlzFnType		wlzFnType;
  WlzMeshGenMethod	meshMthd;
  int			basisFnPolyOrder = 3;
  int			meshMinDst;
  int	 		meshMaxDst;
  WlzTransformType	affineType;
  WlzDVertex2		*srcVtxs, *dstVtxs;
  int		relFlg=0;
  int		numVtxs, maxNumVtxs;
  char		*errMsg;
    
  /* additional defaults */
  outFile = "-";
  bibFile = NULL;
  numVtxs = 0;
  maxNumVtxs = 0;
  srcVtxs = NULL;
  dstVtxs = NULL;

  /* read the argument list and check for an input file */
  opterr = 0;
  while( (option = getopt(argc, argv, optList)) != EOF ){
    switch( option ){

    case 'b':
      bibFile = optarg;
      break;

    case 'o':
      outFile = optarg;
      break;

    case 'h':
    default:
      usage(argv[0]);
      return 0;

    case 'v':
      verboseFlg = 1;
      break;

    }
  }

  /* check input file/stream */
  inFP = stdin;
  if( optind < argc ){
    if( (inFP = fopen(*(argv+optind), "rb")) == NULL ){
      fprintf(stderr, "%s: can't open file %s\n", argv[0], *(argv+optind));
      usage(argv[0]);
      return 1;
    }
  }

  /* check output file/stream */
  if(strcmp(outFile, "-"))
  {
    if((outFP = fopen(outFile, "w")) == NULL)
    {
      errNum = WLZ_ERR_WRITE_EOF;
    }
  }
  else
  {
    outFP = stdout;
  }

  /* check bibfile - get warp function parameters and tie-points */
  if((errNum == WLZ_ERR_NONE) && (bibFile != NULL)){
    if((bibFP = fopen(bibFile, "r")) != NULL){
      bibFileErr = BibFileRecordRead(&bibfileRecord, &errMsg, bibFP);
      while( bibFileErr == BIBFILE_ER_NONE ){

	/* test for warp function and mesh parameters */
	if( !strncmp(bibfileRecord->name, "WlzWarpTransformParams", 22) ){

	  WlzEffBibParseWarpTransformParamsRecord(bibfileRecord,
						  &wlzFnType,
						  &affineType,
						  &meshMthd,
						  &meshMinDst, &meshMaxDst);
	}

	/* test for tie points */
	if( !strncmp(bibfileRecord->name, "WlzTiePointVtxs", 15) ){
	  int		index;
	  WlzDVertex3	dstVtx;
	  WlzDVertex3	srcVtx;

	  WlzEffBibParseTiePointVtxsRecord(bibfileRecord, &index,
				       &dstVtx, &srcVtx, &relFlg);
	  if( relFlg ){
	    fprintf(stderr, "%s: warning, relative vertex positions, probably an error\n",
		    argv[0]);
	  }
	  if( numVtxs >= maxNumVtxs ){
	    maxNumVtxs += 512;
	    srcVtxs = (WlzDVertex2 *) AlcRealloc(srcVtxs,
						 sizeof(WlzDVertex2)*maxNumVtxs);
	    dstVtxs = (WlzDVertex2 *) AlcRealloc(dstVtxs,
						 sizeof(WlzDVertex2)*maxNumVtxs);
	  }
	  srcVtxs[numVtxs].vtX = srcVtx.vtX;
	  srcVtxs[numVtxs].vtY = srcVtx.vtY;
	  dstVtxs[numVtxs].vtX = dstVtx.vtX;
	  dstVtxs[numVtxs].vtY = dstVtx.vtY;
	  numVtxs++;
	}

	BibFileRecordFree(&bibfileRecord);
	bibFileErr = BibFileRecordRead(&bibfileRecord, &errMsg, bibFP);
      }
      fclose( bibFP );
      if( bibFileErr == BIBFILE_ER_EOF ){
	bibFileErr = BIBFILE_ER_NONE;
      }
      if( bibFileErr != BIBFILE_ER_NONE ){
	fprintf(stderr, "%s: error reading bibfile\n", argv[0]);
  	return 1;
      }
    }
    else {
      fprintf(stderr, "%s: can't open parameter bibfile %s\n", argv[0],
	      bibFile);
      return 1;
    }
  }
  else {
    fprintf(stderr, "%s: warp parameters and tie-points bibfile required\n",
	    argv[0]);
    usage(argv[0]);
    return 1;
  }
  
  /* read objects and section if possible */
  while((errNum == WLZ_ERR_NONE) &&
        ((inObj = WlzReadObj(inFP, &errNum)) != NULL))
  {
    switch( inObj->type )
    {
    case WLZ_2D_DOMAINOBJ:
      /* now create the mesh transform */
      if((meshTr = WlzMeshTransformFromCPts(inObj, wlzFnType, basisFnPolyOrder,
					    numVtxs, srcVtxs, numVtxs, dstVtxs,
					    meshMthd, meshMinDst, meshMaxDst,
					    &errNum)) != NULL){
	/* write out transform and free */
	domain.mt = meshTr;
	values.core = NULL;
	outObj = WlzMakeMain(WLZ_MESH_TRANS, domain, values, NULL, NULL, &errNum);
	WlzWriteObj(outFP, outObj);
	WlzFreeObj(outObj);
      }
      else {
	/* something wrong */
	fprintf(stderr,
		"%s: failed to generate a mesh transform, error code: %d\n",
		argv[0], errNum);
      }
      break;

    default:
      fprintf(stderr, "%s: 2D input object required\n", argv[0]);
      usage(argv[0]);
      return 1;
    }

    WlzFreeObj(inObj);
  }
  if(errNum == WLZ_ERR_READ_EOF)
  {
    errNum = WLZ_ERR_NONE;
  }

  return errNum;
}
Example #11
0
/*!
* \return	New 3D object.
* \ingroup	WlzAllocation
* \brief	Constructs a 3D domain object from 2D domain objects read
*		from the given files. Each file is read in turn and added
*		to the 3D object. An empty plane can be specified by
*		setting the file string to NULL. Either all or none of
*		the 2D objects must have values. When the 2D objects
*		have values then the background value of the first 2D
*		object is set to be the background value of the 3D object.
* \param	nFileStr		Number of file strings.
* \param	fileStr			File strings.
* \param	plane1			The plane coordinate of the first
*					2D object.
* \param	xSz			Column voxel size.
* \param	ySz			Line voxel size.
* \param	zSz			Plane voxel size.
* \param	dstErr			Destination error pointer, may be NULL.
*/
WlzObject	*WlzConstruct3DObjFromFile(int nFileStr, char **fileStr,
					  int plane1,
					  float xSz, float ySz, float zSz,
					  WlzErrorNum *dstErr)
{
  int		idx,
  		lastpl;
  WlzDomain	dom3D;
  WlzValues	val3D;
  WlzObject	*obj2D = NULL,
  		*obj3D = NULL;
  WlzPixelV	bgd;
  FILE		*fP = NULL;
  WlzErrorNum	errNum = WLZ_ERR_NONE;

  dom3D.core = NULL;
  val3D.core = NULL;
  lastpl = plane1 + nFileStr - 1;
  if((nFileStr <= 0) || (fileStr == NULL) || (*fileStr == NULL))
  {
    errNum = WLZ_ERR_PARAM_NULL;
  }
  else
  {
    if((fP = fopen(*fileStr, "r")) == NULL)
    {
      errNum = WLZ_ERR_READ_EOF;
    }
    else
    {
      obj2D = WlzReadObj(fP, &errNum);
      (void )fclose(fP);
      fP = NULL;
    }
  }
  if(errNum == WLZ_ERR_NONE)
  {
    switch(obj2D->type)
    {
      case WLZ_EMPTY_OBJ:
	break;
      case WLZ_2D_DOMAINOBJ:
	if(obj2D->domain.core == NULL)
	{
	  errNum = WLZ_ERR_DOMAIN_NULL;
	}
	break;
      default:
	errNum = WLZ_ERR_OBJECT_TYPE;
	break;
    }
  }
  /* Make a plane domain, set column and line bounds later. */
  if(errNum == WLZ_ERR_NONE)
  {
    dom3D.p = WlzMakePlaneDomain(WLZ_PLANEDOMAIN_DOMAIN,
    				 plane1, lastpl,
				 0, 1, 0, 1, &errNum);
  }
  if(errNum == WLZ_ERR_NONE)
  {
    dom3D.p->voxel_size[0] = xSz;
    dom3D.p->voxel_size[1] = ySz;
    dom3D.p->voxel_size[2] = zSz;
  }
  /* Make a voxel value table. */
  if(errNum == WLZ_ERR_NONE)
  {
    if(obj2D->values.core)
    {
      bgd = WlzGetBackground(obj2D, &errNum);
      if(errNum == WLZ_ERR_NONE)
      {
	val3D.vox = WlzMakeVoxelValueTb(WLZ_VOXELVALUETABLE_GREY,
					plane1, lastpl, bgd, NULL, &errNum);
      }
    }				    
  }
  idx = 0;
  while((errNum == WLZ_ERR_NONE) && (idx < nFileStr))
  {
    if(obj2D)
    {
      switch(obj2D->type)
      {
	case WLZ_EMPTY_OBJ:
	  break;
	case WLZ_2D_DOMAINOBJ:
	  if(obj2D->domain.core == NULL)
	  {
	    errNum = WLZ_ERR_DOMAIN_NULL;
	  }
	  break;
	default:
	  errNum = WLZ_ERR_OBJECT_TYPE;
	  break;
      }
      if(errNum == WLZ_ERR_NONE)
      {
	*(dom3D.p->domains + idx) = WlzAssignDomain(obj2D->domain, NULL);
	if(val3D.core)
	{
	  if((obj2D->domain.core != NULL) && (obj2D->values.core == NULL))
	  {
	    errNum = WLZ_ERR_VALUES_NULL;
	  }
	  else
	  {
	    *(val3D.vox->values + idx) = WlzAssignValues(obj2D->values, NULL);
	  }
	}
      }
      WlzFreeObj(obj2D);
      obj2D = NULL;
    }
    if(errNum == WLZ_ERR_NONE)
    {
      ++idx;
      if((idx < nFileStr) && *(fileStr + idx))
      {
	if((fP = fopen(*(fileStr + idx), "r")) == NULL)
	{
	  errNum = WLZ_ERR_READ_EOF;
	}
	else
	{
	  obj2D = WlzReadObj(fP, &errNum);
	  (void )fclose(fP);
	  fP = NULL;
	}
      }
    }
  }
  if(errNum == WLZ_ERR_NONE)
  {
    errNum = WlzStandardPlaneDomain(dom3D.p, val3D.vox);
  }
  if(errNum == WLZ_ERR_NONE)
  {
    obj3D = WlzMakeMain(WLZ_3D_DOMAINOBJ, dom3D, val3D, NULL, NULL, &errNum);
  }
  if(errNum != WLZ_ERR_NONE)
  {
    if(dom3D.core)
    {
      (void )WlzFreeDomain(dom3D);
    }
    if(val3D.core)
    {
      (void )WlzFreeValues(val3D);
    }
  }
  if(dstErr)
  {
    *dstErr = errNum;
  }
  return(obj3D);
}
Example #12
0
/*!
* \return	New 3D object.
* \ingroup	WlzAllocation
* \brief	Constructs a 3D domain object from 2D domain objects. Each
*		2D object is assigned in turn to the 3D object no domains
*		or values are copied. An empty can be specified by
*		setting the 2D object to NULL. Either all or none of
*		the 2D objects must have values. When the 2D objects
*		have values then the background value of the first 2D
*		object is set to be the background value of the 3D object.
* \param	nObjs			Number of objects.
* \param	objs			The 2D objects, the first of which
*					MUST not be NULL.
* \param	plane1			The plane coordinate of the first
*					2D object.
* \param	xSz			Column voxel size.
* \param	ySz			Line voxel size.
* \param	zSz			Plane voxel size.
* \param	dstErr			Destination error pointer, may be NULL.
*/
WlzObject	*WlzConstruct3DObjFromObj(int nObjs, WlzObject **objs,
					 int plane1,
					 float xSz, float ySz, float zSz,
					 WlzErrorNum *dstErr)
{
  int		idx,
  		lastpl;
  WlzDomain	dom3D;
  WlzValues	val3D;
  WlzObject	*obj2D,
  		*obj3D = NULL;
  WlzPixelV	bgd;
  WlzErrorNum	errNum = WLZ_ERR_NONE;

  dom3D.core = NULL;
  val3D.core = NULL;
  lastpl = plane1 + nObjs - 1;
  if((nObjs <= 0) || (objs == NULL))
  {
    errNum = WLZ_ERR_PARAM_NULL;
  }
  else if((obj2D = *objs) == NULL)
  {
    errNum = WLZ_ERR_OBJECT_NULL;
  }
  else
  {
    switch(obj2D->type)
    {
      case WLZ_EMPTY_OBJ:
	break;
      case WLZ_2D_DOMAINOBJ:
	if(obj2D->domain.core == NULL)
	{
	  errNum = WLZ_ERR_DOMAIN_NULL;
	}
	break;
      default:
	errNum = WLZ_ERR_OBJECT_TYPE;
	break;
    }
  }
  /* Make a plane domain, set column and line bounds later. */
  if(errNum == WLZ_ERR_NONE)
  {
    dom3D.p = WlzMakePlaneDomain(WLZ_PLANEDOMAIN_DOMAIN,
    				 plane1, lastpl,
				 0, 1, 0, 1, &errNum);
  }
  if(errNum == WLZ_ERR_NONE)
  {
    dom3D.p->voxel_size[0] = xSz;
    dom3D.p->voxel_size[1] = ySz;
    dom3D.p->voxel_size[2] = zSz;
  }
  /* Make a voxel value table. */
  if(errNum == WLZ_ERR_NONE)
  {
    if(obj2D->values.core)
    {
      bgd = WlzGetBackground(obj2D, &errNum);
      if(errNum == WLZ_ERR_NONE)
      {
	val3D.vox = WlzMakeVoxelValueTb(WLZ_VOXELVALUETABLE_GREY,
					plane1, lastpl, bgd, NULL, &errNum);
      }
    }				    
  }
  for(idx = 0; (errNum == WLZ_ERR_NONE) && (idx < nObjs); ++idx)
  {
    obj2D = *(objs + idx);
    if(obj2D)
    {
      switch(obj2D->type)
      {
	case WLZ_EMPTY_OBJ:
	  break;
	case WLZ_2D_DOMAINOBJ:
	  if(obj2D->domain.core == NULL)
	  {
	    errNum = WLZ_ERR_DOMAIN_NULL;
	  }
	  break;
	default:
	  errNum = WLZ_ERR_OBJECT_TYPE;
	  break;
      }
      if(errNum == WLZ_ERR_NONE)
      {
	*(dom3D.p->domains + idx) = WlzAssignDomain(obj2D->domain, NULL);
	if(val3D.core)
	{
	  if((obj2D->domain.core != NULL) && (obj2D->values.core == NULL))
	  {
	    errNum = WLZ_ERR_VALUES_NULL;
	  }
	  else
	  {
	    *(val3D.vox->values + idx) = WlzAssignValues(obj2D->values, NULL);
	  }
	}
      }
    }
  }
  if(errNum == WLZ_ERR_NONE)
  {
    errNum = WlzStandardPlaneDomain(dom3D.p, val3D.vox);
  }
  if(errNum == WLZ_ERR_NONE)
  {
    obj3D = WlzMakeMain(WLZ_3D_DOMAINOBJ, dom3D, val3D, NULL, NULL, &errNum);
  }
  if(errNum != WLZ_ERR_NONE)
  {
    if(dom3D.core)
    {
      (void )WlzFreeDomain(dom3D);
    }
    if(val3D.core)
    {
      (void )WlzFreeValues(val3D);
    }
  }
  if(dstErr)
  {
    *dstErr = errNum;
  }
  return(obj3D);
}
Example #13
0
/*! 
* \ingroup      WlzValuesFilters
* \brief        Set new grey-range by simple linear interpolation. It
 assumes that the min and max values enclose the true range of
 grey-values in the object. Failure to check this could result in a
 segmentation fault.

The transform function is:
\f[g' = \frac{(gMax - gMin)}{(gmax - gmin)} (g - gmin) + gMin + \delta
\f]
Here \f$\delta\f$ is the dither value.
*
* \return       Woolz error number
* \param    obj	Input grey-level object whose values are to be reset.
* \param    min	Initial minimum value
* \param    max	Initial maximum value
* \param    Min	Final minimum value
* \param    Max	Final maximum value
* \param    Dither values if destination range is greater than source range
*           and this flag is non-zero.
* \par      Source:
*                WlzGreySetRange.c
*/
WlzErrorNum WlzGreySetRange(
  WlzObject	*obj,
  WlzPixelV	min,
  WlzPixelV	max,
  WlzPixelV	Min,
  WlzPixelV	Max,
  int		dither)
{
  double		gMin = 0.0,
  			gMax = 0.0,
			sigma = 0.0,
  			factor,
			val;
  WlzIntervalWSpace	iwsp;
  WlzGreyWSpace		gwsp;
  WlzGreyP		gptr;
  WlzObject		*tempobj;
  WlzValues 		*values;
  WlzDomain		*domains;
  int			i, j, nplanes;
  WlzErrorNum		errNum = WLZ_ERR_NONE;

  /* check object */
  if( obj == NULL ){
    errNum = WLZ_ERR_OBJECT_NULL;
  }

  if( errNum == WLZ_ERR_NONE ){
    switch( obj->type ){

    case WLZ_2D_DOMAINOBJ:
      if( obj->domain.i == NULL ){
	return WLZ_ERR_DOMAIN_NULL;
      }
      if( obj->values.core == NULL ){
	return WLZ_ERR_VALUES_NULL;
      }
      if( WlzGreyTableIsTiled(obj->values.core->type) ){
	return WLZ_ERR_VALUES_TYPE;
      }
      break;

    case WLZ_3D_DOMAINOBJ:
      /* check planedomain and voxeltable */
      if( obj->domain.p == NULL ){
	return WLZ_ERR_DOMAIN_NULL;
      }
      if( obj->domain.p->type != WLZ_PLANEDOMAIN_DOMAIN ){
	return WLZ_ERR_PLANEDOMAIN_TYPE;
      }
      if( obj->values.vox == NULL ){
	return WLZ_ERR_VALUES_NULL;
      }
      if( obj->values.vox->type != WLZ_VOXELVALUETABLE_GREY ){
	return WLZ_ERR_VOXELVALUES_TYPE;
      }

      /* set range of each plane if non-empty - indicated by NULL */
      domains = obj->domain.p->domains;
      values = obj->values.vox->values;
      nplanes = obj->domain.p->lastpl - obj->domain.p->plane1 + 1;
      for(i=0; i < nplanes; i++, domains++, values++){

	if( (*domains).core == NULL || (*values).core == NULL ){
	  continue;
	}

	tempobj = WlzMakeMain(WLZ_2D_DOMAINOBJ,
			      *domains, *values, NULL, NULL,
			      &errNum);
	if((tempobj == NULL) && (errNum == WLZ_ERR_NONE) ){
	  errNum = WLZ_ERR_UNSPECIFIED;
	  break;
	}

	errNum = WlzGreySetRange(tempobj, min, max, Min, Max, dither);
	WlzFreeObj( tempobj );
	if( errNum != WLZ_ERR_NONE ){
	  break;
	}
      }
      
      return errNum;

    case WLZ_TRANS_OBJ:
      return WlzGreySetRange(obj->values.obj, min, max, Min, Max, dither);

    case WLZ_EMPTY_OBJ:
      return errNum;

    default:
      errNum = WLZ_ERR_OBJECT_TYPE;
      break;
    }
  }

  if( errNum == WLZ_ERR_NONE ){
    /* get conversion function - should use LUT
       use 4 LUTS for rgb type since bounded */
    if( WlzGreyTypeFromObj(obj, &errNum) == WLZ_GREY_RGBA ){
      WlzUByte	rgbaLut[4][256];
      WlzUInt	rgbamin[4], rgbaMin[4];
      double	rgbaFactor[4], val1;
      WlzUInt	red, green, blue, alpha;

      rgbamin[0] = WLZ_RGBA_RED_GET(min.v.rgbv);
      rgbaMin[0] = WLZ_RGBA_RED_GET(Min.v.rgbv);
      if(WLZ_RGBA_RED_GET(max.v.rgbv) > WLZ_RGBA_RED_GET(min.v.rgbv)){
	rgbaFactor[0] = (((double) WLZ_RGBA_RED_GET(Max.v.rgbv) - 
			  WLZ_RGBA_RED_GET(Min.v.rgbv))/
			 (WLZ_RGBA_RED_GET(max.v.rgbv) - 
			  WLZ_RGBA_RED_GET(min.v.rgbv)));
      }
      else {
	rgbaFactor[0] = 0.0;
      }

      rgbamin[1] = WLZ_RGBA_GREEN_GET(min.v.rgbv);
      rgbaMin[1] = WLZ_RGBA_GREEN_GET(Min.v.rgbv);
      if(WLZ_RGBA_GREEN_GET(max.v.rgbv) > WLZ_RGBA_GREEN_GET(min.v.rgbv)){
	rgbaFactor[1] = (((double) WLZ_RGBA_GREEN_GET(Max.v.rgbv) - 
			  WLZ_RGBA_GREEN_GET(Min.v.rgbv))/
			 (WLZ_RGBA_GREEN_GET(max.v.rgbv) - 
			  WLZ_RGBA_GREEN_GET(min.v.rgbv)));
      }
      else {
	rgbaFactor[1] = 0.0;
      }

      rgbamin[2] = WLZ_RGBA_BLUE_GET(min.v.rgbv);
      rgbaMin[2] = WLZ_RGBA_BLUE_GET(Min.v.rgbv);
      if(WLZ_RGBA_BLUE_GET(max.v.rgbv) > WLZ_RGBA_BLUE_GET(min.v.rgbv)){
	rgbaFactor[2] = (((double) WLZ_RGBA_BLUE_GET(Max.v.rgbv) - 
			  WLZ_RGBA_BLUE_GET(Min.v.rgbv))/
			 (WLZ_RGBA_BLUE_GET(max.v.rgbv) - 
			  WLZ_RGBA_BLUE_GET(min.v.rgbv)));
      }
      else {
	rgbaFactor[2] = 0.0;
      }

      rgbamin[3] = WLZ_RGBA_ALPHA_GET(min.v.rgbv);
      rgbaMin[3] = WLZ_RGBA_ALPHA_GET(Min.v.rgbv);
      if(WLZ_RGBA_ALPHA_GET(max.v.rgbv) > WLZ_RGBA_ALPHA_GET(min.v.rgbv)){
	rgbaFactor[3] = (((double) WLZ_RGBA_ALPHA_GET(Max.v.rgbv) - 
			  WLZ_RGBA_ALPHA_GET(Min.v.rgbv))/
			 (WLZ_RGBA_ALPHA_GET(max.v.rgbv) - 
			  WLZ_RGBA_ALPHA_GET(min.v.rgbv)));
      }
      else {
	rgbaFactor[3] = 0.0;
      }

      /* now set up the LUTS */
      for(i=0; i < 4; i++){
	for(j=0; j < 256; j++){
	  val1 = rgbaFactor[i] * (j - rgbamin[i]) + rgbaMin[i];
	  rgbaLut[i][j] = (WlzUByte )WLZ_CLAMP(val1, 0, 255);
	}
      }

      /* set values - can assume rgba grey-type */
      errNum = WlzInitGreyScan(obj, &iwsp, &gwsp);
      if(errNum == WLZ_ERR_NONE) {
	while( WlzNextGreyInterval(&iwsp) == WLZ_ERR_NONE ){

	  gptr = gwsp.u_grintptr;
	  for (i=0; i<iwsp.colrmn; i++, gptr.rgbp++){
	    red = rgbaLut[0][WLZ_RGBA_RED_GET(*gptr.rgbp)];
	    green = rgbaLut[0][WLZ_RGBA_GREEN_GET(*gptr.rgbp)];
	    blue = rgbaLut[0][WLZ_RGBA_BLUE_GET(*gptr.rgbp)];
	    alpha = rgbaLut[0][WLZ_RGBA_ALPHA_GET(*gptr.rgbp)];
	    WLZ_RGBA_RGBA_SET(*gptr.rgbp, red, green, blue, alpha);
	  }
	}
	(void )WlzEndGreyScan(&iwsp, &gwsp);
	if(errNum == WLZ_ERR_EOO){
	  errNum = WLZ_ERR_NONE;
	}
      }
    }
    else {
      WlzValueConvertPixel(&min, min, WLZ_GREY_DOUBLE);
      WlzValueConvertPixel(&max, max, WLZ_GREY_DOUBLE);
      WlzValueConvertPixel(&Min, Min, WLZ_GREY_DOUBLE);
      WlzValueConvertPixel(&Max, Max, WLZ_GREY_DOUBLE);
      if( fabs(max.v.dbv - min.v.dbv) < DBL_EPSILON ){
	return WLZ_ERR_FLOAT_DATA;
      }
      errNum = WlzInitGreyScan(obj, &iwsp, &gwsp);
      if(errNum == WLZ_ERR_NONE) {
	factor = (Max.v.dbv - Min.v.dbv) / (max.v.dbv - min.v.dbv);
	if(dither)
	{
	  if(fabs(factor) < 1.0 + DBL_EPSILON)
	  {
	    dither = 0;
	  }
	  else
	  {
	    sigma = fabs(2.0 / factor);
	    AlgRandSeed(101);
	    switch(gwsp.pixeltype) {
	      case WLZ_GREY_INT:
		gMin = ALG_MAX(Min.v.dbv, INT_MIN);
		gMax = ALG_MIN(Max.v.dbv, INT_MAX);
		break;
	      case WLZ_GREY_SHORT:
		gMin = ALG_MAX(Min.v.dbv, SHRT_MIN);
		gMax = ALG_MIN(Max.v.dbv, SHRT_MAX);
		break;
	      case WLZ_GREY_UBYTE:
		gMin = ALG_MAX(Min.v.dbv, 0);
		gMax = ALG_MIN(Max.v.dbv, 255);
		break;
	      case WLZ_GREY_FLOAT:
		gMin = ALG_MAX(Min.v.dbv, FLT_MIN);
		gMax = ALG_MIN(Max.v.dbv, FLT_MAX);
		break;
	      case WLZ_GREY_DOUBLE:
		gMin = Min.v.dbv;
		gMax = Max.v.dbv;
		break;
	      default:
		break;
	    }
	  }
	}
	while((errNum == WLZ_ERR_NONE) &&
	      ((errNum = WlzNextGreyInterval(&iwsp)) == WLZ_ERR_NONE)){
	  gptr = gwsp.u_grintptr;
	  switch (gwsp.pixeltype) {
	    case WLZ_GREY_INT:
	      for (i=0; i<iwsp.colrmn; i++, gptr.inp++){
		if(dither){
		  val = factor * (*gptr.inp +
				  AlgRandZigNormal(0.0, sigma) -
				  min.v.dbv) + Min.v.dbv;
		  val = WLZ_CLAMP(val, gMin, gMax);
		} else {
		  val = factor * (*gptr.inp - min.v.dbv) + Min.v.dbv;
		}
		*gptr.inp = WLZ_NINT(val);
	      }
	      break;
	    case WLZ_GREY_SHORT:
	      for (i=0; i<iwsp.colrmn; i++, gptr.shp++){
		if(dither){
		  val = factor * (*gptr.shp +
				  AlgRandZigNormal(0.0, sigma) -
				  min.v.dbv) + Min.v.dbv;
		  val = WLZ_CLAMP(val, gMin, gMax);
		} else {
		  val = factor * (*gptr.shp - min.v.dbv) + Min.v.dbv;
		}
		*gptr.shp = (short )WLZ_NINT(val);
	      }
	      break;
	    case WLZ_GREY_UBYTE:
	      for (i=0; i<iwsp.colrmn; i++, gptr.ubp++){
		if(dither){
		  val = factor * (*gptr.ubp +
				  AlgRandZigNormal(0.0, sigma) -
				  min.v.dbv) + Min.v.dbv;
		  val = WLZ_CLAMP(val, gMin, gMax);
		} else {
		  val = factor * (*gptr.ubp - min.v.dbv) + Min.v.dbv;
		}
		*gptr.ubp = (WlzUByte )WLZ_NINT(val);
	      }
	      break;
	    case WLZ_GREY_FLOAT:
	      for (i=0; i<iwsp.colrmn; i++, gptr.flp++){
		if(dither){
		  val = factor * (*gptr.flp +
				  AlgRandZigNormal(0.0, sigma) -
				  min.v.dbv) + Min.v.dbv;
		  val = WLZ_CLAMP(val, gMin, gMax);
		} else {
		  val = factor * (*gptr.flp - min.v.dbv) + Min.v.dbv;
		}
		*gptr.flp = (float )val;
	      }
	      break;
	    case WLZ_GREY_DOUBLE:
	      for (i=0; i<iwsp.colrmn; i++, gptr.dbp++){
		if(dither){
		  val = factor * (*gptr.dbp +
				  AlgRandZigNormal(0.0, sigma) -
				  min.v.dbv) + Min.v.dbv;
		  val = WLZ_CLAMP(val, gMin, gMax);
		} else {
		  val = factor * (*gptr.dbp - min.v.dbv) + Min.v.dbv;
		}
		*gptr.dbp = val;
	      }
	      break;
	    default:
	      errNum = WLZ_ERR_GREY_TYPE;
	      break;
	  }
	}
	(void )WlzEndGreyScan(&iwsp, &gwsp);
	if(errNum == WLZ_ERR_EOO){
	  errNum = WLZ_ERR_NONE;
	}
      }
    }
  }
  return errNum;
}
Example #14
0
/*!
* \return	Distance object which shares the given foreground object's
*		domain and has integer distance values, null on error.
* \ingroup	WlzMorphologyOps
* \brief	Computes the distance of every pixel/voxel in the foreground
* 		object from the reference object.
*
*		A distance transform maps all position within a  forground
*		domain to their distances from a reference domain.
*		The distance transforms implemented within this function
*		use efficient morphological primitives.
*		
*		Given two domains,
*		\f$\Omega_r\f$ the reference domain and \f$\Omega_f\f$
*		the domain specifying the region of interest,
*		a domain with a thin shell \f$\Omega_i\f$
*		is iteratively expanded from it's initial domain
*		corresponding to the reference domain \f$\Omega_r\f$.
*		At each iteration
*		\f$\Omega_i\f$ is dilated and clipped
*		by it's intersection with \f$\Omega_f\f$ until \f$\Omega_i\f$
*		becomes the null domain \f$\emptyset\f$.
*		At each iteration the current distance is recorded in a value
*		table which
*		covers the domain \f$\Omega_f\f$.
*
*		An octagonal distance scheme may be used in which
*		the distance metric is alternated between 4 and 8
*		connected for 2D and 6 and 26 connectivities in 3D.
*		See: G. Borgefors. "Distance Transformations in Arbitrary
*		Dimensions" CVGIP 27:321-345, 1984.
*
* 		An approximate Euclidean distance transform may be computed
* 		by: Scaling the given foreground and reference objects using
* 		the given approximation scale parameter, dilating the
* 		reference domain using a sphere with a radius having the same
* 		value as the scale parameter and then finaly sampling the
* 		scaled distances.
* \param	forObj			Foreground object.
* \param	refObj			Reference object.
* \param	dFn			Distance function which must be
*					appropriate to the dimension of
*					the foreground and reference objects.
* \param	dParam			Parameter required for distance
* 					function. Currently only
* 					WLZ_APX_EUCLIDEAN_DISTANCE requires a
* 					parameter. In this case the parameter
* 					is the approximation scale.
* \param	dstErr			Destination error pointer, may be NULL.
*/
WlzObject 	*WlzDistanceTransform(WlzObject *forObj, WlzObject *refObj,
				   WlzDistanceType dFn, double dParam,
				   WlzErrorNum *dstErr)
{
  int 		idP,
		lastP,
		dim,
  		notDone = 1;
  double	scale;
  WlzObject	*tmpObj,
		*sObj = NULL,
		*sForObj = NULL,
		*sRefObj = NULL,
		*dilObj = NULL,
  		*dstObj = NULL,
		*difObj = NULL,
  		*curItrObj = NULL;
  WlzObject 	*bothObj[2];
  WlzDomain	*difDoms;
  WlzPixelV 	dstV,
  		bgdV;
  WlzValues 	*difVals;
  WlzAffineTransform *tr = NULL;
  WlzConnectType con;
  WlzObjectType dstGType;
  WlzErrorNum	errNum = WLZ_ERR_NONE;
  WlzValues 	difVal,
  		dstVal,
		nullVal;
  /* By defining WLZ_DIST_TRANSFORM_ENV these normalization parameters
   * are read from the environment. This is useful for optimization. */
#ifndef WLZ_DIST_TRANSFORM_ENV
  const
#endif /* ! WLZ_DIST_TRANSFORM_ENV */
  /* These normalizarion factors have been choosen to minimize the sum of
   * squares of the deviation of the distance values from Euclidean values
   * over a radius 100 circle or sphere, where the distances are computed
   * from the circumference of the sphere towards it's centre. The values
   * were established by experiment. */
  double	nrmDist4 =  0.97,
		nrmDist6 =  0.91,
		nrmDist8 =  1.36,
		nrmDist18 = 1.34,
		nrmDist26 = 1.60;

#ifdef WLZ_DIST_TRANSFORM_ENV
  double	val;
  char		*envStr;

  if(((envStr = getenv("WLZ_DIST_TRANSFORM_NRMDIST4")) != NULL) &&
     (sscanf(envStr, "%lg", &val) == 1))
  {
    nrmDist4 = val;
  }
  if(((envStr = getenv("WLZ_DIST_TRANSFORM_NRMDIST6")) != NULL) &&
     (sscanf(envStr, "%lg", &val) == 1))
  {
    nrmDist6 = val;
  }
  if(((envStr = getenv("WLZ_DIST_TRANSFORM_NRMDIST8")) != NULL) &&
     (sscanf(envStr, "%lg", &val) == 1))
  {
    nrmDist8 = val;
  }
  if(((envStr = getenv("WLZ_DIST_TRANSFORM_NRMDIST18")) != NULL) &&
     (sscanf(envStr, "%lg", &val) == 1))
  {
    nrmDist18 = val;
  }
  if(((envStr = getenv("WLZ_DIST_TRANSFORM_NRMDIST26")) != NULL) &&
     (sscanf(envStr, "%lg", &val) == 1))
  {
    nrmDist26 = val;
  }
#endif /* WLZ_DIST_TRANSFORM_ENV */
  scale = dParam;
  nullVal.core = NULL;
  /* Check parameters. */
  if((forObj == NULL) || (refObj == NULL))
  {
    errNum = WLZ_ERR_OBJECT_NULL;
  }
  else if(((forObj->type != WLZ_2D_DOMAINOBJ) &&
           (forObj->type != WLZ_3D_DOMAINOBJ)) ||
          ((refObj->type != WLZ_POINTS) &&
	   (refObj->type != forObj->type)))
  {
    errNum = WLZ_ERR_OBJECT_TYPE;
  }
  else if((forObj->domain.core == NULL) || (refObj->domain.core == NULL))
  {
    errNum = WLZ_ERR_DOMAIN_NULL;
  }
  if(errNum == WLZ_ERR_NONE)
  {
    bgdV.type = WLZ_GREY_INT;
    bgdV.v.inv = 0;
    dstV.type = WLZ_GREY_DOUBLE;
    dstV.v.dbv = 0.0;
    switch(forObj->type)
    {
      case WLZ_2D_DOMAINOBJ:
	switch(dFn)
	{
	  case WLZ_4_DISTANCE: /* FALLTHROUGH */
	  case WLZ_8_DISTANCE: /* FALLTHROUGH */
	  case WLZ_OCTAGONAL_DISTANCE: /* FALLTHROUGH */
	  case WLZ_APX_EUCLIDEAN_DISTANCE:
	    dim = 2;
	    break;
	  default:
	    errNum = WLZ_ERR_PARAM_DATA;
	    break;
	}
        break;
      case WLZ_3D_DOMAINOBJ:
	switch(dFn)
	{
	  case WLZ_6_DISTANCE:  /* FALLTHROUGH */
	  case WLZ_18_DISTANCE: /* FALLTHROUGH */
	  case WLZ_26_DISTANCE: /* FALLTHROUGH */
	  case WLZ_OCTAGONAL_DISTANCE: /* FALLTHROUGH */
	  case WLZ_APX_EUCLIDEAN_DISTANCE:
	    dim = 3;
	    break;
	  default:
	    errNum = WLZ_ERR_PARAM_DATA;
	    break;
	}
        break;
      default:
        errNum = WLZ_ERR_OBJECT_TYPE;
	break;
    }
  }
  if(errNum == WLZ_ERR_NONE)
  {
    switch(dFn)
    {
      case WLZ_4_DISTANCE:
        con = WLZ_4_CONNECTED;
	break;
      case WLZ_6_DISTANCE:
        con = WLZ_6_CONNECTED;
	break;
      case WLZ_8_DISTANCE:
        con = WLZ_8_CONNECTED;
	break;
      case WLZ_18_DISTANCE:
        con = WLZ_18_CONNECTED;
	break;
      case WLZ_26_DISTANCE:
        con = WLZ_26_CONNECTED;
	break;
      case WLZ_OCTAGONAL_DISTANCE:
        con = (dim == 2)? WLZ_8_CONNECTED: WLZ_26_CONNECTED;
	break;
      case WLZ_APX_EUCLIDEAN_DISTANCE:
        con = (dim == 2)? WLZ_8_CONNECTED: WLZ_26_CONNECTED;
	if(scale < 1.0)
	{
	  errNum = WLZ_ERR_PARAM_DATA;
	}
	break;
      case WLZ_EUCLIDEAN_DISTANCE:
	errNum = WLZ_ERR_UNIMPLEMENTED;
	break;
      default:
        errNum = WLZ_ERR_PARAM_DATA;
	break;
    }
  }
  /* Create scaled domains and a sphere domain for structual erosion if the
   * distance function is approximate Euclidean. */
  if(errNum == WLZ_ERR_NONE)
  {
    if(dFn == WLZ_APX_EUCLIDEAN_DISTANCE)
    {
      tr = (dim == 2)?
	   WlzAffineTransformFromScale(WLZ_TRANSFORM_2D_AFFINE,
	                               scale, scale, 0.0, &errNum):
	   WlzAffineTransformFromScale(WLZ_TRANSFORM_3D_AFFINE,
	                               scale, scale, scale, &errNum);
      if(errNum == WLZ_ERR_NONE)
      {
	tmpObj = WlzMakeMain(forObj->type, forObj->domain, nullVal,
			     NULL, NULL, &errNum);
	if(tmpObj)
	{
	  sForObj = WlzAssignObject(
	            WlzAffineTransformObj(tmpObj, tr,
		                          WLZ_INTERPOLATION_NEAREST,
		    			  &errNum), NULL);
	  (void )WlzFreeObj(tmpObj);
	}
      }
      if(errNum == WLZ_ERR_NONE)
      {
	if(refObj->type == WLZ_POINTS)
	{
	  sRefObj = WlzPointsToDomObj(refObj->domain.pts, scale, &errNum);
	}
	else /* type == WLZ_2D_DOMAINOBJ || type == WLZ_3D_DOMAINOBJ */
	{
	  tmpObj = WlzMakeMain(refObj->type, refObj->domain, nullVal,
			       NULL, NULL, &errNum);
	  if(errNum == WLZ_ERR_NONE)
	  {
	    sRefObj = WlzAssignObject(
		      WlzAffineTransformObj(tmpObj, tr,
					    WLZ_INTERPOLATION_NEAREST,
					    &errNum), NULL);
	  }
	}
	(void )WlzFreeObj(tmpObj);
      }
      if(errNum == WLZ_ERR_NONE)
      {
	sObj = WlzAssignObject(
	       WlzMakeSphereObject(forObj->type, scale,
	                           0.0, 0.0, 0.0, &errNum), NULL);
      }
      (void )WlzFreeAffineTransform(tr);
    }
    else
    {
      sForObj = WlzAssignObject(
	        WlzMakeMain(forObj->type, forObj->domain, nullVal,
	  		    NULL, NULL, &errNum), NULL);
      if(errNum == WLZ_ERR_NONE)
      {
	if(refObj->type == WLZ_POINTS)
	{
	  sRefObj = WlzPointsToDomObj(refObj->domain.pts, 1.0, &errNum);
	}
	else
	{
	  sRefObj = WlzAssignObject(
		    WlzMakeMain(refObj->type, refObj->domain, nullVal,
				NULL, NULL, &errNum), NULL);
	}
      }
    }
  }
  /* Create new values for the computed distances. */
  if(errNum == WLZ_ERR_NONE)
  {
    dstGType = WlzGreyTableType(WLZ_GREY_TAB_RAGR, WLZ_GREY_INT, NULL);
    if(dim == 2)
    {
      dstVal.v = WlzNewValueTb(sForObj, dstGType, bgdV, &errNum);
    }
    else
    {
      dstVal.vox = WlzNewValuesVox(sForObj, dstGType, bgdV, &errNum);
    }
  }
  /* Create a distance object using the foreground object's domain and
   * the new distance values. */
  if(errNum == WLZ_ERR_NONE)
  {
    dstObj = WlzMakeMain(sForObj->type, sForObj->domain, dstVal,
			 NULL, NULL, &errNum);
  }
  if(errNum == WLZ_ERR_NONE)
  {
    bothObj[0] = sForObj;
    errNum = WlzGreySetValue(dstObj, dstV);
  }
  /* Dilate the reference object while setting the distances in each
   * dilated shell. */
  while((errNum == WLZ_ERR_NONE) && notDone)
  {
    if(dFn == WLZ_APX_EUCLIDEAN_DISTANCE)
    {
      dstV.v.dbv += 1.0;
    }
    else
    {
      switch(con)
      {
	case WLZ_4_CONNECTED:
	  dstV.v.dbv += nrmDist4;
	  break;
	case WLZ_6_CONNECTED:
	  dstV.v.dbv += nrmDist6;
	  break;
	case WLZ_8_CONNECTED:
	  dstV.v.dbv += nrmDist8;
	  break;
	case WLZ_18_CONNECTED:
	  dstV.v.dbv += nrmDist18;
	  break;
	case WLZ_26_CONNECTED:
	  dstV.v.dbv += nrmDist26;
	  break;
        default:
	  errNum = WLZ_ERR_CONNECTIVITY_TYPE;
	  break;
      }
    }
    if(dFn == WLZ_APX_EUCLIDEAN_DISTANCE)
    {
      dilObj = WlzStructDilation(sRefObj, sObj, &errNum);
    }
    else
    {
      dilObj = WlzDilation(sRefObj, con, &errNum);
    }
    if(errNum == WLZ_ERR_NONE)
    {
      switch(sForObj->type)
      {
        case WLZ_2D_DOMAINOBJ:
	  curItrObj = WlzAssignObject(
	              WlzIntersect2(dilObj, sForObj, &errNum), NULL);
	  break;
        case WLZ_3D_DOMAINOBJ:
	  bothObj[1] = dilObj;
	  curItrObj = WlzAssignObject(
	              WlzIntersectN(2, bothObj, 1, &errNum), NULL);
	  break;
        default:
	  errNum = WLZ_ERR_OBJECT_TYPE;
	  break;
      }
    }
    (void)WlzFreeObj(dilObj);
    /* Create difference object for the expanding shell. */
    if(errNum == WLZ_ERR_NONE)
    {
      difObj = WlzDiffDomain(curItrObj, sRefObj, &errNum);
    }
    if((difObj == NULL) || WlzIsEmpty(difObj, &errNum))
    {
      notDone = 0;
    }
    else
    {
      /* Assign the distance object's values to the difference object
       * and set all it's values to the current distance. */
      if(errNum == WLZ_ERR_NONE)
      {
	switch(sForObj->type)
	{
	  case WLZ_2D_DOMAINOBJ:
	    difObj->values = WlzAssignValues(dstObj->values, NULL);
	    errNum = WlzGreySetValue(difObj, dstV);
	    break;
	  case WLZ_3D_DOMAINOBJ:
	    /* 3D is more complex than 2D: Need to create a temporary
	     * voxel valuetable and assign the individual 2D values. */
	    difVal.vox = WlzMakeVoxelValueTb(WLZ_VOXELVALUETABLE_GREY,
					     difObj->domain.p->plane1,
					     difObj->domain.p->lastpl,
					     bgdV, NULL, &errNum);
	    if(errNum == WLZ_ERR_NONE)
	    {
	      difObj->values = WlzAssignValues(difVal, NULL);
	      difDoms = difObj->domain.p->domains;
	      difVals = difObj->values.vox->values;
	      idP = difObj->domain.p->plane1;
	      lastP = difObj->domain.p->lastpl;
	      while(idP <= lastP)
	      {
		if((*difDoms).core)
		{
		  dstVal = dstObj->values.vox->values[idP - 
						      dstObj->domain.p->plane1];
		  *difVals = WlzAssignValues(dstVal, NULL);
		}
		++idP;
		++difDoms;
		++difVals;
	      }
	      if(difObj->domain.p->lastpl > difObj->domain.p->plane1)
	      {
		errNum = WlzGreySetValue(difObj, dstV);
	      }
	    }
	    break;
	  default:
	    errNum = WLZ_ERR_OBJECT_TYPE;
	    break;
	}
      }
      (void )WlzFreeObj(sRefObj);
      sRefObj = WlzAssignObject(curItrObj, NULL);
      (void )WlzFreeObj(curItrObj);
    }
    (void )WlzFreeObj(difObj); difObj = NULL;
    if(dFn == WLZ_OCTAGONAL_DISTANCE)
    {
      /* Alternate connectivities for octagonal distance. */
      if(dim == 2)
      {
	con = (con == WLZ_4_CONNECTED)? WLZ_8_CONNECTED: WLZ_4_CONNECTED;
      }
      else /* dim == 3 */
      {
	con = (con == WLZ_6_CONNECTED)? WLZ_26_CONNECTED: WLZ_6_CONNECTED;
      }
    }
  }
  (void )WlzFreeObj(sObj);
  (void )WlzFreeObj(sForObj);
  (void )WlzFreeObj(sRefObj);
  (void )WlzFreeObj(curItrObj);
  if((errNum == WLZ_ERR_NONE) && (dFn == WLZ_APX_EUCLIDEAN_DISTANCE))
  {
    tmpObj = WlzDistSample(dstObj, dim, scale, &errNum);
    (void )WlzFreeObj(dstObj);
    dstObj = tmpObj;
  }
  if(errNum != WLZ_ERR_NONE)
  {
    (void )WlzFreeObj(dstObj); dstObj = NULL;
  }
  if(dstErr)
  {
    *dstErr = errNum;
  }
  return(dstObj);
}
Example #15
0
void warpSetSignalDomain(
  WlzIVertex2	*selVtx)
{
  WlzErrorNum	errNum=WLZ_ERR_NONE;
  WlzPixelV	threshV, threshV1;
  WlzObject	*obj, *obj1;
  WlzUInt	combineMode;

  /* image processing sequence */
  if( warpGlobals.sgnlThreshObj == NULL ){
    warpSetSignalThreshObj();
  }
  if( warpGlobals.sgnlThreshObj ){
    obj1 = WlzAssignObject(warpGlobals.sgnlThreshObj, &errNum);
  }
  else {
    return;
  }

  /* threshold the resultant image */
  if( errNum == WLZ_ERR_NONE ){
    switch( warpGlobals.thresholdType ){
    case WLZ_RGBA_THRESH_NONE:
      break;

    case WLZ_RGBA_THRESH_SINGLE:
      threshV.type = WLZ_GREY_INT;
      threshV.v.inv = warpGlobals.threshRangeLow;
      if( obj1 ){
	/* clear signal object */
	if( warpGlobals.sgnlObj ){
	  WlzFreeObj(warpGlobals.sgnlObj);
	}
	  
	if((obj = WlzThreshold(obj1, threshV, WLZ_THRESH_HIGH, &errNum)) && (WlzVolume(obj, &errNum) > 0)){
	  obj = WlzAssignObject(obj, &errNum);
	  WlzFreeObj(obj1);
	  threshV.v.inv = warpGlobals.threshRangeHigh + 1;
	  if((obj1 = WlzThreshold(obj, threshV, WLZ_THRESH_LOW, &errNum)) && (WlzVolume(obj1, &errNum) > 0)){
	    warpGlobals.sgnlObj = WlzAssignObject(obj1, &errNum);
	  }
	  else {
	    if( obj1 ){
	      WlzFreeObj(obj1);
	    }
	    warpGlobals.sgnlObj = NULL;
	  }
	  WlzFreeObj(obj);
	}
	else {
	  if( obj ) {
	    WlzFreeObj(obj);
	  }
	  WlzFreeObj(obj1);
	  warpGlobals.sgnlObj = NULL;
	}
      }
      break;

    case WLZ_RGBA_THRESH_MULTI:
      /* clear signal object */
      if( warpGlobals.sgnlObj ){
	WlzFreeObj(warpGlobals.sgnlObj);
      }

      /* set the thresholds and combine mode */
      threshV.type = WLZ_GREY_RGBA;
      WLZ_RGBA_RGBA_SET(threshV.v.rgbv,
			warpGlobals.threshRangeRGBLow[0],
			warpGlobals.threshRangeRGBLow[1],
			warpGlobals.threshRangeRGBLow[2],
			255);
      threshV1.type = WLZ_GREY_RGBA;
      WLZ_RGBA_RGBA_SET(threshV1.v.rgbv,
			warpGlobals.threshRangeRGBHigh[0],
			warpGlobals.threshRangeRGBHigh[1],
			warpGlobals.threshRangeRGBHigh[2],
			255);
      WLZ_RGBA_RGBA_SET(combineMode,
			WLZ_BO_AND, WLZ_BO_AND, WLZ_BO_AND, 255);

      /* use multi-threshold */
      if((obj = WlzRGBAMultiThreshold(obj1, threshV, threshV1,
				      combineMode, &errNum))){
	if( WlzIsEmpty(obj, &errNum) ){
	    WlzFreeObj(obj);
	    warpGlobals.sgnlObj = NULL;
	} else {
	    warpGlobals.sgnlObj = WlzAssignObject(obj, &errNum);
	}
      }
      else {
	warpGlobals.sgnlObj = NULL;
      }
      WlzFreeObj(obj1);
      break;

    case WLZ_RGBA_THRESH_BOX:
      /* clear signal object */
      if( warpGlobals.sgnlObj ){
	WlzFreeObj(warpGlobals.sgnlObj);
      }

      /* use box-threshold */
      if((obj = WlzRGBABoxThreshold(obj1,
				    warpGlobals.lowRGBPoint,
				    warpGlobals.highRGBPoint,
				    &errNum))){
	if( WlzIsEmpty(obj, &errNum) ){
	    WlzFreeObj(obj);
	    warpGlobals.sgnlObj = NULL;
	} else {
	    warpGlobals.sgnlObj = WlzAssignObject(obj, &errNum);
	}
      }
      else {
	warpGlobals.sgnlObj = NULL;
      }
      WlzFreeObj(obj1);	  
      break;

    case WLZ_RGBA_THRESH_SLICE:
      /* clear signal object */
      if( warpGlobals.sgnlObj ){
	WlzFreeObj(warpGlobals.sgnlObj);
      }

      /* use slice-threshold */
      if((obj = WlzRGBASliceThreshold(obj1,
				      warpGlobals.lowRGBPoint,
				      warpGlobals.highRGBPoint,
				      &errNum))){
	if( WlzIsEmpty(obj, &errNum) ){
	    WlzFreeObj(obj);
	    warpGlobals.sgnlObj = NULL;
	} else {
	    warpGlobals.sgnlObj = WlzAssignObject(obj, &errNum);
	}
      }
      else {
	warpGlobals.sgnlObj = NULL;
      }
      WlzFreeObj(obj1);	  
      break;

    case WLZ_RGBA_THRESH_SPHERE:
      /* clear signal object */
      if( warpGlobals.sgnlObj ){
	WlzFreeObj(warpGlobals.sgnlObj);
      }

      /* use Ellipsoid-threshold */
      if((obj = WlzRGBAEllipsoidThreshold(obj1,
					  warpGlobals.lowRGBPoint,
					  warpGlobals.highRGBPoint,
					  warpGlobals.colorEllipseEcc,
					  &errNum))){
	if( WlzIsEmpty(obj, &errNum) ){
	    WlzFreeObj(obj);
	    warpGlobals.sgnlObj = NULL;
	} else {
	    warpGlobals.sgnlObj = WlzAssignObject(obj, &errNum);
	}
      }
      else {
	warpGlobals.sgnlObj = NULL;
      }
      WlzFreeObj(obj1);	  
      break;

    default:
      errNum = WLZ_ERR_PARAM_DATA;
      if( obj1 ){
	WlzFreeObj(obj1);
      }
      if( warpGlobals.sgnlObj ){
	WlzFreeObj(warpGlobals.sgnlObj);
	warpGlobals.sgnlObj = NULL;
      }
      break;
    }
  }

  /* check for local mode */
  if( warpGlobals.sgnlObj && !warpGlobals.globalThreshFlg ){
    if( selVtx != NULL ){
      warpGlobals.globalThreshVtx = *selVtx;
    }
    /* extract a local domain if the vertex is sensible */
    if( warpGlobals.globalThreshVtx.vtX != -10000 ){
      WlzObject	**objs=NULL;
      int	i, numObjs;
      double	x, y;
      obj1 = NULL;
      x = warpGlobals.globalThreshVtx.vtX;
      y = warpGlobals.globalThreshVtx.vtY;
      errNum = WlzLabel(warpGlobals.sgnlObj, &numObjs, &objs, 8192, 0,
			WLZ_4_CONNECTED);
      if( (errNum == WLZ_ERR_INT_DATA) && (numObjs == 8192) ){
	WlzObject	*tmpObj1, *tmpObj2;
	WlzDomain	domain;
	WlzValues	values;

	/* try again, smaller domain */
	for(i=0; i < numObjs; i++){
	  WlzFreeObj( objs[i] );
	}
	AlcFree((void *) objs);
	objs = NULL;
	numObjs = 0;
	domain.i = WlzMakeIntervalDomain(WLZ_INTERVALDOMAIN_RECT,
					 y - 80, y + 80,
					 x - 80, x + 80, &errNum);
	values.core = NULL;
	if((tmpObj1 = WlzMakeMain(warpGlobals.sgnlObj->type, domain, values,
				  NULL, NULL, &errNum))){
	  if((tmpObj2 = WlzIntersect2(warpGlobals.sgnlObj, tmpObj1, &errNum))){
	    tmpObj2->values = WlzAssignValues(warpGlobals.sgnlObj->values, NULL);
	    errNum = WlzLabel(warpGlobals.sgnlObj, &numObjs, &objs, 8192, 0,
			      WLZ_4_CONNECTED);
	    WlzFreeObj(tmpObj2);
	    if((errNum == WLZ_ERR_INT_DATA) && (numObjs == 8192) ){
	      errNum = WLZ_ERR_NONE;
	    }
	  }
	  WlzFreeObj(tmpObj1);
	}
	
      }
      if( errNum == WLZ_ERR_NONE ){

	for(i=0; i < numObjs; i++){
	  if( WlzInsideDomain( objs[i], 0.0, y, x, NULL ) ){
	    obj1 = WlzMakeMain(objs[i]->type,
			       objs[i]->domain,
			       objs[i]->values,
			       NULL, NULL, NULL);
	    obj1 = WlzAssignObject(obj1, NULL);
	  }
	  WlzFreeObj( objs[i] );
	}
	AlcFree((void *) objs);
      }
      if( obj1 ){
	WlzFreeObj(warpGlobals.sgnlObj);
	warpGlobals.sgnlObj = obj1;
      }
    }
    else {
      WlzFreeObj(warpGlobals.sgnlObj);
      warpGlobals.sgnlObj = NULL;
    }
  }

  /* check for increment mode */
  if( warpGlobals.incrThreshFlg && sgnlIncrObj() ){
    if( warpGlobals.sgnlObj ){
      if((obj1 = WlzUnion2(warpGlobals.sgnlObj, sgnlIncrObj(),
			   &errNum))){
	WlzFreeObj(warpGlobals.sgnlObj);
	warpGlobals.sgnlObj = WlzAssignObject(obj1, &errNum);
      }
    }
    else {
      warpGlobals.sgnlObj = WlzAssignObject(sgnlIncrObj(),
					    &errNum);
    }
  }

  if( errNum != WLZ_ERR_NONE ){
    MAPaintReportWlzError(globals.topl, "warpSetSignalDomain", errNum);
  }
  return;
}
Example #16
0
/*!
* \return	RCC classification of the given objects, ie object 0 is a
*               returned classification of object 1.
* \ingroup	WlzBinaryOps
* \brief	The given pair of spatial domain objects are classified
*		using a RCC with optional enclosure and offset classifications.
*
*		For an explanation of RCC8 classifications
*		see the type definition ::WlzRCCClass and the paper:
*		D.A. Randell, etal,
*		"Discrete Mereotopology for Spatial Reasoning in
*		Automated Histological Image Analysis", PAMI 35(3) 2013.
*		The RCC8 has been extended to include both tangential and
*		non-tangential surrounds.
*
* 		The RCC classification is performed using simple combinations
* 		of the Woolz union, intersection, exclusive or, dilation,
* 		fill and convex hull operators on an ordered pair of
* 		spatial domains(\f$\Omega_0\f$ and \f$\Omega_1\f$):
*               \f{eqnarray*}{
                  C_0 &\leftarrow&
		    \Omega_0   \cap \Omega_1
		    \neq \emptyset \\
                  C_1 &\leftarrow&
		    \Omega_0^+ \cap \Omega_1
		    \neq \emptyset \\
                  C_2 &\leftarrow&
		    (\Omega_0   \oplus \Omega_1)
		    \neq \emptyset \\
                  C_3 &\leftarrow&
		    (\Omega_0   \cup \Omega_1)   \oplus
		    \Omega_1 
		    \neq \emptyset \\
                  C_4 &\leftarrow&
		    (\Omega_0^+ \cup \Omega_1)   \oplus
		    \Omega_1 
		    \neq \emptyset \\
                  C_5 &\leftarrow&
		    (\Omega_0   \cup \Omega_1)   \oplus
		    \Omega_0 
		    \neq \emptyset \\
                  C_6 &\leftarrow&
		    (\Omega_0   \cup \Omega_1^+) \oplus
		    \Omega_0 
		    \neq \emptyset \\
		  C_7 &\leftarrow&
		    (\Omega_0^{\bullet} \cup \Omega_1) \oplus
		    \Omega_0^{\bullet}
		    \neq \emptyset \\
		  C_8 &\leftarrow&
		    (\Omega_0 \cup \Omega_1^{\bullet}) \oplus
		    \Omega_1^{\bullet}
		    \neq \emptyset \\
		  C_9 &\leftarrow&
		    2|\Omega_0 \cap \Omega_1^{\circ}|   \ge |\Omega_0| \\
		  C_{10} &\leftarrow&
		    2|\Omega_0^{\circ}   \cap \Omega_1| \ge |\Omega_1|
  		\f}
*		where
*		  are the \f$\cup\f$, \f$\cap\f$ and \f$\oplus\f$
*		  are the set union (logical or), intersection (logical and)
*		  and xor (logical exclusive or) operators;
*		  \f$\Omega^+\f$ indicates the dilation of \f$\Omega\f$,
*		  \f$\Omega^{\circ}\f$ the convex hull of \f$\Omega\f$,
*		  \f$\Omega^{\bullet}\f$ indicates \f$\Omega\f$ filled and
*		  \f$|\Omega|\f$ the cardinality (area or volume) of
*		  \f$\Omega\f$.
* 		The decision tree for the classification excluding
* 		enclosure and offset is:
* 		\f[
C_0
\left\{
\begin{array}{ll}
0 & C_1
    \left\{
    \begin{array}{ll}
    0 & C_7
	\left\{
	\begin{array}{ll}
	0 & NTSURI \\
	  & \\
	  & \\
	1 & C_8
	    \left\{
	    \begin{array}{ll}
	    0 & NTSUR \\
	      & \\
	    1 & DC
	    \end{array}
	    \right. \\
	\end{array}
	\right. \\
      & \\
      & \\
    1 & C_7
	\left\{
	\begin{array}{ll}
	0 & TSURI \\
	  & \\
	  & \\
	1 & C_8
	    \left\{
	    \begin{array}{ll}
	    0 & TSUR \\
	      & \\
	    1 & EC
	    \end{array}
	    \right. \\
	\end{array}
	\right. \\
    \end{array}
    \right. \\
  & \\
  & \\
1 & C_2
    \left\{
    \begin{array}{ll}
    0 & EQ \\
      & \\
      & \\
    1 & C_3
	\left\{
	\begin{array}{ll}
	0 & C_4
	    \left\{
	    \begin{array}{ll}
	    0 & NTPP \\
	      & \\
	    1 & TPP
	    \end{array}
	    \right. \\
	  & \\
	  & \\
	1 & C_5
	    \left\{
	    \begin{array}{ll}
	    0 & C_6
		\left\{
		\begin{array}{ll}
		0 & NTPPI \\
		 & \\
		1 & TPPI
		\end{array}
		\right. \\
	      & \\
	    1 & PO
	    \end{array}
	    \right. \\
	\end{array}
	\right. \\
    \end{array}
    \right. \\
\end{array}
\right.
		\f]
*		The statistics are computed for each classification
*		as below:
* 		<table width="500" border="0">
		<caption>
		  Basic Morphological Operations for the RCC Spatial
		  Relationships
		</caption>
                <tr>
                  <td>RCC</td>
		  <td>Normalised Volume</td>
                </tr>
		<tr>
		  <td>\f$EMPTY(\Omega_0,\Omega_1)\f$</td>
		  <td>0.0</td>
		</tr>
		<tr>
		  <td>\f$DC(\Omega_0,\Omega_1)\f$</td>
		  <td>0.0</td>
		</tr>
		<tr>
		  <td>\f$EC(\Omega_0,\Omega_1)\f$</td>
		  <td>0.0</td>
		</tr>
		<tr>
		  <td>\f$EQ(\Omega_0,\Omega_1)\f$</td>
		  <td>1.0</td>
		</tr>
		<tr>
		  <td>\f$PO(\Omega_0,\Omega_1)\f$</td>
		  <td>\f$|\Omega_0 \cap \Omega_1|/
		         |\Omega_0 \cup \Omega_1|\f$</td>
		</tr>
		<tr>
		  <td>\f$TPP(\Omega_0,\Omega_1)\f$</td>
		  <td>\f$|\Omega_0|/|\Omega_0 \cup \Omega_1|\f$</td>
		</tr>
		<tr>
		  <td>\f$NTPP(\Omega_0,\Omega_1)\f$</td>
		  <td>\f$|\Omega_0|/|\Omega_0 \cup \Omega_1|\f$</td>
		</tr>
		<tr>
		  <td>\f$TPPI(\Omega_0,\Omega_1)\f$</td>
		  <td>\f$|\Omega_1|/|\Omega_0 \cup \Omega_1|\f$</td>
		</tr>
		<tr>
		  <td>\f$NTPPI(\Omega_0,\Omega_1)\f$</td>
		  <td>\f$|\Omega_1|/|\Omega_0 \cup \Omega_1|\f$</td>
		</tr>
		<tr>
		  <td>\f$TSUR(\Omega_0,\Omega_1)\f$</td>
		  <td>\f$|\Omega_0|/|\Omega_0 \cup \Omega_1|\f$</td>
		</tr>
		<tr>
		  <td>\f$TSURI(\Omega_0,\Omega_1)\f$</td>
		  <td>\f$|\Omega_1|/|\Omega_0 \cup \Omega_1|\f$</td>
		</tr>
		<tr>
		  <td>\f$NTSUR(\Omega_0,\Omega_1)\f$</td>
		  <td>\f$|\Omega_0|/|\Omega_0 \cup \Omega_1|\f$</td>
		</tr>
		<tr>
		  <td>\f$NTSURI(\Omega_0,\Omega_1)\f$</td>
		  <td>\f$|\Omega_1|/|\Omega_0 \cup \Omega_1|\f$</td>
		</tr>
		<tr>
		  <td>\f$ENC(\Omega_0,\Omega_1)\f$</td>
		  <td>\f$|\Omega_0 \cap \Omega_1^{\circ}|/|\Omega_0|\f$</td>
		</tr>
		<tr>
		  <td>\f$ENCI(\Omega_0,\Omega_1)\f$</td>
		  <td>\f$|\Omega_0^{\circ} \cap \Omega_1|/|\Omega_1|\f$</td>
		</tr>
		<tr>
		  <td>\f$OST(\Omega_0,\Omega_1)\f$</td>
		  <td>\f$q_1/(q_1 + q_2 - q_0)\f$</td>
		</tr>
		</table>
*
*		Many of the objects that are computed during the
*		classification are done so using a lazy evaluation with the
*		functions WlzRCCMakeC() and WlzRCCMakeT().
*
*		Enclosure and offset are somwhat more expensive to compute
*		than the other classifications, for this reason and because
*		they are not strictly part of a RCC they can be avoided by
*		setting the noEnc or noOst flags.
*
*		Enclosure will be computed if the noEnc has not been set and
*		the classification is not one of WLZ_RCC_EQ, WLZ_RCC_TSUR,
*		WLZ_RCC_TSURI, WLZ_RCC_NTSUR or WLZ_RCC_NTSURI.
*		Enclosure is computed using:
*		\f[
		  |\Omega_0 \cap \Omega_1^{\circ}|/|\Omega_0|
		\f]
*		for \f$\Omega_0\f$ to be encloded by \f$\Omega_1\f$ then
*		at least half of \f$\Omega_0\f$ must intersect the convex
*		hull of \f$\Omega_1\f$.
*
*		Offset will be computed if the noOst parameter has not
*		been set and the classification is not WLZ_RCC_EQ.
*		Offset is computed within a restricted domain in which
*		all pixels/voxels are equidistant for the domains of the
*		given objects:
		\f[
		\Omega_e = (\Omega_0 \cup \Omega_1)^\circ \cap
		           \Omega_0^{+d_{max}} \cap
			   \Omega_1^{+d_{max}} \cap
			   \Omega(D(\Omega_0) = D(\Omega_1))
		\f]
*		where \f$D(\Omega)\f$ is the distance transform of the domain
*		\f$\Omega\f$. Within \f$\Omega_e\f$ the first, second and
*		third quantiles (\f$q_0\f$, \f$q_1\f$ and \f$q_2\f$) of
*		the distances \f$D(\Omega_0)\f$ (or equivalently
*		\f$D(\Omega_1)\f$) are computed. The ratio of the median
*		to the median plus interquartile range is then computed
*		and the domains are classified as offset if this ratio
*		is greater than or equal to one half:
*		\f[
		\frac{q_1}{q_1 + q_2 - q_0} \geq 0.5
		\f]
* \param	obj0			First given spatial domain object.
* \param	obj1			Second given spatial domain object.
* \param	noEnc			Don't include enclosure if non-zero.
* \param	noOst			Don't include offset if non-zero.
* \param	maxOstDist		Maximum distance for offset, not
* 					used if noOst is non-zero.
* \param	dstStatCnt		Destination pointer for the number
* 					of elements returned in the array of
* 					statistics (see above), may be NULL.
* 					Ignored if dstStatAry is NULL.
* \param	dstStatAry		Destination pointer for an array of
* 					statistics (see above), may be NULL.
* 					If an array is returned it should be
* 					freed using AlcFree().
* \param	dstErr			Destination error pointer, may be NULL.
*/
WlzRCCClass 			WlzRegConCalcRCC(
				  WlzObject *obj0,
				  WlzObject *obj1,
				 int noEnc,
				 int noOst,
				 int maxOstDist,
				 int *dstStatCnt,
				 double **dstStatAry,
				 WlzErrorNum *dstErr)
{
  int 		i;
  WlzLong	i01 = 0, 		/* |\Omega_0 \cap \Omega_1| */
  		u01 = 0; 		/* |\Omega_0 \cup \Omega_1| */
  WlzLong	u[2] = {0},		/* |\Omega_i|, i \in 0 \cdots 1 */
  		v[2] = {0};		/* |c_9|, |c_{10}| */
  WlzObject	*c[11] = {NULL},		/* c_i, i \in 0 \cdots 10 */
		*o[2] = {NULL},		/* \Omega_i, i \in 0 \cdots 1 */
		*t[WLZ_RCCTOIDX_CNT] = {NULL}; /* Temporary object as
					in the enum WlzRCCTOIdx. */
  double	stats[WLZ_RCCIDX_CNT] = {0.0}; /* Classification statistics. */
  WlzValues	nullValues;
  WlzRCCClass	cls = WLZ_RCC_EMPTY; /* Classification mask. */
  WlzErrorNum	errNum = WLZ_ERR_NONE;

  nullValues.core = NULL;
  /* Compute classification using the decision tree. */
  if((obj0 == NULL) || (obj1 == NULL) ||
     (WlzIsEmpty(obj0, NULL) != 0) ||
     (WlzIsEmpty(obj1, NULL) != 0))
  {
    cls = WLZ_RCC_EMPTY;
  }
  else if((obj0->domain.core == NULL) || (obj1->domain.core == NULL))
  {
    errNum = WLZ_ERR_DOMAIN_NULL;
  }
  else if((obj0->type != obj1->type) ||
          ((obj0->type != WLZ_2D_DOMAINOBJ) &&
	   (obj0->type != WLZ_3D_DOMAINOBJ)))
  {
    errNum = WLZ_ERR_OBJECT_TYPE;
  }
  else if(((o[0] = WlzAssignObject(
                   WlzMakeMain(obj0->type, obj0->domain, nullValues,
  			       NULL, NULL, &errNum), NULL)) != NULL) &&
          ((o[1] = WlzAssignObject(
		   WlzMakeMain(obj1->type, obj1->domain, nullValues,
	  		       NULL, NULL, &errNum), NULL)) != NULL))
  {
    errNum = WlzRCCMakeC(o, c, t, 0);
  }
  if(errNum == WLZ_ERR_NONE)
  {
    if(WlzIsEmpty(c[0], NULL))
    {
      errNum = WlzRCCMakeC(o, c, t, 1);
      if(errNum == WLZ_ERR_NONE)
      {
	if(WlzIsEmpty(c[1], NULL))
	{
	  errNum = WlzRCCMakeC(o, c, t, 7);
	  if(errNum == WLZ_ERR_NONE)
	  {
	    if(WlzIsEmpty(c[7], NULL))
	    {
	      cls = WLZ_RCC_NTSURI;
	    }
	    else
	    {
	      errNum = WlzRCCMakeC(o, c, t, 8);
	      if(errNum == WLZ_ERR_NONE)
	      {
		if(WlzIsEmpty(c[8], NULL))
		{
		  cls = WLZ_RCC_NTSUR;
		}
		else
		{
		  cls = WLZ_RCC_DC;
		}
	      }
	    }
	  }
	}
	else
	{
	  errNum = WlzRCCMakeC(o, c, t, 7);
	  if(errNum == WLZ_ERR_NONE)
	  {
	    if(WlzIsEmpty(c[7], NULL))
	    {
	      cls = WLZ_RCC_TSURI;
	    }
	    else
	    {
	      errNum = WlzRCCMakeC(o, c, t, 8);
	      if(errNum == WLZ_ERR_NONE)
	      {
		if(WlzIsEmpty(c[8], NULL))
		{
		  cls = WLZ_RCC_TSUR;
		}
		else
		{
		  cls = WLZ_RCC_EC;
		}
	      }
	    }
	  }
	}
      }
    }
    else
    {
      errNum = WlzRCCMakeC(o, c, t, 2);
      if(errNum == WLZ_ERR_NONE)
      {
        if(WlzIsEmpty(c[2], NULL))
	{
	  cls = WLZ_RCC_EQ;
	}
	else
	{
	  errNum = WlzRCCMakeC(o, c, t, 3);
	  if(errNum == WLZ_ERR_NONE)
	  {
	    if(WlzIsEmpty(c[3], NULL))
	    {
	      errNum = WlzRCCMakeC(o, c, t, 4);
	      if(errNum == WLZ_ERR_NONE)
	      {
		if(WlzIsEmpty(c[4], NULL))
		{
		  cls = WLZ_RCC_NTPP;
		}
		else
		{
		  cls = WLZ_RCC_TPP;
		}
	      }
	    }
	    else
	    {
	      errNum = WlzRCCMakeC(o, c, t, 5);
	      if(errNum == WLZ_ERR_NONE)
	      {
		if(WlzIsEmpty(c[5], NULL))
		{
		  errNum = WlzRCCMakeC(o, c, t, 6);
		  if(errNum == WLZ_ERR_NONE)
		  {
		    if(WlzIsEmpty(c[6], NULL))
		    {
		      cls = WLZ_RCC_NTPPI;
		    }
		    else
		    {
		      cls = WLZ_RCC_TPPI;
		    }
		  }
		}
		else
		{
		  cls = WLZ_RCC_PO;
		}
	      }
	    }
	  }
	}
      }
    }
  }
  /* If enclosure is required check for it and add to classification mask. */
  if((errNum == WLZ_ERR_NONE) && (noEnc == 0) &&
     ((cls &
       (WLZ_RCC_EQ |
        WLZ_RCC_TSUR | WLZ_RCC_TSURI |
	WLZ_RCC_NTSUR | WLZ_RCC_NTSURI)) == 0))
  {
    for(i = 0; i <= 1; ++i)
    {
      errNum = WlzRCCMakeT(o, t,
                           (i == 0)? WLZ_RCCTOIDX_O0O1CI: WLZ_RCCTOIDX_O0CO1I);
      if(errNum == WLZ_ERR_NONE)
      {
        u[i] = WlzVolume(o[i], &errNum);
      }
      if(errNum == WLZ_ERR_NONE)
      {
        v[i] = WlzVolume(t[(i == 0)?
	                 WLZ_RCCTOIDX_O0O1CI: WLZ_RCCTOIDX_O0CO1I],
			 &errNum);
	if((errNum == WLZ_ERR_NONE) && (v[i] < 0))
	{
	  errNum = WLZ_ERR_DOMAIN_DATA;
	}
      }
      if(errNum != WLZ_ERR_NONE)
      {
        break;
      }
    }
    if(errNum == WLZ_ERR_NONE)
    {
      if((2 * v[0]) >= u[0])
      {
        cls |= WLZ_RCC_ENC;
      }
      if((2 * v[1]) >= u[1])
      {
        cls |= WLZ_RCC_ENCI;
      }
    }
  }
  /* Compute the maximum normalized volume for the classification(s) in the
   * classification mask. */
  if((errNum == WLZ_ERR_NONE) && (dstStatAry != NULL))
  {
    int 	i,
    		m;

    for(i = 0; i < WLZ_RCCIDX_CNT; ++i)
    {
      m = 1<<i;
      if(m & cls)
      {
	double	s = 0.0;

        switch(m)
	{
	  case WLZ_RCC_EQ:
	    s = 1.0;
	    break;
	  case WLZ_RCC_PO:
	    /* |\Omega_0 \cap \Omega_1| / |\Omega_0 \cup \Omega_1|  =
	     * u_0 / u_01 */
	    if(i01 <= 0)
	    {
	      errNum = WlzRCCMakeT(o, t, WLZ_RCCTOIDX_O0O1I);
	      if(errNum == WLZ_ERR_NONE)
	      {
	        i01 = WlzVolume(t[WLZ_RCCTOIDX_O0O1I], &errNum);
	      }
	    }
	    if((errNum == WLZ_ERR_NONE) && (u01 <= 0))
	    {
	      errNum = WlzRCCMakeT(o, t, WLZ_RCCTOIDX_O0O1U);
	      if(errNum == WLZ_ERR_NONE)
	      {
	        u01 = WlzVolume(t[WLZ_RCCTOIDX_O0O1U], &errNum);
	      }
	    }
	    if(errNum == WLZ_ERR_NONE)
	    {
	      s = (double )(i01) / (double )u01;
            }
	    break;
	  case WLZ_RCC_TSUR: /* FALLTHROUGH */
	  case WLZ_RCC_NTSUR: /* FALLTHROUGH */
	  case WLZ_RCC_TPP: /* FALLTHROUGH */
	  case WLZ_RCC_NTPP:
	    /* |\Omega_0| / |\Omega_0 \cup \Omega_1|  =
	     * u_0 / u_01 */
	    if(u[0] <= 0)
	    {
	      u[0] = WlzVolume(o[0], &errNum);
	    }
	    if(errNum == WLZ_ERR_NONE)
	    {
	      if(u01 <= 0)
	      {
	        errNum = WlzRCCMakeT(o, t, WLZ_RCCTOIDX_O0O1U);
		if(errNum == WLZ_ERR_NONE)
		{
		  u01 = WlzVolume(t[WLZ_RCCTOIDX_O0O1U], &errNum);
		}
	      }
	    }
	    if(errNum == WLZ_ERR_NONE)
	    {
	      s = (double )(u[0]) / (double )u01;
	    }
	    break;
	  case WLZ_RCC_TSURI: /* FALLTHROUGH */
	  case WLZ_RCC_NTSURI: /* FALLTHROUGH */
	  case WLZ_RCC_TPPI: /* FALLTHROUGH */
	  case WLZ_RCC_NTPPI:
	    /* |\Omega_1| / |\Omega_0 \cup \Omega_1|  =
	     * u_1 / u_01 */
	    if(u[1] <= 0)
	    {
	      u[1] = WlzVolume(o[1], &errNum);
	    }
	    if(errNum == WLZ_ERR_NONE)
	    {
	      if(u01 <= 0)
	      {
		errNum = WlzRCCMakeT(o, t, WLZ_RCCTOIDX_O0O1U);
		if(errNum == WLZ_ERR_NONE)
		{
		  u01 = WlzVolume(t[WLZ_RCCTOIDX_O0O1U], &errNum);
		}
	      }
	    }
	    if(errNum == WLZ_ERR_NONE)
	    {
	      s = (double )(u[1]) / (double )u01;
	    }
	    break;
	  case WLZ_RCC_ENC:
	    /* |\Omega_0 \cup \Omega_1^{\circ}|/|\Omega_0| =
	     * v_0 / u_0 */
	    if(u[1] >= 0)
	    {
	      s = (double )(v[0]) / (double )(u[0]);
	    }
	    break;
	  case WLZ_RCC_ENCI:
	    /* |\Omega_0^{\circ} \cup \Omega_1|/|\Omega_1| =
	     * v_1 / u_1 */
	    if(v[1] >= 0)
	    {
	      s = (double )(v[1]) / (double )(u[1]);
	    }
	    break;
	  default:
	    break;
	}
        if(errNum == WLZ_ERR_NONE)
	{
	  stats[i] = s;
	}
      }
    }
  }
  /* If offset is required check for it and add to both the classification
   * mask and statistics. */
  if((errNum == WLZ_ERR_NONE) && (noOst == 0) &&
     ((cls & WLZ_RCC_EQ) == 0))
  {
    int		ostQ[3];

    errNum = WlzRCCOffset(o, t,
                          maxOstDist, &(ostQ[0]), &(ostQ[1]), &(ostQ[2]));
    if(errNum == WLZ_ERR_NONE)
    {
#ifdef WLZ_RCC_DEBUG_OST
      (void )fprintf(stderr,
		     "WLZ_RCC_DEBUG_OST %d %d %d\n",
		     ostQ[0], ostQ[1], ostQ[2]);
#endif
      if((ostQ[1] > 0) && (ostQ[1] < maxOstDist) && (ostQ[2] >= ostQ[0]))
      {
	const double eps = 1.0e-06;

	if(ostQ[2] > ostQ[0])
	{
	  stats[WLZ_RCCIDX_OST] = (double )ostQ[1] /
		                  (double )(ostQ[2] + ostQ[1] - ostQ[0]);
	}
	else
	{
	  stats[WLZ_RCCIDX_OST] = 1.0;
	}
	if(stats[WLZ_RCCIDX_OST] > (0.5 - eps))
	{
	  cls |= WLZ_RCC_OST;
	}
      }
    }
  }
  /* Free objects. */
  for(i = 0; i < WLZ_RCCTOIDX_CNT; ++i)
  {
    (void )WlzFreeObj(t[i]);
  }
  for(i = 0; i <= 8; ++i)
  {
    (void )WlzFreeObj(c[i]);
  }
  for(i = 0; i < 2; ++i)
  {
    (void )WlzFreeObj(o[i]);
  }
  if((errNum == WLZ_ERR_NONE) && (dstStatAry != NULL))
  {
    if((*dstStatAry = (double *)
                        AlcMalloc(sizeof(double) * WLZ_RCCIDX_CNT)) == NULL)
    {
      errNum = WLZ_ERR_MEM_ALLOC;
    }
    else
    {
      (void )memcpy(*dstStatAry, stats, sizeof(double) * WLZ_RCCIDX_CNT);
      if(dstStatCnt)
      {
        *dstStatCnt = WLZ_RCCIDX_CNT;
      }
    }
  }
  if(dstErr)
  {
    *dstErr = errNum;
  }
  return(cls);
}
Example #17
0
/*!
* \return	New Woolz object without holes or NULL on error.
* \ingroup	WlzDomainOps
* \brief	Fills the holes in the given object's domain (which are by
* 		definition not connected to the outside). When the given
* 		object's domain has more than one component part, the
* 		object should first be labeled, this function should then be
* 		called for each of the labeled parts and then the union of
* 		the filled domains should be formed.
* \param	srcObj			Given 3D domain object.
* \param	dstErr			Destination error pointer, may be NULL.
*/
WlzObject 			*WlzDomainFill3D(
  				  WlzObject *srcObj,
    				  WlzErrorNum *dstErr)
{
  int		nPln = 0;
  WlzObject	*bndObj = NULL,
  		*filObj = NULL,
  		*gvnObj = NULL,
		*sedObj = NULL,
		*shlObj = NULL;
  WlzPixelV	zeroV;
  WlzValues 	nullVal;
  WlzErrorNum	errNum = WLZ_ERR_NONE;

  nullVal.core = NULL;
  zeroV.type = WLZ_GREY_UBYTE;
  zeroV.v.ubv = 0;
  if(srcObj == NULL)
  {
    errNum = WLZ_ERR_OBJECT_NULL;
  }
  else if(srcObj->type != WLZ_3D_DOMAINOBJ)
  {
    errNum = WLZ_ERR_OBJECT_TYPE;
  }
  else if(srcObj->domain.core == NULL)
  {
    errNum = WLZ_ERR_DOMAIN_NULL;
  }
  else
  {
    gvnObj = WlzMakeMain(srcObj->type, srcObj->domain, nullVal,
    		         NULL, NULL, &errNum);
  }
  /* Create a then shell 1 voxel thick just inside the given objects's
   * domain. */
  if(errNum == WLZ_ERR_NONE)
  {
    WlzObject	*difObj = NULL;

    difObj = WlzAssignObject(
	     WlzBoundaryDomain(gvnObj, &errNum), NULL);
    if(errNum == WLZ_ERR_NONE)
    {
      WlzIBox3	clipBox;

      /* Clip the dilated shell domain to make sure it stays within the
       * bounding box of the given object then all planes will align. */
      clipBox.xMin = gvnObj->domain.p->kol1;
      clipBox.yMin = gvnObj->domain.p->line1;
      clipBox.zMin = gvnObj->domain.p->plane1;
      clipBox.xMax = gvnObj->domain.p->lastkl;
      clipBox.yMax = gvnObj->domain.p->lastln;
      clipBox.zMax = gvnObj->domain.p->lastpl;
      shlObj = WlzAssignObject(
	       WlzClipObjToBox3D(difObj, clipBox, &errNum), NULL);
    }
    (void )WlzFreeObj(difObj);
  }
  /* Make sure that the bounding box of the thin shell domain fits it and
   * that it's first and last planes have interrvals. */
  if(errNum == WLZ_ERR_NONE)
  {
    errNum = WlzStandardPlaneDomain(shlObj->domain.p, NULL);
  }
  /* Create a value table for the shell object with values set to zero. */
  if(errNum == WLZ_ERR_NONE)
  {
    WlzValues	val;
    WlzObjectType tType;

    tType = WlzGreyTableType(WLZ_GREY_TAB_INTL, WLZ_GREY_UBYTE, NULL);
    val.vox = WlzMakeVoxelValueTb(WLZ_VOXELVALUETABLE_GREY,
				  shlObj->domain.p->plane1,
				  shlObj->domain.p->lastpl,
				  zeroV, NULL, &errNum);
    if(errNum == WLZ_ERR_NONE)
    {
      int	p;

      nPln = shlObj->domain.p->lastpl - shlObj->domain.p->plane1 + 1;
      shlObj->values = WlzAssignValues(val, NULL);
#ifdef _OPENMP
#pragma omp parallel for shared(shlObj)
#endif
      for(p = 0; p < nPln; ++p)
      {
	if(errNum == WLZ_ERR_NONE)
	{
	  WlzDomain dom2;
	  WlzErrorNum errNum2;

	  dom2 = shlObj->domain.p->domains[p];
	  if(dom2.core)
	  {
	    WlzValues val2;
	    WlzObject *shlObj2;
	    shlObj2 = WlzMakeMain(WLZ_2D_DOMAINOBJ, dom2, nullVal, NULL, NULL,
				&errNum2);
	    if(errNum2 == WLZ_ERR_NONE)
	    {
	      val2.i = WlzMakeIntervalValues(tType, shlObj2, zeroV, &errNum2);
	      /* WlzMakeIntervalValues() sets all values to zero. */
	    }
	    if(errNum2 == WLZ_ERR_NONE)                          
	    {
	      shlObj->values.vox->values[p] = WlzAssignValues(val2, NULL);
	    }
	    (void )WlzFreeObj(shlObj2);
	    if(errNum2 == WLZ_ERR_NONE)
	    {
#ifdef _OPENMP
#pragma omp critical
	      {
#endif
		if((errNum == WLZ_ERR_NONE) && (errNum2 != WLZ_ERR_NONE))
		{
		  errNum = errNum2;
		}
#ifdef _OPENMP
	      }
#endif
	    }
	  }
	}
      }
    }
  }
  /* Compute the (plane-wise) boundary list for the given object. */
  if(errNum == WLZ_ERR_NONE)
  {
    bndObj = WlzObjToBoundary(gvnObj, 0, &errNum);
  }
  /* Sweep down through the boundary object setting the values of
   * those voxels in the shell object to a non zero value when they
   * correspond to top level boundaries. */
  if(errNum == WLZ_ERR_NONE)
  {
    int		p;

#ifdef _OPENMP
#pragma omp parallel for shared(bndObj,shlObj)
#endif
    for(p = 0; p < nPln; ++p)
    {
      if(errNum == WLZ_ERR_NONE)
      {
	WlzDomain bDom2;

	bDom2 = bndObj->domain.p->domains[p];
	if(bDom2.core)
	{
	  WlzDomain iDom2;
	  WlzValues iVal2;
	  WlzObject *iObj2 = NULL;
	  WlzGreyValueWSpace *gVWSp = NULL;
	  WlzErrorNum errNum2 = WLZ_ERR_NONE;

	  iDom2 = shlObj->domain.p->domains[p];
	  iVal2 = shlObj->values.vox->values[p];
	  iObj2 = WlzMakeMain(WLZ_2D_DOMAINOBJ, iDom2, iVal2, NULL, NULL,
			      &errNum2);
	  if(errNum == WLZ_ERR_NONE)
	  {
	    gVWSp = WlzGreyValueMakeWSp(iObj2, &errNum2);
	  }
	  if(errNum2 == WLZ_ERR_NONE)
	  {
	    WlzBoundList *bnd,
			 *bnd2;

	    bnd2 = bDom2.b;
	    for(bnd = bnd2; bnd != NULL; bnd = bnd->next)
	    {
	      if(bnd->poly != NULL)
	      {
		WlzPolygonDomain *ply;

		ply = bnd->poly;
		if(ply)
		{
		  int	i;
		  WlzIVertex2 *vtx;

		  vtx = ply->vtx;
		  for(i = 0; i < ply->nvertices; ++i)
		  {
		    WlzGreyValueGet(gVWSp, 0, vtx[i].vtY, vtx[i].vtX);
		    *(gVWSp->gPtr[0].ubp) = 255;
		  }
		}
	      }
	    }
	  }
	  else
	  {
#ifdef _OPENMP
#pragma omp critical
	    {
#endif
	      if(errNum == WLZ_ERR_NONE)
	      {
		errNum = errNum2;
	      }
#ifdef _OPENMP
	    }
#endif
	  }
	  (void )WlzFreeObj(iObj2);
	  WlzGreyValueFreeWSp(gVWSp);
	}
      }
    }
  }
  /* Threshold the shell object, throwing away all but where the voxels
   * are set to create a seed domain. Then remove the value table from
   * the shell object and free it as it's no longer needed. */
  if(errNum == WLZ_ERR_NONE)
  {
    WlzObject	*tObj = NULL;
    WlzPixelV	tV;

    tV.type = WLZ_GREY_UBYTE;
    tV.v.ubv = 1;
    tObj = WlzAssignObject(
    	   WlzThreshold(shlObj, tV, WLZ_THRESH_HIGH, &errNum), NULL);
    if(errNum == WLZ_ERR_NONE)
    {
      sedObj = WlzAssignObject(
      	       WlzMakeMain(tObj->type, tObj->domain, nullVal,
			   NULL, NULL, &errNum), NULL);
    }
    (void )WlzFreeObj(tObj); tObj = NULL;
    if(errNum == WLZ_ERR_NONE)
    {
      tObj = WlzAssignObject(
             WlzMakeMain(shlObj->type, shlObj->domain, nullVal,
			 NULL, NULL, &errNum), NULL);
    }
    (void )WlzFreeObj(shlObj); shlObj = NULL;
    if(errNum == WLZ_ERR_NONE)
    {
      shlObj = tObj;
      tObj = NULL;
    }
    (void )WlzFreeObj(tObj);
#ifdef WLZ_DOMOMAINFILL3D_DEBUG
    {
      FILE	*fP;
      fP = fopen("debug-shlObj-00.wlz", "w");
      (void )WlzWriteObj(fP, shlObj);
      (void )fclose(fP);
    }
#endif
  }
  /* Label the shell domain using 26-connectivity in 3D and then
   * keep only those component objects which intersect the seed domain.
   * Then free the shell and seed domains replacing the shell domain
   * with the union of the intersecting labeled component objects.
   * Finaly free the intersecting component objects, keeping only the
   * new shell domain. */
  if(errNum == WLZ_ERR_NONE)
  {
    int		i,
		j,
    		nCSObj = 0;
    WlzIBox3	bBox;
    WlzObject	**csObj = NULL;

    bBox = WlzBoundingBox3I(shlObj, &errNum);
    if(errNum == WLZ_ERR_NONE)      
    {
      int	maxCSObj;

      maxCSObj = ((bBox.xMax - bBox.xMin + 1) *
      		  (bBox.yMax - bBox.yMin + 1) *
      		  (bBox.zMax - bBox.zMin + 1)) / 8;
      if(maxCSObj < 8)
      {
        maxCSObj = 8;
      }
      errNum = WlzLabel(shlObj, &nCSObj, &csObj, maxCSObj, 0,
			WLZ_26_CONNECTED);
    }
    if(errNum == WLZ_ERR_NONE)
    {
      for(i = 0; i < nCSObj; ++i)
      {
        if(!WlzHasIntersection(csObj[i], sedObj, &errNum))
	{
	  (void )WlzFreeObj(csObj[i]);
	  csObj[i] = NULL;
	}
      }
    }
    if(errNum == WLZ_ERR_NONE)
    {
      /* Squeeze out any NULL objects reseting their number.*/
      for(i = 0, j = 0; i < nCSObj; ++i)
      {
        if(csObj[i])
	{
	  csObj[j++] = csObj[i];
	}
      }
      nCSObj = j;
    }
    if(errNum == WLZ_ERR_NONE)
    {
      WlzObject	*iObj = NULL,
      		*uObj = NULL;

      uObj = WlzAssignObject(
      	     WlzUnionN(nCSObj, csObj, 0, &errNum), NULL);
      iObj = WlzAssignObject(
               WlzIntersect2(uObj, shlObj, &errNum),  NULL);
      (void )WlzFreeObj(uObj);
      (void )WlzFreeObj(shlObj);
      shlObj = iObj;
#ifdef WLZ_DOMOMAINFILL3D_DEBUG
      {
	FILE	*fP;
	fP = fopen("debug-shlObj-01.wlz", "w");
	(void )WlzWriteObj(fP, shlObj);
	(void )fclose(fP);
      }
#endif
    }
    if(csObj)
    {
      for(i = 0; i < nCSObj; ++i)
      {
        (void )WlzFreeObj(csObj[i]);
      }
      (void )AlcFree(csObj);
    }
  }
  /* Sweep down through the boundary lists again creating new boundary lists
   * which do not have boundaries that do not intersect the new shell domain.
   * Then create a new filled object from these boundary lists. */
  if(errNum == WLZ_ERR_NONE)
  {
    int		p,
    		nPlnFil;
    WlzDomain	filDom;

    nPlnFil = shlObj->domain.p->lastpl - shlObj->domain.p->plane1 + 1;
    filDom.p = WlzMakePlaneDomain(WLZ_PLANEDOMAIN_DOMAIN, 
		shlObj->domain.p->plane1, shlObj->domain.p->lastpl,
                shlObj->domain.p->line1, shlObj->domain.p->lastln,
                shlObj->domain.p->kol1, shlObj->domain.p->lastkl,
		&errNum);
#ifdef _OPENMP
#pragma omp parallel for shared(bndObj,shlObj)
#endif
    for(p = 0; p < nPlnFil; ++p)
    {
      if(errNum == WLZ_ERR_NONE)
      {
	WlzDomain bDom2;
	
	bDom2 = bndObj->domain.p->domains[p];
	if(bDom2.core)
	{
	  WlzDomain 	sDom2;
	  WlzObject	*fObj2 = NULL;
	  WlzBoundList  *newBnd = NULL;
	  WlzErrorNum	errNum2 = WLZ_ERR_NONE;

	  sDom2 = shlObj->domain.p->domains[p];
	  if(sDom2.core)
	  {
	    newBnd = WlzDomFill3DDoBound2D(bDom2.b, sDom2, &errNum2);
	    if(newBnd != NULL)
	    {
	      fObj2 = WlzBoundToObj(newBnd, WLZ_SIMPLE_FILL, &errNum2);
	      (void )WlzFreeBoundList(newBnd);
	    }
	    if(errNum2 == WLZ_ERR_NONE)
	    {
	      if(fObj2)
	      {
		filDom.p->domains[p] = WlzAssignDomain(fObj2->domain, NULL);
	      }
	    }
	    else
	    {
#ifdef _OPENMP
#pragma omp critical
	      {
#endif
		if(errNum == WLZ_ERR_NONE)
		{
		  errNum = errNum2;
		}
#ifdef _OPENMP
	      }
#endif
	    }
	    (void )WlzFreeObj(fObj2);
	  }
	}
      }
    }
    if(errNum == WLZ_ERR_NONE)
    {
      errNum = WlzStandardPlaneDomain(filDom.p, NULL);
    }
    if(errNum == WLZ_ERR_NONE)
    {
      WlzObject	*tObj0 = NULL,
      		*tObj1 = NULL;

      /* Put back any isolated voxels this function has removed. */
      tObj0 = WlzAssignObject(
              WlzMakeMain(srcObj->type, filDom, nullVal,
      			  NULL, NULL, &errNum), NULL);
      if(errNum == WLZ_ERR_NONE)
      {
        tObj1 = WlzUnion2(gvnObj, tObj0, &errNum);
      }
      if(errNum == WLZ_ERR_NONE)
      {
	filObj = WlzMakeMain(tObj1->type, tObj1->domain, nullVal,
			     NULL, NULL, &errNum);
      }
      (void )WlzFreeObj(tObj0);
      (void )WlzFreeObj(tObj1);
    }
  }
  (void )WlzFreeObj(bndObj);
  (void )WlzFreeObj(gvnObj);
  (void )WlzFreeObj(shlObj);
  (void )WlzFreeObj(sedObj);
  if((errNum != WLZ_ERR_NONE) && (filObj != NULL))
  {
    (void )WlzFreeObj(filObj);
    filObj = NULL;
  }
  if(dstErr)
  {
    *dstErr = errNum;
  }
  return(filObj);
}
Example #18
0
void setup_ref_display_list_cb(
Widget	w,
XtPointer	client_data,
XtPointer	call_data)
{

  WlzPlaneDomain	*planedmn;
  WlzThreeDViewStruct	*viewStr;
  WlzErrorNum		errNum=WLZ_ERR_NONE;

  if( globals.obj == NULL || globals.obj->type != WLZ_3D_DOMAINOBJ ||
     globals.ref_display_list == 0){
    return;
  }
  /* create a new display list */
  glDeleteLists(globals.ref_display_list, 1);
  globals.ref_display_list = glGenLists( (GLsizei) 1 );

  planedmn = globals.obj->domain.p;

  /* create the reference object 3D display  DisplayList */
  glNewList( globals.ref_display_list, GL_COMPILE );

  glBegin(GL_LINES);
  glColor3f(1.0, 0.0, 0.0);
  glIndexi( (int) HGU_XGetColorPixel(globals.dpy, globals.cmap, 1.0, 0.0, 0.0) );
  glVertex3i(planedmn->kol1, planedmn->line1, planedmn->plane1);
  glVertex3i(planedmn->lastkl, planedmn->line1, planedmn->plane1);
  glVertex3i(planedmn->kol1, planedmn->line1, planedmn->lastpl);
  glVertex3i(planedmn->lastkl, planedmn->line1, planedmn->lastpl);
  glVertex3i(planedmn->kol1, planedmn->lastln, planedmn->plane1);
  glVertex3i(planedmn->lastkl, planedmn->lastln, planedmn->plane1);
  glVertex3i(planedmn->kol1, planedmn->lastln, planedmn->lastpl);
  glVertex3i(planedmn->lastkl, planedmn->lastln, planedmn->lastpl);

  glColor3f(0.0, 1.0, 0.0);
  glIndexi( (int) HGU_XGetColorPixel(globals.dpy, globals.cmap, 0.0, 1.0, 0.0) );
  glVertex3i(planedmn->kol1, planedmn->line1, planedmn->plane1);
  glVertex3i(planedmn->kol1, planedmn->lastln, planedmn->plane1);
  glVertex3i(planedmn->kol1, planedmn->line1, planedmn->lastpl);
  glVertex3i(planedmn->kol1, planedmn->lastln, planedmn->lastpl);
  glVertex3i(planedmn->lastkl, planedmn->line1, planedmn->plane1);
  glVertex3i(planedmn->lastkl, planedmn->lastln, planedmn->plane1);
  glVertex3i(planedmn->lastkl, planedmn->line1, planedmn->lastpl);
  glVertex3i(planedmn->lastkl, planedmn->lastln, planedmn->lastpl);

  glColor3f(0.0, 0.0, 1.0);
  glIndexi( (int) HGU_XGetColorPixel(globals.dpy, globals.cmap, 0.0, 0.0, 1.0) );
  glVertex3i(planedmn->kol1, planedmn->line1, planedmn->plane1);
  glVertex3i(planedmn->kol1, planedmn->line1, planedmn->lastpl);
  glVertex3i(planedmn->kol1, planedmn->lastln, planedmn->plane1);
  glVertex3i(planedmn->kol1, planedmn->lastln, planedmn->lastpl);
  glVertex3i(planedmn->lastkl, planedmn->line1, planedmn->plane1);
  glVertex3i(planedmn->lastkl, planedmn->line1, planedmn->lastpl);
  glVertex3i(planedmn->lastkl, planedmn->lastln, planedmn->plane1);
  glVertex3i(planedmn->lastkl, planedmn->lastln, planedmn->lastpl);
  glEnd();

  if( globals.fb_obj && (globals.fb_obj->type == WLZ_3D_DOMAINOBJ) ){
    WlzObject		*obj1, *boundobj;
    WlzValues		values;
    int			z, step;

    /* establish the step size */
    planedmn = globals.fb_obj->domain.p;
    step = (planedmn->lastkl - planedmn->kol1) / 6;
    z = (planedmn->lastln - planedmn->line1) / 6;
    step = WLZ_MIN(step, z);
    z = (planedmn->lastpl - planedmn->plane1) / 6;
    step = WLZ_MIN(step, z);

    /* set up const z boundaries */
    glColor3f(1.0, 1.0, 1.0);
    glIndexi((int) HGU_XGetColorPixel(globals.dpy, globals.cmap, 1.0, 1.0, 1.0));
    (void) glLineWidth( (GLfloat) 2.0 );
    for(z=planedmn->plane1+step/2; z <= planedmn->lastpl; z += step)
    {
      values.core = NULL;
      obj1 = WlzMakeMain(WLZ_2D_DOMAINOBJ,
			 planedmn->domains[z - planedmn->plane1],
			 values, NULL, NULL, NULL);
      if( obj1->domain.core != NULL )
      {
	boundobj = WlzObjToBoundary(obj1, 1, &errNum);
	if( boundobj != NULL )
	{
	  MAOpenGLDisplayBoundList(boundobj->domain.b, (float) z );
	  WlzFreeObj( boundobj );
	}
	if( errNum != WLZ_ERR_NONE ){
	  break;
	}
      }
      WlzFreeObj( obj1 );
    }
    (void) glLineWidth( (GLfloat) 1.0 );

    /* set up const y boundaries */
    if( errNum == WLZ_ERR_NONE ){
      glColor3f(1.0, 1.0, 0.0);
      glIndexi((int) HGU_XGetColorPixel(globals.dpy, globals.cmap, 1.0, 1.0, 0.0));
      if((viewStr = WlzMake3DViewStruct(WLZ_3D_VIEW_STRUCT, &errNum))){
	viewStr->theta = WLZ_M_PI / 2.0;
	viewStr->phi = WLZ_M_PI / 2.0;
	viewStr->dist = planedmn->line1 - step/2;
	errNum = WlzInit3DViewStruct(viewStr, globals.fb_obj);
	for(z=viewStr->dist+step; (errNum == WLZ_ERR_NONE) && (z <= planedmn->lastln);
	    z += step)
	{
	  Wlz3DSectionIncrementDistance(viewStr, (double) step);
	  if((obj1 = WlzGetSectionFromObject(globals.fb_obj, viewStr,
					     WLZ_INTERPOLATION_NEAREST,
					     &errNum))){
	    obj1 = WlzAssignObject(obj1, NULL);
	    boundobj = WlzObjToBoundary(obj1, 1, &errNum);
	    if( boundobj != NULL )
	    {
	      /* convert boundary coordinates to voxel coordinates */
	      Wlz3DSectionTransformYBound(boundobj->domain.b, viewStr);
	      MAOpenGLDisplayYBoundList(boundobj->domain.b, (float) z);
	      WlzFreeObj( boundobj );
	    }
	    WlzFreeObj( obj1 );
	  }
	}
	WlzFree3DViewStruct(viewStr);
      }
    }

    /* set up const x boundaries */
    if( errNum == WLZ_ERR_NONE ){
      glIndexi((int) HGU_XGetColorPixel(globals.dpy, globals.cmap, 1.0, 1.0, 0.0));
      glColor3f(1.0, 1.0, 0.0);
      if((viewStr = WlzMake3DViewStruct(WLZ_3D_VIEW_STRUCT, &errNum))){
	viewStr->theta = 0.0;
	viewStr->phi = WLZ_M_PI / 2.0;
	viewStr->dist = planedmn->kol1 - step/2;
	errNum = WlzInit3DViewStruct(viewStr, globals.fb_obj);
	for(z=viewStr->dist+step; (errNum == WLZ_ERR_NONE) && (z <= planedmn->lastkl);
	    z += step)
	{
	  Wlz3DSectionIncrementDistance(viewStr, (double) step);
	  if((obj1 = WlzGetSectionFromObject(globals.fb_obj, viewStr,
					     WLZ_INTERPOLATION_NEAREST,
					     &errNum))){
	    obj1 = WlzAssignObject(obj1, NULL);
	    boundobj = WlzObjToBoundary(obj1, 1, &errNum);
	    if( boundobj != NULL )
	    {
	      /* convert boundary coordinates to voxel coordinates */
	      Wlz3DSectionTransformXBound(boundobj->domain.b, viewStr);
	      MAOpenGLDisplayXBoundList(boundobj->domain.b, (float) z);
	      WlzFreeObj( boundobj );
	    }
	    WlzFreeObj( obj1 );
	  }
	}
	WlzFree3DViewStruct(viewStr);
      }
    }
  }

  if( errNum == WLZ_ERR_NONE ){
    glIndexi( (int) HGU_XGetColorPixel(globals.dpy, globals.cmap, 1.0, 1.0, 1.0) );
    glColor3f(1.0, 1.0, 1.0);
    glEndList();

    WLZ_VTX_3_SET(globals.bbox_vtx, planedmn->kol1 - 2.0,
		  planedmn->line1 - 2.0, planedmn->plane1 - 2.0);
    WLZ_VTX_3_SET(globals.bbox_size,
		  planedmn->lastkl - planedmn->kol1 + 4.0,
		  planedmn->lastln - planedmn->line1 + 4.0,
		  planedmn->lastpl - planedmn->plane1 + 4.0);
    glFogf(GL_FOG_DENSITY, 0.25/globals.bbox_size.vtX);
    MAOpenGLDrawScene( globals.canvas );
  }
  else {
    MAPaintReportWlzError(globals.topl, "setup_ref_display_list_cb", errNum);
  }

  return;
}
Example #19
0
void referenceFileListCb(
  Widget	w,
  XtPointer	client_data,
  XtPointer	call_data)
{
  HGU_XmFileListCallbackStruct	*cbs=
    (HGU_XmFileListCallbackStruct *) client_data;
  WlzObject	*obj;
  Widget	cascade;
  WlzErrorNum	errNum=WLZ_ERR_NONE;

  HGU_XmSetHourGlassCursor(globals.topl);
  if( cbs == NULL ){
    /* clear list selection */
    HGU_XmFileListClearList(globals.fileList);
    HGU_XmFileListWriteResourceFile(globals.fileList,
				    globals.resourceFile);
    if((cascade = XtNameToWidget(globals.topl,
				 "*file_menu*_pulldown*Recent"))){
      HGU_XmFileListResetMenu(globals.fileList, cascade, referenceFileListCb);
    }
  }
  else if((obj = HGU_XmFileListReadObject(w, cbs, &errNum))){
    WlzDomain	domain;
    WlzValues	values;
    WlzObject	*newObj;

    switch( obj->type ){

    case WLZ_2D_DOMAINOBJ:
      if((domain.p = WlzMakePlaneDomain(WLZ_PLANEDOMAIN_DOMAIN, 0, 0,
					obj->domain.i->line1,
					obj->domain.i->lastln,
					obj->domain.i->kol1,
					obj->domain.i->lastkl,
					&errNum))){
	domain.p->domains[0] = WlzAssignDomain(obj->domain, NULL);
	if((values.vox = WlzMakeVoxelValueTb(WLZ_VOXELVALUETABLE_GREY,
					     0, 0, WlzGetBackground(obj, NULL),
					     NULL, &errNum))){
	  values.vox->values[0] = WlzAssignValues(obj->values, NULL);
	  newObj = WlzMakeMain(WLZ_3D_DOMAINOBJ, domain, values,
			       NULL, NULL, NULL);
	  WlzFreeObj(obj);
	  obj = newObj;
	}
      }
      globals.origObjType = WLZ_2D_DOMAINOBJ;
      break;

    case WLZ_3D_DOMAINOBJ:
      globals.origObjType = WLZ_3D_DOMAINOBJ;
      break;

    default:
      HGU_XmUserError(globals.topl,
		      "Read Reference Object:\n"
		      "    The reference object must be a 2- or 3-D\n"
		      "    grey-level image. Please select an alternate\n"
		      "    object",
		      XmDIALOG_FULL_APPLICATION_MODAL);
      WlzFreeObj( obj );
      /* set hour glass cursor */
      HGU_XmUnsetHourGlassCursor(globals.topl);
      return;
    }
    MAPaintLogData("ReferenceFile", refFileList[0], 0, NULL);
    install_paint_reference_object( obj );

    /* set the title of the top-level window */
    set_topl_title(cbs->file);
    globals.file = AlcStrDup(cbs->file);
    globals.origObjExtType = cbs->format;

    /* add to the file list and write file */
    HGU_XmFileListAddFile(globals.fileList, cbs->file, cbs->format);
    HGU_XmFileListWriteResourceFile(globals.fileList,
				    globals.resourceFile);
    if((cascade = XtNameToWidget(globals.topl,
				 "*file_menu*_pulldown*Recent"))){
      HGU_XmFileListResetMenu(globals.fileList, cascade, referenceFileListCb);
    }
  }

  HGU_XmUnsetHourGlassCursor(globals.topl);

  if( errNum != WLZ_ERR_NONE ){
    MAPaintReportWlzError(globals.topl, "ReferenceFileListCb", errNum);
  }
  return;
}
Example #20
0
void file_menu_init(
  Widget	topl)
{
  Widget	rc, form, toggle;
  Visual	*visual;
  Arg		arg[1];
  char		fileStr[128];
  FILE 		*fp;
  WlzEffFormat	image_type=WLZEFF_FORMAT_WLZ;

  /* set the top-level title */
  set_topl_title(NULL);

  /* get the visual explicitly */
  visual = HGU_XmWidgetToVisual(topl);
  XtSetArg(arg[0], XmNvisual, visual);

  /* create the read-model file selection dialog */
  read_model_dialog = XmCreateFileSelectionDialog(topl,
						  "read_model_dialog", arg, 1);
  XtAddCallback(read_model_dialog, XmNokCallback,
		read_reference_object_cb, (XtPointer) WLZEFF_FORMAT_WLZ);
  XtAddCallback(read_model_dialog, XmNokCallback, PopdownCallback, NULL);
  XtAddCallback( read_model_dialog, XmNcancelCallback, 
		PopdownCallback, NULL);
  XtAddCallback(read_model_dialog, XmNmapCallback,
		FSBPopupCallback, NULL);
  XtManageChild( read_model_dialog );

  /* create the read-obj file selection dialog */
  read_obj_dialog = HGU_XmCreateExtFFObjectFSB(topl, "read_obj_dialog",
					      read_reference_object_cb, NULL);
  if((rc = XtNameToWidget(read_obj_dialog, "*.formatFormRC"))){

    /* add a form to include file type and fill-blanks toggle */
    form = XtVaCreateManagedWidget("read_file_form", xmFormWidgetClass,
				   rc,
				   XmNborderWidth,	0,
				   NULL);

    /* add a fill-blanks toggles */
    toggle = XtVaCreateManagedWidget("fill_blanks", xmToggleButtonGadgetClass,
				     form,
				     XmNindicatorOn, 	True,
				     XmNindicatorType,	XmN_OF_MANY,
				     XmNset,		False,
				     XmNtopAttachment,	XmATTACH_FORM,
				     XmNleftAttachment,	XmATTACH_FORM,
				     NULL);

    toggle = XtVaCreateManagedWidget("min_domain", xmToggleButtonGadgetClass,
				     form,
				     XmNindicatorOn, 	True,
				     XmNindicatorType,	XmN_OF_MANY,
				     XmNset,		True,
				     XmNtopAttachment,	XmATTACH_FORM,
				     XmNleftAttachment,	XmATTACH_WIDGET,
				     XmNleftWidget,	toggle,
				     NULL);
  }

  HGU_XmExtFFObjectFSBSetType(read_obj_dialog, WLZEFF_FORMAT_WLZ);
  XtManageChild( read_obj_dialog );

  /* add to the save restore list */
  HGU_XmSaveRestoreAddWidget( read_obj_dialog, HGU_XmFSD_SaveFunc,
			     (XtPointer) XtName(topl), NULL, NULL );

  /* create the write-obj file selection dialog */
  write_obj_dialog = HGU_XmCreateExtFFObjectFSB(topl, "write_obj_dialog",
					       write_reference_object_cb,
					       NULL);
  HGU_XmExtFFObjectFSBSetType(write_obj_dialog, WLZEFF_FORMAT_WLZ);


  /* initialise the reference file list pulldown */
  if( !globals.sectViewFlg ){
    Widget	cascade;

    if((cascade = XtNameToWidget(globals.topl,
				 "*file_menu*_pulldown*Recent"))){
      globals.resourceFile = (String) 
	AlcMalloc(sizeof(char) * (strlen(getenv("HOME")) + 16));
      sprintf(globals.resourceFile, "%s/%s", getenv("HOME"), ".maRecentFiles");
      globals.fileList = HGU_XmFileListCreateList(globals.resourceFile, NULL);
      HGU_XmFileListResetMenu(globals.fileList, cascade, referenceFileListCb);
    }
  }

  /* add to the save restore list */
  HGU_XmSaveRestoreAddWidget( write_obj_dialog, HGU_XmFSD_SaveFunc,
			     (XtPointer) XtName(topl), NULL, NULL );

  /* create the object properties dialog */
  obj_props_dialog_init( topl );

  globals.file      = NULL;
  globals.obj       = NULL;
  globals.orig_obj  = NULL;
  globals.fb_obj    = NULL;
  globals.origObjExtType = image_type;

  /* setup the theiler directory and menu item - check for stage */
  XtGetApplicationResources(topl, &globals, set_att_res,
			    XtNumber(set_att_res), NULL, 0);

  /* check the logfile */
  if( globals.logfile ){
    if( (globals.logfileFp = fopen(globals.logfile, "w")) == NULL ){
      fprintf(stderr,
	      "MAPaint: something wrong with the logfile %s\n"
	      "Please check name and permissions\n"
	      "Logging not enabled\n\007", globals.logfile);
    }
    else {
      char		timeBuf[16];
      struct hostent 	*hstnt;
      fprintf(stderr, "MAPaint: logging enabled to %s\n", globals.logfile);
      MAPaintLogData("Filename", globals.logfile, 0, NULL);
      MAPaintLogData("User", getenv("USER"), 0, NULL);
#if defined (LINUX2) || defined (DARWIN)
      strcpy(timeBuf, "00/00/00");
#else
      tmpTime = time(NULL);
      cftime(timeBuf, "%d/%m/%Y", &tmpTime);
#endif /* LINUX2 */
      MAPaintLogData("Date", timeBuf, 0, NULL);
#if defined (LINUX2) || defined (DARWIN)
      strcpy(timeBuf, "00.00");
#else
      cftime(timeBuf, "%H.%M", &tmpTime);
#endif /* LINUX2 */
      MAPaintLogData("Time", timeBuf, 0, NULL);
      hstnt = gethostbyname(getenv("HOST"));
      MAPaintLogData("Host", getenv("HOST"), 0, NULL);
      MAPaintLogData("Hostname", hstnt->h_name, 0, NULL);
    }
  }
  else {
    globals.logfileFp = NULL;
  }

  /* check base directory - if the string has come from the resources then
     we need to duplicate it to allow it to be freed
     possibly some memory leakage here */
  /* note: only non-NULL if set by the user, if NULL then attempt to find
     the cdrom or copied data */
  if( globals.base_theiler_dir ){
    globals.base_theiler_dir = AlcStrDup( globals.base_theiler_dir );
  }
/*  else {
    FILE	*pp;*/
    
    /* search for the Theiler mode directory as per the CDROM 
       should search local disc first */
/*#if defined (LINUX2)
    if((pp = popen("find /mnt -maxdepth 4 -name Models", "r"))){
      while( fscanf(pp, "%s", fileStr) != EOF ){
	if( strstr(fileStr, "Models") ){
	  globals.base_theiler_dir = AlcStrDup(fileStr);
	  break;
	}
      }
      pclose(pp);
    }
#elif defined (DARWIN)
    if( (pp = popen("find /Volumes -maxdepth 4 -name Models", "r")) ){
      while( fscanf(pp, "%s", fileStr) != EOF ){
	if( strstr(fileStr, "Models") ){
	  globals.base_theiler_dir = AlcStrDup(fileStr);
	  break;
	}
      }
      pclose(pp);
    }
#elif defined (SUNOS4) || defined (SUNOS5)
    if( pp = popen("find /cdrom -maxdepth 4 -name Models", "r") ){
      while( fscanf(pp, "%s", fileStr) != EOF ){
	if( strstr(fileStr, "Models") ){
	  globals.base_theiler_dir = AlcStrDup(fileStr);
	  break;
	}
      }
      pclose(pp);
    }
#else
    globals.base_theiler_dir = NULL;
#endif
  }*/
  if( globals.theiler_stage ){
    char *tStr;
    if((tStr = theilerString(globals.theiler_stage))){
      globals.theiler_stage = AlcStrDup(tStr);
    }
    else {
      globals.theiler_stage = NULL;
    }
  }
  theiler_menu_init( topl );

  /* check for an initial reference file else check Theiler stage */
  if( initial_reference_file != NULL ){
    WlzObject 	*obj;

    /* open the reference object file and install */
    if( (fp = fopen(initial_reference_file, "r")) ){
      HGU_XmSetHourGlassCursor(topl);
      if((obj = WlzReadObj( fp, NULL ))){
        WlzDomain	domain;
        WlzValues	values;
        WlzObject	*newObj;
	switch( obj->type ){

	case WLZ_2D_DOMAINOBJ:
	  domain.p = WlzMakePlaneDomain(WLZ_PLANEDOMAIN_DOMAIN, 0, 0,
					obj->domain.i->line1,
					obj->domain.i->lastln,
					obj->domain.i->kol1,
					obj->domain.i->lastkl,
					NULL);
	  domain.p->domains[0] = WlzAssignDomain(obj->domain, NULL);
	  values.vox = WlzMakeVoxelValueTb(WLZ_VOXELVALUETABLE_GREY,
					   0, 0, WlzGetBackground(obj, NULL),
					   NULL, NULL);
	  values.vox->values[0] = WlzAssignValues(obj->values, NULL);
	  newObj = WlzMakeMain(WLZ_3D_DOMAINOBJ, domain, values,
			       NULL, NULL, NULL);
	  WlzFreeObj(obj);
	  obj = newObj;
	  globals.origObjType = WLZ_2D_DOMAINOBJ;
	  break;

	case WLZ_3D_DOMAINOBJ:
	  globals.origObjType = WLZ_3D_DOMAINOBJ;
	  break;

	default:
	  HGU_XmUserError(globals.topl,
			  "Read Reference Object:\n"
			  "    The reference object must be a 2- or 3-D woolz\n"
			  "    grey-level image. Please select an alternate\n"
			  "    object",
			  XmDIALOG_FULL_APPLICATION_MODAL);
	  WlzFreeObj( obj );
	  /* set hour glass cursor */
	  HGU_XmUnsetHourGlassCursor(globals.topl);
	  return;

	}
	HGU_XmFileListAddFile(globals.fileList, initial_reference_file,
			      image_type);
	HGU_XmFileListWriteResourceFile(globals.fileList,
					globals.resourceFile);
	MAPaintLogData("ReferenceFile", initial_reference_file, 0, NULL);
	install_paint_reference_object( obj );

	/* set the globals reference file */
	globals.file = initial_reference_file;

	/* set the title of the top-level window */
	set_topl_title(globals.file);
      }
      else {
	/* if it fails to read, check the file name
	   or the file content for special options */
	if( strstr(initial_reference_file, "MAPaint") ){
	  /* standard MAPaint startup */
	  globals.app_name = "MAPaint";
	  /* set the title of the top-level window */
	  set_topl_title(globals.file);
	}
	else if( strstr(initial_reference_file, "SectionView") ){
	  /* restricted section view startup */
	  globals.app_name = "SectionView";
	  globals.sectViewFlg = 1;
	  /* set the title of the top-level window */
	  set_topl_title(globals.file);
	}
	else if( theilerString(initial_reference_file) ){
	  /* load in theiler stage anatomy etc. */
	  globals.app_name = "SectionView";
	  globals.sectViewFlg = 1;
	  set_theiler_stage_cb(topl, theilerString(initial_reference_file),
			       NULL);
	}
	else {
	  char	strBuf[33];
	  /* check the content */
	  rewind(fp);
	  fscanf(fp, "%32s", strBuf);
	  if( strstr(strBuf, "MAPaint") ){
	    /* standard MAPaint startup */
	    globals.app_name = "MAPaint";
	    /* set the title of the top-level window */
	    set_topl_title(globals.file);
	  }
	  else if( strstr(strBuf, "SectionView") ){
	    /* restricted section view startup */
	    globals.app_name = "SectionView";
	    globals.sectViewFlg = 1;
	    /* set the title of the top-level window */
	    set_topl_title(globals.file);
	  }
	  else if( theilerString(strBuf) ){
	    /* load in theiler stage anatomy etc. */
	    globals.app_name = "SectionView";
	    globals.sectViewFlg = 1;
	    set_theiler_stage_cb(topl,
				 theilerString(strBuf),
				 NULL);
	  }
	}

	/* set the globals reference file */
	globals.file = NULL;
      }
      (void) fclose( fp );

      HGU_XmUnsetHourGlassCursor(topl);
    }
  }
  else if( globals.theiler_stage ){
    globals.app_name = "MAPaint";
    set_theiler_stage_cb(topl, theilerString(globals.theiler_stage), NULL);
  }

  /* reset the colormap */
  if( globals.sectViewFlg == 1 ){
    init_paint_cmapstruct(globals.topl);
  }

  /* check for an initial domain file */
  if( initial_domain_file != NULL ){
    WlzObject 	*obj;

    /* open the domain object file and put it in as a 3D feedback option */
    if( (fp = fopen(initial_domain_file, "rb")) ){
      HGU_XmSetHourGlassCursor(topl);
      if((obj = WlzReadObj( fp, NULL ))){
	if( globals.fb_obj ){
	  WlzFreeObj(globals.fb_obj);
	}
	globals.fb_obj = WlzAssignObject(obj, NULL);
	setup_ref_display_list_cb(read_obj_dialog, NULL, NULL);
      }
      (void) fclose( fp );
      HGU_XmUnsetHourGlassCursor(topl);
    }
  }

  return;
}
Example #21
0
/*!
* \return	Object read from file.
* \ingroup	WlzExtFF
* \brief	Reads a Woolz object from the given stream using the
* 		GRUMMP vmesh tetrahedral mesh file format.
* \param	fP			Input file stream.
* \param	dstErr			Destination error number ptr, may be
* 					NULL.
*/
WlzObject	*WlzEffReadObjEMT(FILE *fP, WlzErrorNum *dstErr)
{
  int		nElm = 0,
		nNod = 0;
  char		*str;
  WlzDVertex3   *vBuf = NULL;
  WlzCMesh3D	*mesh = NULL;
  WlzObject	*obj = NULL;
  WlzErrorNum	errNum = WLZ_ERR_NONE;
  char		cBuf[256];

  if(fP == NULL)
  {
    errNum = WLZ_ERR_PARAM_NULL;
  }
  else
  {
    int		idC = 0;

    /* Optional records may be comments starting with a '#' but apart
     * from these the first line should have a single integer specifying
     * the number of nodes. */
    do
    {
      if((str = WlzEffReadObjEMTRec(fP, cBuf, 256)) == NULL)
      {
	errNum = WLZ_ERR_READ_INCOMPLETE;
      }
      else if(*str != '#')
      {
	if((idC = sscanf(str, "%d", &nNod)) != 1)
	{
	  errNum = WLZ_ERR_READ_INCOMPLETE;
	}
      }
    } while((errNum == WLZ_ERR_NONE) && (idC != 1));
  }
  /* Check for reasonable number of nodes. */
  if(errNum == WLZ_ERR_NONE)
  {
    if(nNod <= 0)
    {
      errNum = WLZ_ERR_READ_INCOMPLETE;
    }
  }
  /* Create a new 3D constrained mesh. */
  if(errNum == WLZ_ERR_NONE)
  {
    mesh = WlzCMeshNew3D(&errNum);
  }
  /* Read in the node positions into a temporary buffer computing their
   * bounding box and then create the nodes. */
  if(errNum == WLZ_ERR_NONE)
  {
    if((vBuf = AlcMalloc(sizeof(WlzDVertex3) * nNod)) == NULL)
    {
      errNum = WLZ_ERR_MEM_ALLOC;
    }
  }
  if(errNum == WLZ_ERR_NONE)
  {
    int		idN = 0;

    while(idN < nNod)
    {
      if((str = WlzEffReadObjEMTRec(fP, cBuf, 256)) == NULL)
      {
	errNum = WLZ_ERR_READ_INCOMPLETE;
	break;
      }
      else if(*str != '#')
      {
	if(sscanf(str, "%lg %lg %lg",
		  &(vBuf[idN].vtX), &(vBuf[idN].vtY), &(vBuf[idN].vtZ)) != 3)
	{
	  errNum = WLZ_ERR_READ_INCOMPLETE;
	  break;
	}
	++idN;
      }
    }
  }
  if(errNum == WLZ_ERR_NONE)
  {
    mesh->bBox = WlzBoundingBoxVtx3D(nNod, vBuf, NULL);
    if(AlcVectorExtendAndGet(mesh->res.nod.vec, nNod) == NULL)
    {
      errNum = WLZ_ERR_MEM_ALLOC;
    }
  }
  if(errNum == WLZ_ERR_NONE)
  {
    errNum = WlzCMeshReassignGridCells3D(mesh, nNod);
  }
  if(errNum == WLZ_ERR_NONE)
  {
    int		idN;

    for(idN = 0; idN < nNod; ++idN)
    {
       (void )WlzCMeshNewNod3D(mesh, vBuf[idN], NULL);
    }
  }
  AlcFree(vBuf);
  /* Read the number of elements in the mesh. */
  if(errNum == WLZ_ERR_NONE)
  {
    int		idC = 0;

    /* Optional records may be comments starting with a '#' but apart
     * from these the first line should have a single integer specifying
     * the number of nodes. */
    do
    {
      if((str = WlzEffReadObjEMTRec(fP, cBuf, 256)) == NULL)
      {
	errNum = WLZ_ERR_READ_INCOMPLETE;
      }
      else if(*str != '#')
      {
	if((idC = sscanf(str, "%d", &nElm)) != 1)
	{
	  errNum = WLZ_ERR_READ_INCOMPLETE;
	}
      }
    } while((errNum == WLZ_ERR_NONE) && (idC != 1));
  }
  /* Check for reasonable number of elements. */
  if(errNum == WLZ_ERR_NONE)
  {
    if(nElm <= 0)
    {
      errNum = WLZ_ERR_READ_INCOMPLETE;
    }
  }
  /* Allocate room for the elements in the mesh. */
  if(errNum == WLZ_ERR_NONE)
  {
    if(AlcVectorExtendAndGet(mesh->res.elm.vec, nElm) == NULL)
    {
      errNum = WLZ_ERR_MEM_ALLOC;
    }
  }
  /* Read the elements adding them to the mesh. */
  if(errNum == WLZ_ERR_NONE)
  {
    int		idE = 0;

    while(idE < nElm)
    {
      if((str = WlzEffReadObjEMTRec(fP, cBuf, 256)) == NULL)
      {
	errNum = WLZ_ERR_READ_INCOMPLETE;
	break;
      }
      else if(*str != '#')
      {
	int	dummyI;
	int	nIdx[4];
	WlzCMeshNod3D *nBuf[4];

	if((sscanf(str, "%d %d %d %d %d",
		   &dummyI,
		   &(nIdx[0]), &(nIdx[1]), &(nIdx[2]), &(nIdx[3])) != 5) ||
	   (nIdx[0] <= 0) || (nIdx[0] > nNod) ||
	   (nIdx[1] <= 0) || (nIdx[1] > nNod) ||
	   (nIdx[2] <= 0) || (nIdx[2] > nNod) ||
	   (nIdx[3] <= 0) || (nIdx[3] > nNod))
	{
	  errNum = WLZ_ERR_READ_INCOMPLETE;
	  break;
	}
	else
	{
	  int	idN;

	  for(idN = 0; idN < 4; ++idN)
	  {
	    nBuf[idN] = (WlzCMeshNod3D *)
			AlcVectorItemGet(mesh->res.nod.vec, nIdx[idN] - 1);
	  }
	  (void )WlzCMeshNewElm3D(mesh, nBuf[0], nBuf[1], nBuf[3], nBuf[2], 1,
				  &errNum);
	  if(errNum != WLZ_ERR_NONE)
	  {
	    break;
	  }
	  ++idE;
	}
      }
    }
  }
  /* Ignore the boundary faces in the file, they're redundant information. */
  if(errNum == WLZ_ERR_NONE)
  {
    WlzDomain	dom;
    WlzValues	val;

    val.core = NULL;
    dom.cm3 = mesh;
    WlzCMeshDelUnusedNodes3D(mesh);
    WlzCMeshUpdateMaxSqEdgLen3D(mesh);
    obj = WlzMakeMain(WLZ_CMESH_3D, dom, val, NULL, NULL, &errNum);
  }
  if(errNum != WLZ_ERR_NONE)
  {
    (void )WlzCMeshFree3D(mesh);
  }
  if(dstErr)
  {
    *dstErr = errNum;
  }
  return(obj);
}
Example #22
0
/*! 
* \ingroup      WlzBinaryOps
* \brief        Segment a domain into connected parts. Connectivity
 is defined by the connect parameter and can be 4- or 8-connected for
 2D objects and 6-, 18- or 26-connected for 3D objects. Note this
 version requires that there is sufficient space in the objects array
 defined by maxNumObjs and this is not extended. This should be changed
 in future so that the array is extended as required.
*
* \return       Error number.
* \param    obj	input object to be segmented
* \param    mm	number of objects return
* \param    dstArrayObjs	object array return, allocated in the
 procedure.
* \param    maxNumObjs	maximum number of object to return (determines
 the size of the array)
* \param    ignlns	ignore objects with num lines <= ignlns
* \param    connect	connectivity to determine connected regions
* \par      Source:
*                WlzLabel.c
*/
WlzErrorNum WlzLabel(
  WlzObject	*obj,
  int		*mm,
  WlzObject	***dstArrayObjs,
  int		maxNumObjs,
  int		ignlns,
  WlzConnectType connect)
{ 
  WlzIntervalDomain 	*jdp;
  WlzRagRValues 	*jvp;
  WlzIntervalWSpace 	iwsp;
  WlzInterval 		*itvl;
  WlzInterval 		*jtvl;
  WlzLAllocBuf 		*crntal, *altemp;
  WlzLAllocBuf		*al, *crntst, *crlast;
  WlzLAllocBuf		*precal, *precst, *prlast;
  int			nints, mkl;
  int			maxinline,nob,line,ended,lend,chainlistsize;
  WlzLLink		*freechain, *alprec, *alloc, *link1, *link2;
  int			lftcrn, lftprc, rtcrn, rtprec;
  int			jrtcrn, mxkl, jl, jr;
  int			oll, ofl, jjj;
  WlzDomain		domain;
  WlzValues		values;
  int			jdqt;
  WlzErrorNum		errNum=WLZ_ERR_NONE;
  WlzObject		**objlist;

  /* see HISTORY for comments from the FORTRAN version */

  /* now we allocate space for the objects */
  if( (objlist = (WlzObject **)AlcMalloc(sizeof(WlzObject *) * maxNumObjs))
     == NULL ){
    errNum = WLZ_ERR_MEM_ALLOC;
  }
  else {
    *dstArrayObjs = objlist;
  }
  

  /* check object note *mm is always set to zero on error
     return because the "Too many objects" error can return
     nobj valid objects therefore if *mm != 0 there are valid objects
     in objlist which must be freed */
  if( obj == NULL ){
    *mm = 0;
    return WLZ_ERR_OBJECT_NULL;
  }

  /* check types */
  switch( obj->type ){

  case WLZ_2D_DOMAINOBJ:
    if( obj->domain.core == NULL ){
      *mm = 0;
      return WLZ_ERR_DOMAIN_NULL;
    }

    switch( obj->domain.core->type ){

    case WLZ_INTERVALDOMAIN_INTVL:
      break;

    case WLZ_INTERVALDOMAIN_RECT:
      if( (obj->domain.i->lastln - obj->domain.i->line1) < ignlns ){
	*mm = 0;
	return( WLZ_ERR_NONE );
      }

      if( maxNumObjs < 1 ){
	*mm = 0;
	return( WLZ_ERR_INT_DATA );
      }

      objlist[0] = WlzAssignObject(
	WlzMakeMain(obj->type, obj->domain,
		    obj->values, NULL, NULL, &errNum), NULL);
      *mm = 1;
      return WLZ_ERR_NONE;
      
    default:
      *mm = 0;
      return WLZ_ERR_DOMAIN_TYPE;

    }
    break;

  case WLZ_3D_DOMAINOBJ:
    if( obj->domain.core == NULL ){
      *mm = 0;
      return WLZ_ERR_DOMAIN_NULL;
    }

    return WlzLabel3d(obj, mm, objlist, maxNumObjs, ignlns, connect);

  case WLZ_EMPTY_OBJ:
    *mm = 0;
    return WLZ_ERR_NONE;

  case WLZ_TRANS_OBJ:
    /* should be able to do this quite easily */
  default:
    *mm = 0;
    return WLZ_ERR_OBJECT_TYPE;

  }

  /* check connectivity parameter */
  switch( connect ){

  default:
    return WLZ_ERR_INT_DATA;

  case WLZ_8_CONNECTED:
    jdqt = 0;
    break;

  case WLZ_4_CONNECTED:
    jdqt = 1;
    break;

  }
    
  /*
   * Allocate and initialise the working spaces.
   *
   * The chain store size is not easily predictable.
   * Here we use ((twice the number of lines) plus (one third the
   * number of intervals)), very much smaller than the
   * previous allocation, but apparently adequate to
   * segment both metaphase spreads and single connected objects.
   * In any case, this version of label can if necessary allocate
   * more space when the original chain store fills up.
   */
  chainlistsize = mintcount(obj->domain.i, &maxinline) / 3;
  chainlistsize += (1 + obj->domain.i->lastln - obj->domain.i->line1)*2;
  if( (freechain = chainalloc(0,chainlistsize)) == NULL ){
    *mm = 0;
    return WLZ_ERR_MEM_ALLOC;
  }
  buckle(freechain, freechain, chainlistsize);
  /*
   * The allocation list size is determined as twice
   * (1 + maximum number of intervals in a line of input object).
   */
  if( (al = (WlzLAllocBuf *)
       AlcCalloc(2 * (maxinline+1), sizeof(WlzLAllocBuf))) == NULL ){
    chainFree();
    *mm = 0;
    return WLZ_ERR_MEM_ALLOC;
  }
  jvp = obj->values.v;

  /* initialise interval scanning */
  WlzInitRasterScan (obj, &iwsp, WLZ_RASTERDIR_ILIC);
  line = iwsp.linpos;
  ended = 0 ;
  lend = 0 ;
  WlzNextInterval(&iwsp);
  crntst = al + 1 + maxinline;
  nob = 0 ;
  prlast = al ;
  precst = al + 1 ;

  /* commence new line */
  while (!ended) {
    crntal = crntst-1 ;

    line++;
    if (lend) { 
      ended = 1 ;
      lend = 0 ;
    }
    else {
      /* read the intervals into the allocation buffer */
      while (iwsp.linpos <= line) {
	crntal++;
	crntal->a_int.ileft = iwsp.lftpos;
	crntal->a_int.iright = iwsp.rgtpos;
	if (WlzNextInterval(&iwsp) != 0) {
	  lend = 1 ;
	  break ;
	}
      }
    }
    crlast = crntal ;
    crntal = crntst ;
    precal = precst ;
    alloc = NULL ;

    /* test whether last interval in current line dealt with */
    while (crntal <= crlast) {
      lftcrn = crntal->a_int.ileft ;
      jrtcrn = crntal->a_int.iright ;
      rtcrn = jrtcrn+2 ;
      alprec = precal->a_link;
      lftprc = precal->a_int.ileft ;
      rtprec = precal->a_int.iright +2 ;

      /* test whether last interval in preceeding line dealt with */
      if (precal > prlast || rtcrn <= lftprc + jdqt) { 
	/* is interval in current line already allocated */
	if (!alloc) { 
	  /* start a new object and allocate this interval to it */
	  /* interval list */
	  link1 = newchain2(freechain,lftcrn,jrtcrn);
	  /* line-of-intervals list */
	  link2 = newchain1(freechain, (unsigned long) link1);
	  /* "object" -- first line, last line, line-of-intervals pointer */
	  crntal->a_link  = newchain1(freechain,line) ;
	  crntal->a_link = addlink1 (freechain, crntal->a_link, (unsigned long)line);
	  crntal->a_link = addlink1 (freechain, crntal->a_link, (unsigned long) link2);
	}
	/* move on to next interval in current line */
	crntal++ ;
	alloc = NULL;
      }
      else {
	if (rtprec > lftcrn+ (int )jdqt) { 
	  /* case of overlapping intervals: */
	  /* is intvl in current line already allocated ? */
	  if (!alloc) { 
	    /* allocate this interval and add to object list */
	    alloc = alprec ;
	    link1 = alloc->l_link ;
	    crntal->a_link = alloc ;
	    /* test whether this line has already been started for this object */
	    if (link1->l_u.line != line) {
	      /* update last line */
	      link1->l_u.line = line;
	      /* add a link to the line list for this line */
	      link1 = newchain2(freechain,lftcrn,jrtcrn);
	      alloc->l_u.u_link = addlink1 (freechain, alloc->l_u.u_link, (unsigned long) link1);
	    }
	    else {
	      /* add interval to interval list for last line */
	      link1 = alloc->l_u.u_link;
	      link1->l_u.u_link = addlink2 (freechain, link1->l_u.u_link, lftcrn, jrtcrn);
	    }
	  }
	  else {
	    /* merge lists and reallocate intervals */
	    /* test whether both already allocated to same object */
	    if (alprec != alloc) { 
	      merge (&alprec, &alloc, freechain);
	      /* reallocate intervals in preceding line */
	      for (altemp = precst; altemp <= prlast; altemp++)	{
		if (altemp->a_link == alloc) { 
		  altemp->a_link = alprec ;	
		}	
	      }
	      /* reallocate intervals in current line */
	      for (altemp = crntst; altemp <= crntal; altemp++)	{
		if (altemp->a_link == alloc) { 
		  altemp->a_link = alprec ;	
		}	
	      }
	      alloc = alprec ;
	    }
	  }
	  if (rtcrn < rtprec) { 
	    /* move to next interval in this line */
	    crntal++;
	    alloc = NULL ;
	    continue;	/* the outer while loop */
	  }
	}
	/* move on to next interval in preceding line */
	precal++ ;
      }
    }

    /* all intervals in current line dealt with: */
    /* find and construct any finished objects */
    if (precst <= prlast) { 
      for (precal = precst; precal <= prlast; precal++) {
	alprec = precal->a_link ;
	/* has the object to which this interval was allocated been dealt with */
	if (alprec) { 
	  /* remove any later intervals allocated to the same object */
	  for (altemp = precal; altemp <= prlast; altemp++) {
	    if (altemp->a_link == alprec) { 
	      altemp->a_link  = NULL ;	
	    }	
	  }
	  /* test if this object has intervals in the current line */
	  /* and if so skip to end of outer loop */
	  if (crntst <= crlast) { 
	    for (altemp = crntst; altemp <= crlast; altemp++)	{
	      if (altemp->a_link == alprec)
		goto loopend;
	    }
	  }
	  /* construct object - first find line and column bounds */
	  link1 = alprec->l_link;
	  oll = (int) link1->l_u.line;
	  link1 = link1->l_link;
	  ofl = (int) link1->l_u.line;
	  link1 = alprec->l_u.u_link;
	  mkl = 0; /* Just to keep lint happy. */
	  mxkl = 0; /* Just to keep lint happy. */
	  nints = 0;
	  for (jjj=ofl; jjj<=oll; jjj++) {
	    link1 = link1->l_link;
	    link2 = link1->l_u.u_link;
	    do {
	      link2 = link2->l_link;
	      jl = link2->l_u.intv.ileft;
	      jr = link2->l_u.intv.iright;
	      if (nints == 0 || jl < mkl)
		mkl = jl ;	
	      if (nints == 0 || jr > mxkl)
		mxkl = jr ;	
	      nints++;
	      /* test for end of line */
	    } 
	    while (link2 != link1->l_u.u_link);
	  }
	  /* test whether object large enough, if not ignore it */
	  /* test for height or width less than threshold */
	  if (oll-ofl < ignlns || mxkl-mkl < ignlns) {
	    for (jjj = ofl; jjj <= oll; jjj++)	{
	      link1 = link1->l_link;
	      link2 = link1->l_u.u_link;
	      /* recover chain space */
	      join (freechain, link2) ;
	    }
	  }
	  else {

	    /* test for object array overflow */
	    if (nob >= maxNumObjs) {
	      AlcFree((void *) al);
	      chainFree();
	      *mm = nob;
	      return(WLZ_ERR_INT_DATA);
	    }
	    link1 = alprec->l_u.u_link;
	    /* set up domain and object, and update counts
	       need to test successful space allocation here */
	    jdp = WlzMakeIntervalDomain(WLZ_INTERVALDOMAIN_INTVL,
					ofl,oll,mkl,mxkl, &errNum);
	    domain.i = jdp;
	    values.v = jvp;
	    *objlist = WlzAssignObject(
	      WlzMakeMain(WLZ_2D_DOMAINOBJ,
			  domain,values,NULL,obj,&errNum), NULL);
	    objlist++;
	    nob++;
	    /* get the size correct here !!! */
	    itvl = (WlzInterval *) AlcMalloc (nints * sizeof(WlzInterval));
	    jdp->freeptr = AlcFreeStackPush(jdp->freeptr, (void *)itvl, NULL);
	    /* write intervals and interval pointers lists */
	    for (jjj=ofl; jjj<=oll; jjj++) {
	      jtvl = itvl;
	      nints = 0;
	      link1 = link1->l_link;
	      link2 = link1->l_u.u_link;
	      do {
		/*
		 * the following increment since the interval
		 * list is circular, monotone increasing,
		 * but link2 originally points at the
		 * rightmost interval (see comment at top).
		 */
		link2 = link2->l_link;
		itvl->ileft = link2->l_u.intv.ileft - mkl;
		itvl->iright = link2->l_u.intv.iright - mkl;
		itvl++;
		nints++;
		/* test for end of line */
	      } 
	      while (link2 != link1->l_u.u_link);
	      WlzMakeInterval(jjj,jdp,nints,jtvl);
	      join (freechain, link2) ;
	    }
	  }
	  /* return line list etc to free-list store */
	  join (freechain, alprec->l_u.u_link);
	  join (freechain, alprec) ;
	}
      loopend:			 
	;
      }
    }

    /* update pointers - swap the two halves of the allocation list */
    /* before getting the intervals in the next line */
    altemp = crntst ;
    crntst = precst ;
    precst = altemp ;
    prlast = crlast ;
  }

  *mm = nob ;
  AlcFree((void *) al);
  chainFree();

  return WLZ_ERR_NONE;
} 
Example #23
0
/*!
* \return	Woolz compound array object.
* \ingroup	WlzExtFF
* \brief	Given an object in which distinct voxel values represent
*		different domains and each of these has a corresponding
*		material, this function creates a new compound array
*		object. Each of the materials has it's own domain and
*		the material properties are encoded in a simple ascii
*		property list of the domain.
*		The materials are known to have indices which increase
*		from 0.
* \param	gObj			Given index object.
* \param	head			Amira header data structure with the
*					list of materials.
* \param	dstErr			Destination pointer for error number,
*					may be NULL.
*/
static WlzCompoundArray *WlzEffAmSplitLabelObj(WlzObject *gObj,
					WlzEffAmHead *head,
					WlzErrorNum *dstErr)
{
  int		idx,
  		empty = 0;
  WlzPixelV	thrV;
  WlzObject	*tObj0 = NULL,
  		*tObj1 = NULL,
		*tObj2,
		*tObj3;
  WlzEffAmMaterial *mat;
  WlzPropertyList *pList = NULL;
  WlzCompoundArray *aObj = NULL;
  WlzDomain	nullDom;
  WlzValues	dValues,
  		nullVal;
  WlzErrorNum errNum = WLZ_ERR_NONE;
  const int	allEmptyAfterFirst = 0;

  idx = 0;
  nullDom.core = NULL;
  nullVal.core = NULL;
  dValues.core = NULL;
  mat = head->materials;
  thrV.type = WLZ_GREY_INT;
  /* Create compound array object. */
  aObj = WlzMakeCompoundArray(WLZ_COMPOUND_ARR_1, 1, head->matCount, NULL,
  			      WLZ_3D_DOMAINOBJ, &errNum);
  /* For each material create a new domain corresponding to the index. */
  while((errNum == WLZ_ERR_NONE) && (idx < head->matCount))
  {
    thrV.v.inv = mat->id + 1;
    pList = WlzEffAmMakeMaterialPropList(mat, &errNum);
    if(empty && allEmptyAfterFirst)
    {
      tObj3 = WlzMakeMain(WLZ_EMPTY_OBJ, nullDom, nullVal, pList,
      			  NULL, &errNum);
      
    }
    else
    {
      if(errNum == WLZ_ERR_NONE)
      {
	if(idx == 0)
	{
	  tObj1 = WlzAssignObject(
		  WlzThreshold(gObj, thrV, WLZ_THRESH_HIGH, &errNum), NULL);
	  if(errNum == WLZ_ERR_NONE)
	  {
	    tObj2 = WlzDiffDomain(gObj, tObj1, &errNum);
	  }
	}
	else
	{
	  tObj1 = WlzAssignObject(
		  WlzThreshold(tObj0, thrV, WLZ_THRESH_HIGH, &errNum), NULL);
	  if(errNum == WLZ_ERR_NONE)
	  {
	    tObj2 = WlzDiffDomain(tObj0, tObj1, &errNum);
	  }
	}
      }
      if(errNum == WLZ_ERR_NONE)
      {
        if(WlzIsEmpty(tObj1, &errNum) || WlzIsEmpty(tObj2, &errNum))
	{
	  empty = 1;
	  tObj3 = WlzMakeMain(WLZ_EMPTY_OBJ, nullDom, nullVal, pList,
	                      NULL, &errNum);
	}
	else
	{
	  tObj3 = WlzMakeMain(WLZ_3D_DOMAINOBJ, tObj2->domain,
			      dValues, pList, NULL, &errNum);
	}
      }
      (void )WlzFreeObj(tObj2); tObj2 = NULL;
      (void )WlzFreeObj(tObj0);
      tObj0 = tObj1;
      tObj1 = NULL;
    }
    if(errNum == WLZ_ERR_NONE)
    {
      aObj->o[idx] = WlzAssignObject(tObj3, NULL);
    }
    ++idx;
    mat = mat->next;
  }
  (void )WlzFreeObj(tObj0);
  if(dstErr)
  {
    *dstErr = errNum;
  }
  return(aObj);
}
Example #24
0
int             main(int argc, char **argv)
{
  int		option,
		ok = 1,
		usage = 0;
  WlzObject	*inObj = NULL,
  		*outObj = NULL,
		*grdObj = NULL,
		*edgObj = NULL;
  double	alpha = 1.0,
  		mult = 1.0;
  WlzPixelV	pThrV,
  		sThrV;
  WlzCannyDericheFilterAction action = WLZ_CANNYDERICHE_FLTACT_EDG;
  WlzErrorNum	errNum = WLZ_ERR_NONE;
  FILE		*fP = NULL;
  char 		*outFileStr,
  		*inObjFileStr;
  static char	optList[] = "ho:a:m:l:u:deg",
		outFileStrDef[] = "-",
  		inObjFileStrDef[] = "-";

  opterr = 0;
  outFileStr = outFileStrDef;
  inObjFileStr = inObjFileStrDef;
  pThrV.type = sThrV.type = WLZ_GREY_INT;
  pThrV.v.inv = sThrV.v.inv = 1.0;
  while(ok && ((option = getopt(argc, argv, optList)) != -1))
  {
    switch(option)
    {
      case 'o':
        outFileStr = optarg;
	break;
      case 'h':
        usage = 1;
	ok = 0;
	break;
      case 'a':
	if((optarg == NULL) || (sscanf(optarg, "%lg", &alpha) != 1))
	{
	  usage = 1;
	  ok = 0;
	}
        break;
      case 'd':
        action = WLZ_CANNYDERICHE_FLTACT_DIR;
	break;
      case 'e':
        action = WLZ_CANNYDERICHE_FLTACT_EDG;
	break;
      case 'g':
        action = WLZ_CANNYDERICHE_FLTACT_GRD;
        break;
      case 'm':
        if((optarg == NULL) || (sscanf(optarg, "%lg", &mult) != 1))
	{
	  usage = 1;
	  ok = 0;
	}
      case 'l':
        if((optarg == NULL) || (sscanf(optarg, "%d", &(sThrV.v.inv)) != 1))
	{
	  usage = 1;
	  ok = 0;
	}
	break;
      case 'u':
        if((optarg == NULL) || (sscanf(optarg, "%d", &(pThrV.v.inv)) != 1))
	{
	  usage = 1;
	  ok = 0;
	}
	break;
      default:
        usage = 1;
	ok = 0;
	break;
    }
  }
  if(ok)
  {
    if((inObjFileStr == NULL) || (*inObjFileStr == '\0') ||
       (outFileStr == NULL) || (*outFileStr == '\0'))
    {
      ok = 0;
      usage = 1;
    }
  }
  if(ok && (optind < argc))
  {
    if((optind + 1) != argc)
    {
      usage = 1;
      ok = 0;
    }
    else
    {
      inObjFileStr = *(argv + optind);
    }
  }
  if(ok)
  {
    if((inObjFileStr == NULL) ||
       (*inObjFileStr == '\0') ||
       ((fP = (strcmp(inObjFileStr, "-")?
	      fopen(inObjFileStr, "r"): stdin)) == NULL) ||
       ((inObj= WlzAssignObject(WlzReadObj(fP, &errNum), NULL)) == NULL) ||
       (errNum != WLZ_ERR_NONE))
    {
      ok = 0;
      (void )fprintf(stderr,
		     "%s: failed to read object from file %s\n",
		     *argv, inObjFileStr);
    }
    if(fP && strcmp(inObjFileStr, "-"))
    {
      fclose(fP);
    }
  }
  if(ok)
  {
    switch(action)
    {
      case WLZ_CANNYDERICHE_FLTACT_DIR:
	outObj = WlzCannyDeriche(NULL, inObj, alpha, mult,
				 pThrV, sThrV, &errNum);
        break;
      case WLZ_CANNYDERICHE_FLTACT_EDG:
	edgObj = WlzCannyDeriche(&grdObj, inObj, alpha, mult,
				 pThrV, sThrV, &errNum);
	if(errNum == WLZ_ERR_NONE)
	{
	  outObj = WlzMakeMain(edgObj->type, edgObj->domain, grdObj->values,
			       NULL, NULL, &errNum);
	}
	WlzFreeObj(edgObj);
	WlzFreeObj(grdObj);
        break;
      case WLZ_CANNYDERICHE_FLTACT_GRD:
	edgObj = WlzCannyDeriche(&outObj, inObj, alpha, mult,
				 pThrV, sThrV, &errNum);
	WlzFreeObj(edgObj);
        break;
    }
    if(errNum != WLZ_ERR_NONE)
    {
      ok = 0;
       (void )fprintf(stderr, "%s Failed to filter object (%s)\n",
       	              *argv, WlzStringFromErrorNum(errNum, NULL));
    }
  }
  if(ok)
  {
    if(((fP = (strcmp(outFileStr, "-")?
	      fopen(outFileStr, "w"):
	      stdout)) == NULL) ||
       (WlzWriteObj(fP, outObj) != WLZ_ERR_NONE))
    {
      ok = 0;
      (void )fprintf(stderr,
		     "%s: failed to write output object\n",
		     *argv);
    }
    if(fP && strcmp(outFileStr, "-"))
    {
      fclose(fP);
    }
  }
  if(inObj)
  {
    WlzFreeObj(inObj);
  }
  if(outObj)
  {
    WlzFreeObj(outObj);
  }
  if(usage)
  {
    (void )fprintf(stderr,
    "Usage: %s%s%s%sExample: %s%s",
    *argv,
    " [-o<output object>] [-h] [-o] [-a#] [-d] [-e] [-g]\n"
    "        [-m#] [-l#] [-u#] [<input object>]\n"
    "Version: ",
    WlzVersion(),
    "\n"
    "Options:\n"
    "  -h  Prints this usage information\n"
    "  -o  Output object file name.\n"
    "  -a  Deriche's alpha parameter.\n"
    "  -d  Output object with edge direction encoding.\n"
    "  -e  Output object with edge gradients.\n"
    "  -g  Output object with all gradients.\n"
    "  -m  Filter multiplier parameter.\n"
    "  -l  Lower hysteresis threshold value.\n"
    "  -u  Upper hysteresis threshold value.\n"
    "Applies a Canny/Deriche edge detection filter to a Woolz domain object\n"
    "with grey values.\n"
    "The input object is read from stdin and the filtered object is\n"
    "written to stdout unless the filenames are given.\n",
    *argv,
    " -e -a 1.0 -l 15 -u 40 -m 10 -o edges.wlz in.wlz\n"
    "The input Woolz object is read from in.wlz, and filtered using a\n"
    "Deriche edge operator with alpha=1.0, gradients are multiplied by\n"
    "10.0 before non-maximal suppression or hysteresis thresholding. The\n"
    "hysteresis threshold values of 15 and 40 are used to threshold the\n"
    "edge image which is written to edge.wlz.\n");
  }
  return(!ok);
}
Example #25
0
/*! 
* \ingroup      WlzDomainOps
* \brief        Calculate the volume of the input 3D domain object.
*
* \return       Volume of input 3D object, -1 on error.
* \param    obj	Input object pointer.
* \param    wlzErr	Error return.
* \par      Source:
*                WlzVolume.c
*/
WlzLong WlzVolume(
  WlzObject 	*obj,
  WlzErrorNum 	*wlzErr)
{
  WlzObject		*tmpobj;
  WlzPlaneDomain	*pldom;
  WlzDomain		domain;
  WlzValues		values;
  WlzLong		vol = -1,
  			p;
  WlzErrorNum		errNum = WLZ_ERR_NONE; 

  /* check the object */
  if( obj == NULL )
  {
    if(*wlzErr)
    {
      *wlzErr = WLZ_ERR_OBJECT_NULL;
    }
    return( -1 );
  }

  switch( obj->type ){

  case WLZ_2D_DOMAINOBJ:
    return(WlzArea(obj, wlzErr));

  case WLZ_3D_DOMAINOBJ:
    if( obj->domain.core == NULL ){
      if(*wlzErr)
      {
        *wlzErr = WLZ_ERR_DOMAIN_NULL;
      }
      return -1;
    }

    if( obj->domain.core->type != WLZ_PLANEDOMAIN_DOMAIN )
    {
      if(*wlzErr)
      {
        *wlzErr = WLZ_ERR_DOMAIN_TYPE;
      }
      return -1;
    }
    break;

  case WLZ_EMPTY_OBJ:
    if(*wlzErr)
    {
      *wlzErr = WLZ_ERR_NONE;
    }
    return 0;

  default:
    if(wlzErr)
    {
      *wlzErr = WLZ_ERR_OBJECT_TYPE;
    }
    return( -1 );

  }

  /* scan through planes calculating the area */
  vol = 0;
  values.core = NULL;
  pldom = obj->domain.p;
  for(p=0; (p <= (pldom->lastpl - pldom->plane1)) && (errNum == WLZ_ERR_NONE);
      p++){
    domain = pldom->domains[p];
    if( domain.core ){
      tmpobj = WlzMakeMain(WLZ_2D_DOMAINOBJ, domain, values, NULL, NULL,
      			   &errNum);
      if(tmpobj) {
	vol += WlzArea(tmpobj , &errNum);
	WlzFreeObj( tmpobj );
      }
    }
  }
  if(errNum != WLZ_ERR_NONE)
  {
    vol = -1;
  }
  if(wlzErr)
  {
    *wlzErr = errNum;
  }

  return( vol );
}
Example #26
0
int		main(int argc, char *argv[])
{
  int		idE,
  		nElm = 0,
  		ok = 1,
  		option,
  		usage = 0,
		conform = 1,
		copyMesh = 0,
		features = 0,
		laplacianItr = 0,
		lowPassItr = 0,
		smoothBnd = 0,
		verify = 0;
  char		outFmt = 'v';
  double	laplacianAlpha = 0.1,
		lowPassLambda = 0.33,
		lowPassMu = -0.34,
  		minElmSz = 25.0,
  		maxElmSz = 100.0;
  int		*idx = NULL;
  double	*vol = NULL,
  		*minLen = NULL,
		*maxLen = NULL;
  FILE		*fP = NULL;
  char		*inObjFileStr,
  		*outFileStr;
  const char	*errMsgStr;
  WlzErrorNum	errNum = WLZ_ERR_NONE;
  WlzDomain	dom;
  WlzValues	val;
  WlzObject	*obj = NULL,
  		*outObj = NULL;
  WlzCMeshP 	mesh,
  		meshCopy;
  WlzObjectType	cMType;
  static char   optList[] = "a:BCFhl:L:m:M:o:u:vVwW:y";
  const char    inObjFileStrDef[] = "-",
  	        outFileStrDef[] = "-";

  val.core = NULL;
  mesh.v = NULL;
  opterr = 0;
  inObjFileStr = (char *)inObjFileStrDef;
  outFileStr = (char *)outFileStrDef;
  while((usage == 0) && ((option = getopt(argc, argv, optList)) != EOF))
  {
    switch(option)
    {
      case 'a':
	if(sscanf(optarg, "%lg", &laplacianAlpha) != 1)
	{
	  usage = 1;
	}
        break;
      case 'B':
        smoothBnd = 1;
	break;
      case 'C':
        conform = 0;
	break;
      case 'F':
        features = 1;
	break;
      case 'l':
	if(sscanf(optarg, "%lg", &lowPassLambda) != 1)
	{
	  usage = 1;
	}
        break;
      case 'L':
	if(sscanf(optarg, "%d", &laplacianItr) != 1)
	{
	  usage = 1;
	}
        break;
      case 'm':
        if(sscanf(optarg, "%lg", &minElmSz) != 1)
	{
	  usage = 1;
	}
	break;
      case 'M':
        if(sscanf(optarg, "%lg", &maxElmSz) != 1)
	{
	  usage = 1;
	}
        break;
      case 'o':
        outFileStr = optarg;
	break;
      case 'u':
	if(sscanf(optarg, "%lg", &lowPassMu) != 1)
	{
	  usage = 1;
	}
        break;
      case 'W':
	if(sscanf(optarg, "%d", &lowPassItr) != 1)
	{
	  usage = 1;
	}
        break;
      case 'v':
        outFmt = 'v';
	break;
      case 'V':
        verify = 1;
	break;
      case 'w':
        outFmt = 'w';
	break;
      case 'y':
        copyMesh = 1;
	break;
      case 'h':
      default:
	usage = 1;
	break;
    }
  }
  ok = usage == 0;
  if(ok)
  {
    if((inObjFileStr == NULL) || (*inObjFileStr == '\0') ||
       (outFileStr == NULL) || (*outFileStr == '\0'))
    {
      ok = 0;
      usage = 1;
    }
    if(ok && (optind < argc))
    {
      if((optind + 1) != argc)
      {
        usage = 1;
        ok = 0;
      }
      else
      {
        inObjFileStr = *(argv + optind);
      }
    }
  }
  if(ok)
  {
    if((inObjFileStr == NULL) ||
       (*inObjFileStr == '\0') ||
       ((fP = (strcmp(inObjFileStr, "-")?
              fopen(inObjFileStr, "r"): stdin)) == NULL) ||
       ((obj = WlzAssignObject(WlzReadObj(fP, &errNum), NULL)) == NULL) ||
       (errNum != WLZ_ERR_NONE))
    {
      ok = 0;
      (void )fprintf(stderr,
                     "%s: failed to read object from file %s\n",
                     *argv, inObjFileStr);
    }
    if(fP && strcmp(inObjFileStr, "-"))
    {
      (void )fclose(fP); fP = NULL;
    }
  }
  if(ok)
  {
    (void )WlzAssignObject(obj, NULL);
    mesh = WlzCMeshFromObj(obj, minElmSz, maxElmSz, NULL, conform, &errNum);
    if(errNum != WLZ_ERR_NONE)
    {
      ok = 0;
      (void )WlzStringFromErrorNum(errNum, &errMsgStr);
      (void )fprintf(stderr,
      		     "%s Failed to create conforming mesh, %s.\n",
      		     argv[0],
		     errMsgStr);
    }
  }
  if(ok)
  {
    WlzCMeshSetBoundNodFlags(mesh);
    if(verify)
    {
      errNum = WlzCMeshVerify(mesh, NULL, 1, stderr);
      if(errNum != WLZ_ERR_NONE)
      {
	ok = 0;
	(void )WlzStringFromErrorNum(errNum, &errMsgStr);
	(void )fprintf(stderr,
		       "%s Failed to verify mesh, %s.\n",
		       argv[0],
		       errMsgStr);
      }
    }
  }
  if(ok && (laplacianItr > 0))
  {
    errNum = WlzCMeshLaplacianSmooth(mesh, laplacianItr, laplacianAlpha,
    				     smoothBnd, 1);
    if((errNum == WLZ_ERR_NONE) && verify)
    {
      errNum = WlzCMeshVerify(mesh, NULL, 1, stderr);
    }
    if(errNum != WLZ_ERR_NONE)
    {
      ok = 0;
      (void )WlzStringFromErrorNum(errNum, &errMsgStr);
      (void )fprintf(stderr,
                     "%s Failed to Laplacian smooth mesh, %s.\n",
		     argv[0],
		     errMsgStr);
    }
  }
  if(ok && (lowPassItr > 0))
  {
    errNum = WlzCMeshLPFilterLM(mesh, lowPassLambda, lowPassMu,
    				lowPassItr, smoothBnd, 1);
    if((errNum == WLZ_ERR_NONE) && verify)
    {
      errNum = WlzCMeshVerify(mesh, NULL, 1, stderr);
    }
    if(errNum != WLZ_ERR_NONE)
    {
      ok = 0;
      (void )WlzStringFromErrorNum(errNum, &errMsgStr);
      (void )fprintf(stderr,
                     "%s Failed to low pass filter mesh, %s.\n",
		     argv[0],
		     errMsgStr);
    }
  }
  if(ok && (copyMesh != 0))
  {
    meshCopy = WlzCMeshCopy(mesh, 1, 0, NULL, NULL, &errNum);
    if(errNum != WLZ_ERR_NONE)
    {
      ok = 0;
      (void )WlzStringFromErrorNum(errNum, &errMsgStr);
      (void )fprintf(stderr,
                     "%s Failed to copy mesh, %s.\n",
		     argv[0],
		     errMsgStr);
    }
    else
    {
      (void )WlzCMeshFree(mesh);
      mesh = meshCopy;
      meshCopy.v = NULL;
    }
  }
  if(ok)
  {
    if((fP = (strcmp(outFileStr, "-")?
	     fopen(outFileStr, "w"): stdout)) == NULL)
    {
      ok = 0;
      (void )fprintf(stderr,
		     "%s: Failed to open output file %s.\n",
		     argv[0], outFileStr);
    }
  }
  if(ok && features)
  {
    errNum = WlzCMeshCmpElmFeat(mesh, &nElm, &idx, &vol, &minLen, &maxLen);
    if(errNum == WLZ_ERR_NONE)
    {
      for(idE = 0; idE < nElm; ++idE)
      {
        (void )printf("%d %lg %lg %lg\n",
	              *(idx + idE), *(vol + idE),
	              *(minLen + idE), *(maxLen + idE));
      }
    }
    else
    {
      ok = 0;
      (void )WlzStringFromErrorNum(errNum, &errMsgStr);
      (void )fprintf(stderr,
                     "%s Failed to compute mesh features, %s.\n",
		     argv[0],
		     errMsgStr);
    }
    AlcFree(idx);
    AlcFree(vol);
    AlcFree(minLen);
    AlcFree(maxLen);
  }
  if(ok)
  {
    switch(outFmt)
    {
      case 'v':
        WlzCMeshDbgOutVTK(fP, mesh);
	break;
      case 'w':
	switch(mesh.m2->type)
	{
	  case WLZ_CMESH_2D:
	    cMType = WLZ_CMESH_2D;
	    dom.cm2 = mesh.m2;
	    break;
	  case WLZ_CMESH_3D:
	    cMType = WLZ_CMESH_3D;
	    dom.cm3 = mesh.m3;
	    break;
	  default:
	    errNum = WLZ_ERR_DOMAIN_TYPE;
	    break;
	}
	if(errNum == WLZ_ERR_NONE)
	{
	  outObj = WlzMakeMain(cMType, dom, val, NULL, NULL, &errNum);
	}
	if(errNum == WLZ_ERR_NONE)
	{
	  errNum = WlzWriteObj(fP, outObj);
	}
	(void )WlzFreeObj(outObj);
	break;
    }
  }
  if(fP && strcmp(outFileStr, "-"))
  {
    (void )fclose(fP); fP = NULL;
  }
  (void )WlzFreeObj(obj);
  if(usage)
  {
    fprintf(stderr,
            "Usage: %s [-h] [-o<output file>]\n"
	    "       [-L#] [-a#] [-W#] [-l#] [-u#] [-B] [-C]\n"
	    "       [-m#] [-M#] [-F] [-V] [-y] [<input object>]\n"
    	    "Computes a conforming mesh for the given input object.\n"
	    "Options are:\n"
	    "  -h  Help, prints this usage message.\n"
	    "  -o  Output file.\n"
	    "  -a  Laplacian alpha parameter.\n"
	    "  -W  Number of low pass filter smoothing iterations.\n"
	    "  -l  Low pass filter lambda value.\n"
	    "  -u  Low pass filter mu value.\n"
	    "  -B  Smooth boundary (requires a smoothing method to be\n"
	    "      selected).\n"
	    "  -C  Don't make the mesh conform to the object's domain.\n"
	    "  -m  Minimum mesh element size.\n"
	    "  -L  Number of Laplacian smoothing iterations.\n"
	    "  -M  Maximum mesh element size.\n"
	    "  -F  Prints features of the mesh elements to the standard\n"
	    "      output.\n"
	    "  -V  Verify mesh. This may take a long time and may give\n"
	    "      segmentation faults for buggy meshes.\n"
	    "  -v  VTK file format for output.\n"
	    "  -w  Woolz file format for output.\n"
	    "  -y  Copy mesh to squeeze out all deleted entities.\n",
	    argv[0]);

  }
  return(!ok);
}
Example #27
0
int             main(int argc, char **argv)
{
  int		tI,
		idN,
  		option,
		con = WLZ_0_CONNECTED,
		nLo = 0,
		nHi = 0,
		maxSep = 1024,
		nObj = 0,
  		ok = 1,
		usage = 0;
  char		tC;
  double  	tD,
		mrkMass = 1.0,
  		rad = 0.0;
  int		tR[4];
  WlzPixelV	gV,
  		bV;
  WlzBlobMark	mrk = WLZ_BLOBMARK_CIRCLE;
  WlzObject     *inObj = NULL,
  		*outObj = NULL,
		*mrkObj = NULL;
  WlzObject	**lObj = NULL;
  FILE		*fP = NULL;
  char 		*inObjFileStr,
  		*outObjFileStr;
  WlzErrorNum	errNum = WLZ_ERR_NONE;
  const char	*errMsg;
  static char	optList[] = "c:g:G:hm:n:N:o:r:x:",
  		fileStrDef[] = "-";

  opterr = 0;
  memset(&gV, 0, sizeof(WlzPixelV));
  bV.type = WLZ_GREY_UBYTE;
  bV.v.ubv = 0;
  gV.type = WLZ_GREY_ERROR;
  inObjFileStr = fileStrDef;
  outObjFileStr = fileStrDef;
  while((usage == 0) && ((option = getopt(argc, argv, optList)) != -1))
  {
    switch(option)
    {
      case 'c':
        if(sscanf(optarg, "%d", &tI) != 1)
	{
	  usage = 1;
	}
	else
	{
	  switch(tI)
	  {
	    case  4:
	      con = WLZ_4_CONNECTED;
	      break;
	    case  6:
	      con = WLZ_6_CONNECTED;
	      break;
	    case  8:
	      con = WLZ_8_CONNECTED;
	      break;
	    case 18:
	      con = WLZ_18_CONNECTED;
	      break;
	    case 26:
	      con = WLZ_26_CONNECTED;
	      break;
	    default:
	      usage = 1;
	      break;
	  }
	}
	break;
      case 'g':
        switch(gV.type)
	{
	  case WLZ_GREY_UBYTE:
	    if((sscanf(optarg, "%d", &tI) != 1) ||
	       (tI < 0) || (tI > 255))
	    {
	      usage = 1;
	    }
	    else
	    {
	      gV.v.ubv = tI;
	    }
	    break;
	  case WLZ_GREY_SHORT:
	    if((sscanf(optarg, "%d", &tI) != 1) ||
	       (tI < SHRT_MIN) || (tI > SHRT_MAX))
	    {
	      usage = 1;
	    }
	    else
	    {
	      gV.v.shv = tI;
	    }
	    break;
	  case WLZ_GREY_INT:
	    if(sscanf(optarg, "%d", &tI) != 1)
	    {
	      usage = 1;
	    }
	    else
	    {
	      gV.v.inv = tI;
	    }
	    break;
	  case WLZ_GREY_FLOAT:
	    if((sscanf(optarg, "%lg", &tD) != 1) ||
	       (tD < -(FLT_MAX)) || (tD > FLT_MAX))
	    {
	      usage = 1;
	    }
	    else
	    {
	      gV.v.flv = tD;
	    }
	    break;
	  case WLZ_GREY_DOUBLE:
	    if(sscanf(optarg, "%lg", &tD) != 1)
	    {
	      usage = 1;
	    }
	    else
	    {
	      gV.v.dbv = tD;
	    }
	    break;
	  case WLZ_GREY_RGBA:
	    tR[3] = 255;
	    tR[0] = tR[1] = tR[2] = 0;
	    if((sscanf(optarg, "%d,%d,%d,%d",
	               &(tR[0]), &(tR[1]), &(tR[2]), &(tR[3])) == 0) ||
	       (tR[0] < 0) || (tR[0] > 255) ||
	       (tR[1] < 0) || (tR[1] > 255) ||
	       (tR[2] < 0) || (tR[2] > 255) ||
	       (tR[3] < 0) || (tR[3] > 255))
	    {
	      usage = 1;
	    }
	    else
	    {
	      WLZ_RGBA_RGBA_SET(gV.v.rgbv, tR[0], tR[1], tR[2], tR[3]);
	    }
	    break;
	  default:
	    usage = 1;
	    break;
	}
	break;
      case 'G':
        if(sscanf(optarg, "%c", &tC) != 1)
	{
	  usage = 1;
	}
	switch(tC)
	{
	  case 'v':
	    gV.type = WLZ_GREY_ERROR;
	    break;
	  case 'u':
	    gV.type = WLZ_GREY_UBYTE;
	    break;
	  case 's':
	    gV.type = WLZ_GREY_SHORT;
	    break;
	  case 'i':
	    gV.type = WLZ_GREY_INT;
	    break;
	  case 'f':
	    gV.type = WLZ_GREY_FLOAT;
	    break;
	  case 'd':
	    gV.type = WLZ_GREY_DOUBLE;
	    break;
	  case 'r':
	    gV.type = WLZ_GREY_RGBA;
	    break;
	  default:
	    usage = 1;
	    break;
	}
	break;
      case 'm':
        if((sscanf(optarg, "%d", &tI) != 1) ||
	   ((tI != WLZ_BLOBMARK_CIRCLE) && (tI != WLZ_BLOBMARK_SQUARE)))
	{
	  usage = 1;
	}
	else
	{
	  mrk = (WlzBlobMark )tI;
	}
	break;
      case 'n':
        if((sscanf(optarg, "%d", &nLo) != 1) || (nLo < 0))
	{
	  usage = 1;
	}
	break;
      case 'N':
        if((sscanf(optarg, "%d", &nHi) != 1) || (nHi < 0))
	{
	  usage = 1;
	}
	break;
      case 'o':
        outObjFileStr = optarg;
	break;
      case 'r':
        if((sscanf(optarg, "%lg", &rad) != 1) || (rad < 0.0))
	{
	  usage = 1;
	}
	break;
      case 'x':
        if((sscanf(optarg, "%d", &maxSep) != 1) || (maxSep < 1))
	{
	  usage = 1;
	}
      case 'h': /* FALLTHROUGH */
      default:
        usage = 1;
	break;
    }
  }
  if((usage == 0) && (nLo > nHi) && (nHi != 0))
  {
    usage = 1;
  }
  if((usage == 0) && (optind < argc))
  {
    if((optind + 1) != argc)
    {
      usage = 1;
    }
    else
    {
      inObjFileStr = *(argv + optind);
    }
  }
  ok = (usage == 0);
  /* Read input domain object. */
  if(ok)
  {
    if((inObjFileStr == NULL) ||
	(*inObjFileStr == '\0') ||
	((fP = (strcmp(inObjFileStr, "-")?
	       fopen(inObjFileStr, "r"): stdin)) == NULL) ||
	((inObj = WlzAssignObject(WlzReadObj(fP, &errNum), NULL)) == NULL) ||
	(errNum != WLZ_ERR_NONE))
    {
      ok = 0;
    }
    if(fP)
    {
      if(strcmp(inObjFileStr, "-"))
      {
	(void )fclose(fP);
      }
      fP = NULL;
    }
  }
  /* Check object type and connectivity. */
  if(ok)
  {
    switch(inObj->type)
    {
      case WLZ_2D_DOMAINOBJ:
	switch(con)
	{
	  case WLZ_0_CONNECTED:
	    con = WLZ_8_CONNECTED;
	    break;
	  case WLZ_4_CONNECTED: /* FALLTHROUGH */
	  case WLZ_8_CONNECTED:
	    break;
	  default:
	    ok = 0;
	    errNum = WLZ_ERR_PARAM_DATA;
	    (void )WlzStringFromErrorNum(errNum, &errMsg);
	    (void )fprintf(stderr,
	           "%s: Connectivity for 2D must be 4 or 8 (%s).\n",
		   *argv, errMsg);
	    break;
	}
	break;
      case WLZ_3D_DOMAINOBJ:
	switch(con)
	{
	  case WLZ_0_CONNECTED:
	    con = WLZ_26_CONNECTED;
	    break;
	  case  WLZ_6_CONNECTED: /* FALLTHROUGH */
	  case WLZ_18_CONNECTED: /* FALLTHROUGH */
	  case WLZ_26_CONNECTED:
	    break;
	  default:
	    ok = 0;
	    errNum = WLZ_ERR_PARAM_DATA;
	    (void )WlzStringFromErrorNum(errNum, &errMsg);
	    (void )fprintf(stderr,
	           "%s: Connectivity for 3D must be 6, 18 or 26 (%s).\n",
		   *argv, errMsg);
	    break;
	}
	break;
      default:
	ok = 0;
	errNum = WLZ_ERR_OBJECT_TYPE;
	(void )WlzStringFromErrorNum(errNum, &errMsg);
	(void )fprintf(stderr,
	       "%s: Input object must either a 2 or 3D domain object (%s).\n",
	       *argv, errMsg);
	break;
    }
  }
  /* Make basic marker with centre at the origin. */
  if(ok)
  {
    double	mrkRad;

    if(rad > 0.5)
    {
      mrkRad = rad;
    }
    else
    {
      mrkRad = 127;
    }
    if(mrk == WLZ_BLOBMARK_SQUARE)
    {
      mrkObj = WlzMakeCuboidObject(inObj->type, mrkRad, mrkRad, mrkRad,
                                   0, 0, 0, &errNum);
    }
    else /* mrk = WLZ_BLOBMARK_CIRCLE */
    {
      mrkObj = WlzMakeSphereObject(inObj->type, mrkRad, 0, 0, 0, &errNum);
    }
    if(mrkObj == NULL)
    {
      ok = 0;
      (void )WlzStringFromErrorNum(errNum, &errMsg);
      (void )fprintf(stderr,
             "%s: Failed to create basic marker object (%s).\n",
	     *argv, errMsg);
    }
    else
    {
      mrkMass = WlzVolume(mrkObj, NULL);
    }
  }
  /* Label the given domain. */
  if(ok)
  {
    errNum = WlzLabel(inObj, &nObj, &lObj, maxSep, 1, con);
    if((errNum != WLZ_ERR_NONE) || (nObj == 0))
    {
      ok = 0;
      if(errNum == WLZ_ERR_NONE)
      {
        errNum = WLZ_ERR_DOMAIN_DATA;
      }
      (void )WlzStringFromErrorNum(errNum, &errMsg);
      (void )fprintf(stderr,
      "%s: Failed to split the given object into separate regions (%s)\n",
      *argv, errMsg);
    }
  }
  /* Work through the separate object list removing small/large objects
   * according to the low and high thresholds. */
  if(ok)
  {
    int		idM;

    for(idN = 0, idM = 0; idN < nObj; ++idN)
    {
      int	vol;

      vol = WlzVolume(lObj[idN], &errNum);
      if(errNum == WLZ_ERR_NONE)
      {
        if(((nLo > 0) && (vol < nLo)) || ((nHi > 0) && (vol > nHi)))
	{
	  (void )WlzFreeObj(lObj[idN]);
	}
	else
	{
	  lObj[idM] = lObj[idN];
	  ++idM;
	}
      }
    }
    nObj = idM;
    if(nObj == 0)
    {
      ok = 0;
      errNum = WLZ_ERR_DOMAIN_DATA;
      (void )WlzStringFromErrorNum(errNum, &errMsg);
      (void )fprintf(stderr,
                     "%s: Failed to find and separate regions (%s)\n",
		     *argv, errMsg);

    }
  }
  /* Build a marker object by adding a mark at the centre of mass of each
   * separate fragment. */
  if(ok)
  {
    WlzObject	*obj0 = NULL;

    idN = 0;
    obj0 = WlzMakeEmpty(&errNum);
    while((errNum == WLZ_ERR_NONE) && (idN < nObj))
    {
      double	  mass;
      WlzDVertex3 com;
      WlzObject	  *obj1 = NULL,
      		  *obj2 = NULL;
      WlzAffineTransform *tr = NULL;

      com = WlzCentreOfMass3D(lObj[idN], 1, &mass, &errNum);
      if(errNum == WLZ_ERR_NONE)
      {
        double	s;

	if(rad < 0.5)
	{
	  double t;

	  t = mass / mrkMass;
	  if(inObj->type == WLZ_2D_DOMAINOBJ)
	  {
	    s = sqrt(t);
	  }
	  else /* inObj->type == WLZ_3D_DOMAINOBJ */
	  {
	    s = cbrt(t);
	  }
	}
	else
	{
	  s = 1.0;
	}
        tr = (inObj->type == WLZ_2D_DOMAINOBJ)?
             WlzAffineTransformFromPrimVal(
	       WLZ_TRANSFORM_2D_AFFINE, com.vtX, com.vtY, 0.0,
	       s, 0.0, 0.0, 0.0, 0.0, 0.0, 0, &errNum):
             WlzAffineTransformFromPrimVal(
	       WLZ_TRANSFORM_3D_AFFINE, com.vtX, com.vtY, com.vtZ,
	       s, 0.0, 0.0, 0.0, 0.0, 0.0, 0, &errNum);
      }
      if(errNum == WLZ_ERR_NONE)
      {
	obj1 = WlzAffineTransformObj(mrkObj, tr, WLZ_INTERPOLATION_NEAREST,
				     &errNum);
      }
      if(errNum == WLZ_ERR_NONE)
      {
	obj2 = WlzUnion2(obj0, obj1, &errNum);
      }
      if(errNum == WLZ_ERR_NONE)
      {
        (void )WlzFreeObj(obj0);
	obj0 = obj2;
	obj2 = NULL;
      }
      (void )WlzFreeObj(obj1);
      (void )WlzFreeObj(obj2);
      (void )WlzFreeAffineTransform(tr);
      ++idN;
    }
    if(errNum == WLZ_ERR_NONE)
    {
      WlzValues	val;
      WlzObjectType vTT;

      val.core = NULL;
      if(gV.type != WLZ_GREY_ERROR)
      {
	vTT = WlzGreyTableType(WLZ_GREY_TAB_RAGR, gV.type, NULL);
	if(inObj->type == WLZ_2D_DOMAINOBJ)
	{
	  val.v = WlzNewValueTb(obj0, vTT, bV, &errNum);
	}
	else /* inObj->type == WLZ_3D_DOMAINOBJ */
	{
	  val.vox = WlzNewValuesVox(obj0, vTT, bV, &errNum);
	}
      }
      if(errNum == WLZ_ERR_NONE)
      {
        outObj = WlzMakeMain(inObj->type, obj0->domain, val, NULL, NULL,
	                     &errNum);
      }
      if((errNum == WLZ_ERR_NONE) && (gV.type != WLZ_GREY_ERROR))
      {
        errNum = WlzGreySetValue(outObj, gV);
      }
    }
  }
  if(ok)
  {
    errNum = WLZ_ERR_WRITE_EOF;
    if(((fP = (strcmp(outObjFileStr, "-")?
              fopen(outObjFileStr, "w"): stdout)) == NULL) ||
       ((errNum = WlzWriteObj(fP, outObj)) != WLZ_ERR_NONE))
    {
      ok = 0;
      (void )WlzStringFromErrorNum(errNum, &errMsg);
      (void )fprintf(stderr,
                     "%s: Failed to write output object (%s).\n",
		     *argv, errMsg);
    }
    if(fP && strcmp(outObjFileStr, "-"))
    {
      (void )fclose(fP);
    }
  }
  (void )WlzFreeObj(inObj);
  if(lObj != NULL)
  {
    for(idN = 0; idN < nObj; ++idN)
    {
      (void )WlzFreeObj(lObj[idN]);
    }
    AlcFree(lObj);
  }
  (void )WlzFreeObj(outObj);
  if(usage)
  {
    (void )fprintf(stderr,
    "Usage: %s%sExample: %s%s",
    *argv,
    " [-c#] [-g#] [-G#] [-h] [-m#] [-n#] [-N#]\n"
    "       [-o<output object>] [-r#]] [-x#] [<input object>]\n"
    "Options:\n"
    "  -c  Connectivity: 4, 6, 8, 18 or 26 connected (default 8 for 2D\n"
    "      domains and 26 for 3D domains).\n"
    "  -g  Grey value for marker. This is a single number for all except\n"
    "      RGBA (colour) grey values. RGBA components must be separated by\n"
    "      by a comma.\n"
    "  -G  Grey value type for marker specified by letter:\n"
    "        v  no grey values (default).\n"
    "        u  unsigned byte grey values.\n"
    "        s  short grey values.\n"
    "        i  int grey values.\n"
    "        f  int grey values.\n"
    "        d  int grey values.\n"
    "        r  red, green, blue, alpha grey values.\n"
    "  -h  Help, prints usage message.\n"
    "  -m  Marker type specified by a number:\n"
    "        1  circle/sphere (default)\n"
    "        2  square/cube\n"
    "  -n  Threshold minimum area/volume of blob for a marker (default\n"
    "      >= 1).\n"
    "  -N  Threshold maximum area/volume of blob for a marker. If zero\n"
    "      there is no upper limit. (default  0).\n"
    "  -o  Output object file.\n"
    "  -r  Marker radius. Attempts to keep the same area/volume if zero.\n"
    "      (default 0).\n"
    "  -x  Maximum number of separate regions in the object (default 1024).\n"
    "Reads a spatial domain object and replaces each spatialy separate\n"
    "region with a marker placed at the centre of mass of the region.\n"
    "All files are read from the standard input and written to the standard\n"
    "output unless filenames are given.\n"
    "If grey values are required then the grey value type must be set before\n"
    "the actual grey value.\n",
    *argv,
    " -o out.wlz -n 4 -r 10 -G r -g 200,100,0,255 in.wlz\n"
    "A spatial domain object is read from the file in.wlz and each\n"
    "spatialy separate region of the domain is replaced by a circle or\n"
    "sphere of radius 10 (pixels). All small regions with less than four\n"
    "(pixels voxels) is ignored. The output object (with grey values set\n"
    "to orange) is written to the file out.wlz.\n");
  }
  return(!ok);
}
Example #28
0
/*!
* \return	New object or NULL on error.
* \ingroup	WlzValuesUtils
* \brief 	Transfers grey values from the source object to the
*               destination object within the intersection of the source
*               and destination. Grey values within the destination
*               object outside of the source object are unchanged.
*               It is an error if either object has a different dimension
*               or grey value type, except for when either is an empty
*               object.
* \param	dObj			Destination object which may be
* 					empty, but otherwise should be of the
* 					same dimension as the source object
* 					with valid values..
* \param	sObj			Source object which if not empty must
* 					have both a valid domain and valid
* 					values.
* \param	inplace			Overwrite the destination object's
* 					values if non zero.
* \param	dstErr			Destination error pointer, may be NULL.
*/
WlzObject			*WlzGreyTransfer(
				  WlzObject *dObj,
				  WlzObject *sObj,
				  int inplace,
				  WlzErrorNum *dstErr)
{
  WlzObject	*rObj = NULL;
  WlzErrorNum	errNum = WLZ_ERR_NONE;

  if((dObj == NULL) || (sObj == NULL))
  {
    errNum = WLZ_ERR_OBJECT_NULL;
  }
  else if(WlzIsEmpty(dObj, NULL))
  {
    rObj = WlzMakeEmpty(&errNum);
  }
  else if(WlzIsEmpty(sObj, NULL))
  {
    rObj = WlzMakeMain(dObj->type, dObj->domain, dObj->values,
                       dObj->plist, NULL, &errNum);
  }
  else if(dObj->type != sObj->type)
  {
    errNum = WLZ_ERR_OBJECT_TYPE;
  }
  else if((dObj->domain.core == NULL) || (sObj->domain.core == NULL))
  {
    errNum = WLZ_ERR_DOMAIN_NULL;
  }
  else if(sObj->values.core == NULL)
  {
    errNum = WLZ_ERR_VALUES_NULL;
  }
  else
  {
    switch(sObj->type)
    {
      case WLZ_2D_DOMAINOBJ:
      case WLZ_3D_DOMAINOBJ: /* FALLTHROUGH */
        {
	  WlzObject	*rIObj = NULL;

	  rIObj = WlzIntersect2(dObj, sObj, &errNum);
	  if((errNum == WLZ_ERR_NONE) && (WlzIsEmpty(rIObj, NULL) == 0))
	  {
	    rObj = (inplace)?
		   WlzMakeMain(dObj->type, dObj->domain, dObj->values,
			       dObj->plist, NULL, &errNum):
		   WlzCopyObject(dObj, &errNum);
	    if(errNum == WLZ_ERR_NONE)
	    {
	      /* If the destination object does not have values then
	       * create them to match the domain of the destination
	       * object. */
	      if((sObj->values.core != NULL) && (rObj->values.core == NULL))
	      {
		WlzPixelV bgdV;
		WlzGreyType gType;
		WlzObjectType gTT;
		WlzValues	newVal;

		newVal.core = NULL;
		bgdV = WlzGetBackground(sObj, &errNum);
		if(errNum == WLZ_ERR_NONE)
		{
		  gType = WlzGreyTypeFromObj(sObj, &errNum);
		}
		if(errNum == WLZ_ERR_NONE)
		{
		  gTT = WlzGreyTableType(WLZ_GREY_TAB_RAGR, gType, NULL);
		  if(rObj->type == WLZ_2D_DOMAINOBJ)
		  {
		    newVal.v = WlzNewValueTb(rObj, gTT, bgdV, &errNum);
		  }
		  else /* rObj->type == WLZ_3D_DOMAINOBJ */
		  {
		    newVal.vox = WlzNewValuesVox(rObj, gTT, bgdV, &errNum);
		  }
		}
		if(errNum == WLZ_ERR_NONE)
		{
		  rObj->values = WlzAssignValues(newVal, NULL);
		}
		if(errNum == WLZ_ERR_NONE)
		{
		  errNum = WlzGreySetValue(rObj, bgdV);
		}
	      }
	    }
	    if(errNum == WLZ_ERR_NONE)
	    {
	      if(sObj->type == WLZ_2D_DOMAINOBJ)
	      {
		WlzObject *sIObj;

		rIObj->values = WlzAssignValues(rObj->values, NULL);
		sIObj = WlzMakeMain(WLZ_2D_DOMAINOBJ,
				    rIObj->domain, sObj->values,
				    NULL, NULL, &errNum);
		if(errNum == WLZ_ERR_NONE)
		{
		  errNum = WlzGreyTransfer2D(rIObj, sIObj);
		}
		(void )WlzFreeObj(sIObj);
	      }
	      else /* sObj->type == WLZ_3D_DOMAINOBJ */
	      {
		int	p,
			  rTiled,
			  sTiled,
			  nPlanes;

		rTiled = WlzGreyTableIsTiled(rObj->values.core->type);
		sTiled = WlzGreyTableIsTiled(sObj->values.core->type);
		nPlanes = rIObj->domain.p->lastpl - rIObj->domain.p->plane1 + 1;
#ifdef _OPENMP
#pragma omp parallel for
#endif
		for(p = 0; p < nPlanes; ++p)
		{
		  if(errNum == WLZ_ERR_NONE)
		  {
		    int	     pln;
		    WlzDomain  dom;
		    WlzValues  val;
		    WlzObject  *rIObj2D = NULL,
			       *sIObj2D = NULL;
		    WlzErrorNum errNum2D = WLZ_ERR_NONE;

		    pln = p + rIObj->domain.p->plane1;
		    dom = rIObj->domain.p->domains[p];
		    val = (rTiled)?
			  rObj->values:
			  rObj->values.vox->values[pln -
						   rObj->values.vox->plane1];
		    rIObj2D = WlzMakeMain(WLZ_2D_DOMAINOBJ,
					  dom, val, NULL, NULL, &errNum2D);
		    if(errNum2D == WLZ_ERR_NONE)
		    {
		      val = (sTiled)?
			    sObj->values:
			    sObj->values.vox->values[pln -
						     sObj->values.vox->plane1];
		      sIObj2D = WlzMakeMain(WLZ_2D_DOMAINOBJ,
					    dom, val, NULL, NULL, &errNum2D);
		    }
		    if(errNum2D == WLZ_ERR_NONE)
		    {
		      errNum2D = WlzGreyTransfer2D(rIObj2D, sIObj2D);
		    }
		    (void )WlzFreeObj(rIObj2D);
		    (void )WlzFreeObj(sIObj2D);
#ifdef _OPENMP
#pragma omp critical
		    {
#endif
		      if((errNum == WLZ_ERR_NONE) && (errNum2D != WLZ_ERR_NONE))
		      {
			errNum = errNum2D;
		      }
#ifdef _OPENMP
		    }
#endif
		  }
		}
	      }
	    }
	  }
	  (void )WlzFreeObj(rIObj);
	}
	break;
      default:
	errNum = WLZ_ERR_OBJECT_TYPE;
        break;
    }
  }
  if(errNum != WLZ_ERR_NONE)
  {
    WlzFreeObj(rObj);
    rObj = NULL;
  }
  if(dstErr)
  {
    *dstErr = errNum;
  }
  return(rObj);
}
Example #29
0
/*! 
* \ingroup      WlzBoundary
* \brief        Return a domain object corresponding to the input boundary
object.
*
* \return       Domain object corresponding to the input boundary, NULL on error.
* \param    boundary	Input boundary object.
* \param    fillMode	Fill mode for the individual polyline boundaries.
 If the input object is a genuine boundary object then there will be no
 self-intersecting polylines and <tt> fillMode = WLZ_SIMPLE_FILL </tt>
 is appropriate. See WlzPolyToObj().
 * \param    dstErr	Error return
* \par      Source:
*                WlzBoundToObj.c
*/
WlzObject *WlzBoundaryToObj(
  WlzObject		*boundary,
  WlzPolyFillMode	fillMode,
  WlzErrorNum		*dstErr)
{
  WlzObject	*rtnObj=NULL, *tmpObj;
  WlzDomain	domain, *domains, *bnddmns;
  WlzValues	values;
  int		p;
  WlzErrorNum	errNum=WLZ_ERR_NONE;

  /* check object */
  if( boundary == NULL ){
    errNum = WLZ_ERR_OBJECT_NULL;
  }
  else {
    switch( boundary->type ){
    case WLZ_3D_DOMAINOBJ:
      /* check plane domain */
      if( boundary->domain.p == NULL ){
	errNum = WLZ_ERR_DOMAIN_NULL;
      }
      else {
	switch( boundary->domain.p->type ){
	case WLZ_PLANEDOMAIN_BOUNDLIST:
	  if((domain.p = WlzMakePlaneDomain(WLZ_PLANEDOMAIN_DOMAIN,
					    boundary->domain.p->plane1,
					    boundary->domain.p->lastpl,
					    boundary->domain.p->line1,
					    boundary->domain.p->lastln,
					    boundary->domain.p->kol1,
					    boundary->domain.p->lastkl,
					    &errNum)) != NULL){
	    domain.p->voxel_size[0] = boundary->domain.p->voxel_size[0];
	    domain.p->voxel_size[1] = boundary->domain.p->voxel_size[1];
	    domain.p->voxel_size[2] = boundary->domain.p->voxel_size[2];
	    domains = domain.p->domains;
	    bnddmns = boundary->domain.p->domains;
	    for(p=domain.p->plane1; p <= domain.p->lastpl;
		p++, domains++, bnddmns++){
	      if( (*bnddmns).poly ){
		if((tmpObj = WlzBoundToObj((*bnddmns).b, fillMode,
					   &errNum)) != NULL){
		  *domains = WlzAssignDomain(tmpObj->domain, NULL);
		  WlzFreeObj(tmpObj);
		}
		else {
		  WlzFreePlaneDomain(domain.p);
		  domain.p = NULL;
		  break;
		}
	      }
	    }
	    if( domain.p ){
	      values.core = NULL;
	      if( (rtnObj = WlzMakeMain(WLZ_3D_DOMAINOBJ, domain, values,
					NULL, NULL, &errNum)) == NULL ){
		WlzFreePlaneDomain(domain.p);
	      }
	    }
	  }
	  break;
	  
	case WLZ_EMPTY_DOMAIN:
	  return WlzMakeEmpty(dstErr);

	default:
	  errNum = WLZ_ERR_DOMAIN_TYPE;
	  break;
	}
      }
      break;

    case WLZ_BOUNDLIST:
      return WlzBoundToObj(boundary->domain.b, fillMode, dstErr);

    case WLZ_TRANS_OBJ:
      if((values.obj = WlzBoundaryToObj(boundary->values.obj, fillMode,
				       &errNum)) != NULL){
	return WlzMakeMain(WLZ_TRANS_OBJ, boundary->domain, values,
			   NULL, NULL, dstErr);
      }
      break;

    case WLZ_EMPTY_OBJ:
      return WlzMakeEmpty(dstErr);

    default:
      errNum = WLZ_ERR_OBJECT_TYPE;
      break;
    }
  }

  if( dstErr ){
    *dstErr = errNum;
  }
  return rtnObj;
}
Example #30
0
/*!
* \return	Object read from file.
* \ingroup	WlzExtFF
* \brief	Reads a Woolz object from the given stream using the
* 		stereolithography stl surface file format. This format
* 		has surface definitions defined by a name and a collection
* 		of facet normals and loops. Each facet loop has the
* 		cooordinates of it's vertices.
* 		Only triangulated surface models can be read and all solids
* 		will be treated as one.
* \param	fP			Input file stream.
* \param	dstErr			Destination error number ptr, may be
* 					NULL.
*/
WlzObject	*WlzEffReadObjStl(FILE *fP, WlzErrorNum *dstErr)
{
  int		vCnt = 0,
  		inSolid = 0,
  		inFacet = 0,
		inLoop = 0;
  char		*sav,
  		*str,
  		*tok;
  WlzDVertex3	vBuf[3];
  WlzGMModel	*model = NULL;
  WlzObject	*obj = NULL;
  WlzDomain	dom;
  WlzValues	val;
  WlzErrorNum	errNum = WLZ_ERR_NONE;
  char		cBuf[256];

  dom.core = NULL;
  val.core = NULL;
  if(fP == NULL)
  {
    errNum = WLZ_ERR_PARAM_NULL;
  }
  else
  {
    model = WlzGMModelNew(WLZ_GMMOD_3D, 0, 0, &errNum);
  }
  while((errNum == WLZ_ERR_NONE) &&
        ((str = WlzEffReadObjStlRec(fP, cBuf, 256)) != NULL))
  {
    if((tok = strtok_r(str, " \t", &sav)) != NULL)
    {
      if(strncmp(tok, "solid", 5) == 0)
      {
        if(inSolid == 0)
	{
	  inSolid = 1;
	}
	else
	{
	  errNum = WLZ_ERR_READ_INCOMPLETE;
	}
      }
      else if(strncmp(tok, "facet", 5) == 0)
      {
        if((inSolid == 1) && (inFacet == 0))
	{
	  inFacet = 1;
	  /* Normal vector is ignored. */
	}
	else
	{
	  errNum = WLZ_ERR_READ_INCOMPLETE;
	}
      }
      else if(strncmp(tok, "outer", 5) == 0)
      {
        if(((tok = strtok_r(NULL, " \t", &sav)) == NULL) ||
	   (strncmp(tok, "loop", 4) != 0) ||
           (inSolid == 0) || (inFacet == 0) || (inLoop != 0))
	{
	  errNum = WLZ_ERR_READ_INCOMPLETE;
	}
	else
	{
	  vCnt = 0;
	  inLoop = 1;
	}
      }
      else if(strncmp(tok, "vertex", 6) == 0)
      {
	char *pTok[3];

        if((vCnt < 3) &&
	   ((pTok[0] = strtok_r(NULL, " \t", &sav)) != NULL) &&
	   ((pTok[1] = strtok_r(NULL, " \t", &sav)) != NULL) &&
	   ((pTok[2] = strtok_r(NULL, " \t", &sav)) != NULL) &&
	   (sscanf(pTok[0], "%lg", &(vBuf[vCnt].vtX)) == 1) &&
	   (sscanf(pTok[1], "%lg", &(vBuf[vCnt].vtY)) == 1) &&
	   (sscanf(pTok[2], "%lg", &(vBuf[vCnt].vtZ)) == 1))
	{
	  ++vCnt;
	}
	else
	{
	  errNum = WLZ_ERR_READ_INCOMPLETE;
	}
      }
      else if(strncmp(tok, "endloop", 7) == 0)
      {
        if(inLoop == 1)
	{
	  inLoop = 0;
	  if(vCnt == 3)
	  {
	    errNum = WlzGMModelConstructSimplex3D(model, vBuf);
	  }
	  else
	  {
	    errNum = WLZ_ERR_READ_INCOMPLETE;
	  }
	}
	else
	{
	  errNum = WLZ_ERR_READ_INCOMPLETE;
	}
      }
      else if(strncmp(tok, "endfacet", 8) == 0)
      {
        if(inFacet == 1)
	{
	  inFacet = 0;
	}
	else
	{
	  errNum = WLZ_ERR_READ_INCOMPLETE;
	}
      }
      else if(strncmp(tok, "endsolid", 8) == 0)
      {
        if(inSolid == 1)
	{
	  inSolid = 0;
	}
	else
	{
	  errNum = WLZ_ERR_READ_INCOMPLETE;
	}
      }
    }
  }
  /* Create the Woolz object. */
  if(errNum == WLZ_ERR_NONE)
  {
    if((dom.ctr = WlzMakeContour(&errNum)) != NULL)
    {
      dom.ctr->model = WlzAssignGMModel(model, NULL);
      obj = WlzMakeMain(WLZ_CONTOUR, dom, val, NULL, NULL, &errNum);
    }
  }
  if(errNum != WLZ_ERR_NONE)
  {
    if(obj != NULL)
    {
      (void )WlzFreeObj(obj);
    }
    else if(dom.ctr != NULL)
    {
      (void )WlzFreeContour(dom.ctr);
    }
    else
    {
      (void )WlzGMModelFree(model);
    }
    obj = NULL;
  }
  if(dstErr)
  {
    *dstErr = errNum;
  }
  return(obj);
}