/*! * \return Woolz error code. * \ingroup WlzValuesUtils * \brief Sets the values of a 2 or 3D domain object with int * values so that they increment throughout the object * in scan order. Object values are set by incrementing * the given value in place. The given object must have * WLZ_GREY_INT values. * \param obj The given object. * \param gVal Pointer to current value, this is * incremented in place. If NULL then * the values will be incremented from * zero. */ WlzErrorNum WlzGreySetIncValues(WlzObject *obj, int *gVal) { int val; WlzGreyType gType; WlzErrorNum errNum = WLZ_ERR_NONE; if(obj == NULL) { errNum = WLZ_ERR_OBJECT_NULL; } else if(obj->domain.core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } else if(obj->values.core == NULL) { errNum = WLZ_ERR_VALUES_NULL; } else { gType = WlzGreyTypeFromObj(obj, &errNum); } if(errNum == WLZ_ERR_NONE) { if(gType != WLZ_GREY_INT) { errNum = WLZ_ERR_GREY_TYPE; } } if(errNum == WLZ_ERR_NONE) { val = (gVal)? *gVal: 0; switch(obj->type) { case WLZ_2D_DOMAINOBJ: /* FALLTROUGH */ case WLZ_3D_DOMAINOBJ: errNum = WlzGreySetIncValuesItr(obj, &val); break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } if(gVal && (errNum == WLZ_ERR_NONE)) { *gVal = val; } } return(errNum); }
/*! * \return Woolz error code. * \ingroup WlzExtFF * \brief Writes the given object to a jpeg image. * \param fP Given file stream. * \param obj Given object to be written. * \param params Jpeg parameters string, currently this * is a single ascii integer, which should * have the range 1 - 100 and rpresents * the image quality with 100 being * lossless. */ WlzErrorNum WlzEffWriteObjJpeg( FILE *fP, WlzObject *obj, char *params) { WlzErrorNum errNum=WLZ_ERR_NONE; struct jpeg_compress_struct cinfo; struct my_error_mgr jerr; JSAMPARRAY buffer = NULL; /* Output row buffer */ int quality = 100; /* Output quality. */ int row_stride; /* physical row width in input buffer */ int width, height; WlzIntervalWSpace iwsp; WlzGreyWSpace gwsp; int i, j; WlzObject *rectObj=NULL; WlzGreyType gType = WLZ_GREY_ERROR; /* check input */ if( fP == NULL ){ errNum = WLZ_ERR_PARAM_NULL; } if( obj ){ switch( obj->type ){ case WLZ_2D_DOMAINOBJ: if( obj->domain.core ){ if( obj->values.core == NULL ){ errNum = WLZ_ERR_VALUES_NULL; } else { WlzIBox2 cutBox; cutBox.xMin = obj->domain.i->kol1; cutBox.yMin = obj->domain.i->line1; cutBox.xMax = obj->domain.i->lastkl; cutBox.yMax = obj->domain.i->lastln; gType = WlzGreyTypeFromObj(obj, &errNum); if((rectObj = WlzCutObjToBox2D(obj, cutBox, gType, 0, 0.0, 0.0, &errNum)) != NULL){ width = rectObj->domain.i->lastkl - rectObj->domain.i->kol1 + 1; height = rectObj->domain.i->lastln - rectObj->domain.i->line1 + 1; } } } else { errNum = WLZ_ERR_DOMAIN_NULL; } break; case WLZ_TRANS_OBJ: errNum = WlzEffWriteObjJpeg(fP, obj->values.obj, params); break; case WLZ_EMPTY_OBJ: return WLZ_ERR_NONE; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } else { errNum = WLZ_ERR_OBJECT_NULL; } /* We set up the normal JPEG error routines, then override error_exit. */ if( errNum == WLZ_ERR_NONE ){ cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = my_error_exit; /* Establish the setjmp return context for my_error_exit to use. */ if (setjmp(jerr.setjmp_buffer)) { /* If we get here, the JPEG code has signaled an error. * We need to clean up the JPEG object, close the input file, and return. */ jpeg_destroy_compress(&cinfo); if( rectObj ){ WlzFreeObj(rectObj); } errNum = WLZ_ERR_WRITE_INCOMPLETE; } } if( errNum == WLZ_ERR_NONE ){ jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, fP); /* set the image parameters */ width = obj->domain.i->lastkl - obj->domain.i->kol1 + 1; height = obj->domain.i->lastln - obj->domain.i->line1 + 1; cinfo.image_width = width; cinfo.image_height = height; switch( gType ){ case WLZ_GREY_INT: case WLZ_GREY_SHORT: case WLZ_GREY_FLOAT: case WLZ_GREY_DOUBLE: errNum = WLZ_ERR_UNIMPLEMENTED; break; case WLZ_GREY_UBYTE: cinfo.input_components = 1; cinfo.in_color_space = JCS_GRAYSCALE; break; case WLZ_GREY_RGBA: cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; break; default: break; } if( errNum == WLZ_ERR_NONE ){ /* set the default parameters */ jpeg_set_defaults(&cinfo); /* check for other parameters */ if( params ){ sscanf(params, "%d", &quality); } jpeg_set_quality(&cinfo, quality, TRUE); /* JSAMPLEs per row in output buffer */ row_stride = cinfo.image_width * cinfo.input_components; /* Make a one-row-high sample array that will go away when done with * image */ buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); } else { jpeg_destroy_compress(&cinfo); if( rectObj ){ WlzFreeObj(rectObj); } } } if( errNum == WLZ_ERR_NONE ){ jpeg_start_compress(&cinfo, TRUE); /* loop through the woolz object setting the output buffer note this is the "input" to the compressor */ if((errNum = WlzInitGreyScan(rectObj, &iwsp, &gwsp)) == WLZ_ERR_NONE){ while((errNum = WlzNextGreyInterval(&iwsp)) == WLZ_ERR_NONE){ WlzUInt val; switch( gType ){ case WLZ_GREY_UBYTE: for(i=0, j=0; i < width; i++){ buffer[0][j++] = gwsp.u_grintptr.ubp[i]; } break; case WLZ_GREY_RGBA: for(i=0, j=0; i < width; i++){ val = gwsp.u_grintptr.rgbp[i]; buffer[0][j++] = WLZ_RGBA_RED_GET(val); buffer[0][j++] = WLZ_RGBA_GREEN_GET(val); buffer[0][j++] = WLZ_RGBA_BLUE_GET(val); } break; default: break; } (void) jpeg_write_scanlines(&cinfo, buffer, 1); } if( errNum == WLZ_ERR_EOO ){ errNum = WLZ_ERR_NONE; } } jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); WlzFreeObj(rectObj); } return errNum; }
/*! * \ingroup WlzValuesFilters * \brief Gaussian filter of grey-level 2D woolz object. x- and y-coordinate width parameters and derivative degree can be independently specified. For derivative zero, i.e. Gaussian smoothing, the filter is normalised. Derivatives are derivative of the normalised filter. RGB data will only return values for smoothing, higher derivatives are not implemented. The width parameter is the full-width half-height of the Gaussian distribution. Note RGB pixel types are converted to a compound object with each channel returned with WLZ_GREY_SHORT pixel type. * * \return Pointer to transformed object * \param obj Input object * \param wx x-direction width parameter * \param wy y-direction width parameter * \param x_deriv x-direction derivative * \param y_deriv y-direction derivative * \param wlzErr error return * \par Source: * WlzGauss.c */ WlzObject *WlzGauss2( WlzObject *obj, double wx, double wy, int x_deriv, int y_deriv, WlzErrorNum *wlzErr) { WlzObject *newobj=NULL; Wlz1DConvMask x_params, y_params; float alpha, sum; int i, n, value; WlzErrorNum errNum=WLZ_ERR_NONE; /* check object, don't need to check type etc. because WlzSepTrans does it */ if( obj == NULL ) { errNum = WLZ_ERR_OBJECT_NULL; } /* do need to check for rgb grey type */ if( errNum == WLZ_ERR_NONE ){ if( (obj->type == WLZ_2D_DOMAINOBJ) && (WlzGreyTypeFromObj(obj, &errNum) == WLZ_GREY_RGBA) ){ if( (x_deriv != 0) || (y_deriv != 0) ){ /* implement this using a compond object since the result should be a vector value */ WlzCompoundArray *cobj; if((cobj = WlzRGBAToCompound(obj, WLZ_RGBA_SPACE_RGB, &errNum)) != NULL){ /* need to convert each to short for gradient calc */ for(i=0; i < 3; i++){ WlzObject *tmpObj; tmpObj = cobj->o[i]; cobj->o[i] = WlzAssignObject(WlzConvertPix(tmpObj, WLZ_GREY_SHORT, &errNum), NULL); WlzFreeObj(tmpObj); } newobj = WlzGauss2((WlzObject *) cobj, wx, wy, x_deriv, y_deriv, &errNum); WlzFreeObj((WlzObject *) cobj); if( wlzErr ){ *wlzErr = errNum; } return newobj; } } } } /* now start work */ if( errNum == WLZ_ERR_NONE ){ alpha = (float )(4.0 * log((double )2.0)); /* set up x function parameters */ x_params.mask_size = (((int) wx * 4)/2)*2 + 1; if( (x_params.mask_values = (int *) AlcMalloc(sizeof(int) * x_params.mask_size)) == NULL){ errNum = WLZ_ERR_MEM_ALLOC; } else { n = x_params.mask_size / 2; switch( x_deriv ){ case 0: for(i=0, sum = -AFACTOR; i <= n; i++){ value = (int )(AFACTOR * exp(((double) -alpha*i*i/wx/wx))); *(x_params.mask_values+n-i) = value; *(x_params.mask_values+n+i) = value; sum += 2 * value; } x_params.norm_factor = sum; break; case 1: *(x_params.mask_values+n) = 0.0; for(i=1, sum = 0; i <= n; i++){ value = (int )(AFACTOR * i * exp(((double) -alpha*i*i/wx/wx))); *(x_params.mask_values+n-i) = value; *(x_params.mask_values+n+i) = -value; sum += value; } /* sum *= -wx / 2 / sqrt( log( (double) 2 ) / WLZ_M_PI );*/ if( n > 0 ) x_params.norm_factor = sum; else x_params.norm_factor = 1; break; case 2: for(i=0; i <= n; i++){ value = (int )(AFACTOR * (alpha * i*i / wx/wx -1) * exp(((double) -alpha*i*i/wx/wx))); *(x_params.mask_values+n-i) = value; *(x_params.mask_values+n+i) = value; } x_params.norm_factor = (int )(*(x_params.mask_values+n) * wx*wx*wx / 4 / alpha / sqrt(log((double )2) / WLZ_M_PI )); break; default: AlcFree((void *) x_params.mask_values); x_params.mask_values = NULL; errNum = WLZ_ERR_PARAM_DATA; break; } } } /* set up y function parameters */ if( errNum == WLZ_ERR_NONE ){ y_params.mask_size = (((int) wy * 4)/2)*2 + 1; if( (y_params.mask_values = (int *) AlcMalloc(sizeof(int) * y_params.mask_size)) == NULL){ AlcFree((void *) x_params.mask_values); errNum = WLZ_ERR_MEM_ALLOC; } else { n = y_params.mask_size / 2; switch( y_deriv ){ case 0: for(i=0, sum = -AFACTOR; i <= n; i++){ value = (int )(AFACTOR * exp(((double) -alpha*i*i/wy/wy))); *(y_params.mask_values+n-i) = value; *(y_params.mask_values+n+i) = value; sum += 2 * value; } y_params.norm_factor = sum; break; case 1: *(y_params.mask_values+n) = 0.0; for(i=1, sum = 0; i <= n; i++){ value = (int )(AFACTOR * i * exp(((double) -alpha*i*i/wy/wy))); *(y_params.mask_values+n-i) = value; *(y_params.mask_values+n+i) = -value; sum += value; } /* sum *= -wy / 2 / sqrt( log( (double) 2 ) /WLZ_M_PI );*/ if( n > 0 ) y_params.norm_factor = sum; else y_params.norm_factor = 1; break; case 2: for(i=0; i <= n; i++){ value = (int )(AFACTOR * (alpha * i*i / wy/wy -1) * exp(((double) -alpha*i*i/wy/wy))); *(y_params.mask_values+n-i) = value; *(y_params.mask_values+n+i) = value; } y_params.norm_factor = (int )(*(y_params.mask_values+n) * wy*wy*wy / 4 / alpha / sqrt( log( (double) 2 ) / WLZ_M_PI )); break; default: AlcFree((void *) x_params.mask_values); AlcFree((void *) y_params.mask_values); x_params.mask_values = NULL; y_params.mask_values = NULL; errNum = WLZ_ERR_PARAM_DATA; break; } } } if( errNum == WLZ_ERR_NONE ){ newobj = WlzSepTrans(obj, Wlz1DConv, (void *) &x_params, Wlz1DConv, (void *) &y_params, &errNum); AlcFree((void *) x_params.mask_values); AlcFree((void *) y_params.mask_values); } if( wlzErr ) { *wlzErr = errNum; } return(newobj); }
/*! * \return Woolz error code. * \ingroup WlzBinaryOps * \brief Splits the given montage object into component objects * clipped from the montage object. The montage object * must be composed of component images embedded in a * background, with little variation in the background * values. * \param mObj Montage object, which must be either * a WLZ_2D_DOMAINOBJ or a * WLZ_3D_DOMAINOBJ with values. * \param gapV Value for the uniform background. * Must be either WLZ_GREY_INT or * WLZ_GREY_RGBA. * \param tol Tolerance (fraction) for the * variation in background values. * \param bWidth Additional boundary width added * to detected images before they are * clipped. * \param minArea Minimum area for a valid component * image, must be greater than zero. * \param maxComp Maximum number of components. * \param dstNComp Destination pointer for the number of * components extracted, must not be NULL. * \param dstComp Destination pointer for the extracted * components, must not be NULL. */ WlzErrorNum WlzSplitMontageObj(WlzObject *mObj, WlzPixelV gapV, double tol, int bWidth, int minArea, int maxComp, int *dstNComp, WlzObject ***dstComp) { int id0, id1, area, nLComp = 0; WlzObject *gObj = NULL, *tObj = NULL; WlzObject **lComp; WlzGreyType objG; WlzBox box; WlzPixelV gapLV, gapHV; WlzConnectType lCon; int tI[8]; WlzErrorNum errNum = WLZ_ERR_NONE; tol = WLZ_CLAMP(tol, 0.0, 1.0); if(mObj == NULL) { errNum = WLZ_ERR_OBJECT_NULL; } else if(minArea < 1) { errNum = WLZ_ERR_PARAM_DATA; } else { switch(mObj->type) { case WLZ_2D_DOMAINOBJ: lCon = WLZ_4_CONNECTED; break; case WLZ_3D_DOMAINOBJ: lCon = WLZ_6_CONNECTED; break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } if(errNum == WLZ_ERR_NONE) { objG = WlzGreyTypeFromObj(mObj, &errNum); } if(errNum == WLZ_ERR_NONE) { switch(gapV.type) { case WLZ_GREY_INT: /* FALLTHROUGH */ case WLZ_GREY_RGBA: break; default: errNum = WLZ_ERR_GREY_TYPE; break; } } if(errNum == WLZ_ERR_NONE) { if(objG == WLZ_GREY_RGBA) { if(gapV.type != WLZ_GREY_RGBA) { (void )WlzValueConvertPixel(&gapV, gapV, WLZ_GREY_RGBA); } } else { if(gapV.type != WLZ_GREY_INT) { (void )WlzValueConvertPixel(&gapV, gapV, WLZ_GREY_INT); } } gapLV.type = gapHV.type = gapV.type; if(gapV.type == WLZ_GREY_INT) { tI[0] = gapV.v.inv * tol; gapLV.v.inv = gapV.v.inv - tI[0]; gapHV.v.inv = gapV.v.inv + tI[0]; tObj = WlzThreshold(mObj, gapLV, WLZ_THRESH_HIGH, &errNum); if((errNum == WLZ_ERR_NONE) && (tObj != NULL)) { gObj = WlzThreshold(tObj, gapHV, WLZ_THRESH_LOW, &errNum); } (void )WlzFreeObj(tObj); tObj = NULL; } else /* gapV.type == WLZ_GREY_RGBA */ { tI[0] = WLZ_RGBA_RED_GET(gapV.v.rgbv); tI[1] = (int )floor((double )(tI[0]) * tol); tI[2] = tI[0] - tI[1]; tI[5] = tI[0] + tI[1]; tI[0] = WLZ_RGBA_GREEN_GET(gapV.v.rgbv); tI[1] = (int )floor((double )(tI[0]) * tol); tI[3] = tI[0] - tI[1]; tI[6] = tI[0] + tI[1]; tI[0] = WLZ_RGBA_BLUE_GET(gapV.v.rgbv); tI[1] = (int )floor((double )(tI[0]) * tol); tI[4] = tI[0] - tI[1]; tI[7] = tI[0] + tI[1]; tI[2] = WLZ_CLAMP(tI[2], 0, 255); tI[3] = WLZ_CLAMP(tI[3], 0, 255); tI[4] = WLZ_CLAMP(tI[4], 0, 255); WLZ_RGBA_RGBA_SET(gapLV.v.rgbv, tI[2], tI[3], tI[4], 255); tI[5] = WLZ_CLAMP(tI[5], 0, 255); tI[6] = WLZ_CLAMP(tI[6], 0, 255); tI[7] = WLZ_CLAMP(tI[7], 0, 255); WLZ_RGBA_RGBA_SET(gapHV.v.rgbv, tI[5], tI[6], tI[7], 255); gObj = WlzRGBABoxThreshold(mObj, gapLV, gapHV, &errNum); } } if(errNum == WLZ_ERR_NONE) { tObj = WlzDiffDomain(mObj, gObj, &errNum); } (void )WlzFreeObj(gObj); if(errNum == WLZ_ERR_NONE) { errNum = WlzLabel(tObj, &nLComp, &lComp, maxComp, 0, lCon); } (void )WlzFreeObj(tObj); if(errNum == WLZ_ERR_NONE) { /* Get rid of small objects using minArea as the threshold. */ id0 = 0; id1 = 0; while(id0 < nLComp) { switch((*(lComp + id0))->type) { case WLZ_2D_DOMAINOBJ: area = WlzArea(*(lComp + id0), NULL); break; case WLZ_3D_DOMAINOBJ: area = WlzVolume(*(lComp + id0), NULL); break; default: area = 0; break; } if(area >= minArea) { *(lComp + id1) = *(lComp + id0); ++id1; } else { (void )WlzFreeObj(*(lComp + id0)); *(lComp + id0) = NULL; } ++id0; } nLComp = id1; } if(errNum == WLZ_ERR_NONE) { /* Clip rectangular objects from the montage object. */ id0 = 0; while((errNum == WLZ_ERR_NONE) && (id0 < nLComp)) { if(tObj->type == WLZ_2D_DOMAINOBJ) { box.i2 = WlzBoundingBox2I(*(lComp + id0), &errNum); box.i2.xMin -= bWidth; box.i2.yMin -= bWidth; box.i2.xMax += bWidth; box.i2.yMax += bWidth; (void )WlzFreeObj(*(lComp + id0)); *(lComp + id0) = WlzClipObjToBox2D(mObj, box.i2, &errNum); } else /* tObj->type == WLZ_3D_DOMAINOBJ */ { box.i3 = WlzBoundingBox3I(*(lComp + id0), &errNum); box.i3.xMin -= bWidth; box.i3.yMin -= bWidth; box.i3.zMin -= bWidth; box.i3.xMax += bWidth; box.i3.yMax += bWidth; box.i3.zMax += bWidth; (void )WlzFreeObj(*(lComp + id0)); *(lComp + id0) = WlzClipObjToBox3D(mObj, box.i3, &errNum); } ++id0; } } *dstNComp = nLComp; *dstComp = lComp; return(errNum); }
/*! * \return projection object * \ingroup WlzTransform * \brief Use the view transform to define a projection from * 3D to 2D. Currently only the domain is projected as * an opaque shadow. * This is old code temporarily kept for compatibility. * \param obj source 3D object * \param viewStr view structure defining the projection * \param intFunc grey-value summation function * \param intFuncData data to be passed to the integration function * \param dstErr error return */ WlzObject *WlzGetProjectionFromObject( WlzObject *obj, WlzThreeDViewStruct *viewStr, Wlz3DProjectionIntFn intFunc, void *intFuncData, WlzErrorNum *dstErr) { WlzObject *rtnObj=NULL, *obj1; WlzThreeDViewStruct *viewStr1=NULL; WlzDomain domain; WlzValues values; WlzGreyType srcGType = WLZ_GREY_UBYTE, dstGType = WLZ_GREY_UBYTE; WlzPixelV pixval; WlzPixelP pixptr; WlzIntervalWSpace iwsp; WlzGreyWSpace gwsp; WlzGreyValueWSpace *gVWSp = NULL; WlzDVertex3 vtx, vtx1; double x, y, z; double *s_to_x=NULL; double *s_to_y=NULL; double *s_to_z=NULL; int k, xp, yp, s, sp; int length = 0, size = 0, occupiedFlg; WlzErrorNum errNum=WLZ_ERR_NONE; /* check inputs */ if( obj == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; } else if( obj->type != WLZ_3D_DOMAINOBJ ){ errNum = WLZ_ERR_OBJECT_TYPE; } else if( obj->domain.core == NULL ){ errNum = WLZ_ERR_DOMAIN_NULL; } else if( obj->domain.core->type != WLZ_PLANEDOMAIN_DOMAIN ){ errNum = WLZ_ERR_DOMAIN_TYPE; } if( (errNum == WLZ_ERR_NONE) && (viewStr == NULL) ){ errNum = WLZ_ERR_OBJECT_NULL; } /* create new view transform */ if( errNum == WLZ_ERR_NONE ){ if((viewStr1 = WlzMake3DViewStruct(WLZ_3D_VIEW_STRUCT, &errNum)) != NULL){ /* need to worry about fixed line mode here sometime */ viewStr1->fixed = viewStr->fixed; viewStr1->theta = viewStr->theta; viewStr1->phi = viewStr->phi; viewStr1->zeta = viewStr->zeta; viewStr1->dist = viewStr->dist; viewStr1->scale = viewStr->scale; viewStr1->voxelSize[0] = viewStr->voxelSize[0]; viewStr1->voxelSize[1] = viewStr->voxelSize[1]; viewStr1->voxelSize[2] = viewStr->voxelSize[2]; viewStr1->voxelRescaleFlg = viewStr->voxelRescaleFlg; viewStr1->interp = viewStr->interp; viewStr1->view_mode = viewStr->view_mode; viewStr1->up = viewStr->up; /* now intialize it */ /* could optimise by setting fixed point to object centre */ if( (errNum = WlzInit3DViewStruct(viewStr1, obj)) != WLZ_ERR_NONE ){ WlzFree3DViewStruct(viewStr1); viewStr1 = NULL; } } } /* set up orthogonal line parameters & luts */ if( errNum == WLZ_ERR_NONE ){ length = WLZ_NINT(viewStr1->maxvals.vtZ) - WLZ_NINT(viewStr1->minvals.vtZ) + 1; s_to_x = (double *) AlcMalloc(sizeof(double) * length ); s_to_y = (double *) AlcMalloc(sizeof(double) * length ); s_to_z = (double *) AlcMalloc(sizeof(double) * length ); /* transform a perpendicular vector */ vtx.vtX = 0.0; vtx.vtY = 0.0; vtx.vtZ = 1.0; Wlz3DSectionTransformInvVtx(&vtx, viewStr1); vtx1.vtX = 0.0; vtx1.vtY = 0.0; vtx1.vtZ = 0.0; Wlz3DSectionTransformInvVtx(&vtx1, viewStr1); vtx.vtX -= vtx1.vtX; vtx.vtY -= vtx1.vtY; vtx.vtZ -= vtx1.vtZ; /* assign lut values */ s = (int )(WLZ_NINT(viewStr1->minvals.vtZ) - viewStr1->dist); for(sp=0; sp < length; sp++, s++){ s_to_x[sp] = s * vtx.vtX; s_to_y[sp] = s * vtx.vtY; s_to_z[sp] = s * vtx.vtZ; } } /* if there is an integration function then allocate space for the grey-level array */ if( (errNum == WLZ_ERR_NONE) && (intFunc) ){ srcGType = WlzGreyTypeFromObj(obj, &errNum); switch( srcGType ){ case WLZ_GREY_LONG: size = sizeof(WlzLong)*length; break; case WLZ_GREY_INT: size = sizeof(int)*length; break; case WLZ_GREY_SHORT: size = sizeof(short)*length; break; case WLZ_GREY_UBYTE: size = sizeof(WlzUByte)*length; break; case WLZ_GREY_FLOAT: size = sizeof(float)*length; break; case WLZ_GREY_DOUBLE: size = sizeof(double)*length; break; case WLZ_GREY_RGBA: size = sizeof(int)*length; break; default: errNum = WLZ_ERR_GREY_TYPE; break; } if( (pixptr.p.inp = (int *) AlcMalloc(size)) == NULL ){ errNum = WLZ_ERR_MEM_ALLOC; } pixptr.type = srcGType; /* set up the grey-value workspace for random access */ gVWSp = WlzGreyValueMakeWSp(obj, &errNum); } /* create rectangular projection image */ if( errNum == WLZ_ERR_NONE ){ if((domain.i = WlzMakeIntervalDomain(WLZ_INTERVALDOMAIN_RECT, WLZ_NINT(viewStr1->minvals.vtY), WLZ_NINT(viewStr1->maxvals.vtY), WLZ_NINT(viewStr1->minvals.vtX), WLZ_NINT(viewStr1->maxvals.vtX), &errNum)) != NULL){ values.core = NULL; if((rtnObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, domain, values, NULL, NULL, &errNum)) != NULL){ /* note the grey-values required are determined by the integration function. Here we use WlzUByte and reset later if needed */ dstGType = WLZ_GREY_UBYTE; pixval.type = WLZ_GREY_UBYTE; pixval.v.ubv = (WlzUByte )0; if((values.v = WlzNewValueTb(rtnObj, WlzGreyTableType(WLZ_GREY_TAB_RECT, dstGType, NULL), pixval, &errNum)) != NULL){ rtnObj->values = WlzAssignValues(values, &errNum); } else { WlzFreeObj(rtnObj); rtnObj = NULL; } } else { WlzFreeDomain(domain); domain.core = NULL; } } } /* scan image setting values */ if( errNum == WLZ_ERR_NONE ){ errNum = WlzInitGreyScan(rtnObj, &iwsp, &gwsp); } if( errNum == WLZ_ERR_NONE ){ while( (errNum = WlzNextGreyInterval(&iwsp)) == WLZ_ERR_NONE ){ yp = iwsp.linpos - WLZ_NINT(viewStr1->minvals.vtY); for(k=iwsp.lftpos; k <= iwsp.rgtpos; k++){ xp = k - WLZ_NINT(viewStr1->minvals.vtX); vtx.vtX = viewStr1->xp_to_x[xp] + viewStr1->yp_to_x[yp]; vtx.vtY = viewStr1->xp_to_y[xp] + viewStr1->yp_to_y[yp]; vtx.vtZ = viewStr1->xp_to_z[xp] + viewStr1->yp_to_z[yp]; /* get the projection values */ /* if no function then just check for occupancy */ if( intFunc == NULL ){ occupiedFlg = 0; sp = (int )(viewStr1->dist - WLZ_NINT(viewStr1->minvals.vtZ)); for(; !occupiedFlg && (sp < length); sp++){ x = vtx.vtX + s_to_x[sp]; y = vtx.vtY + s_to_y[sp]; z = vtx.vtZ + s_to_z[sp]; if( WlzInsideDomain(obj, z, y, x, &errNum) ){ occupiedFlg = 1; } } sp = (int )(viewStr1->dist - WLZ_NINT(viewStr1->minvals.vtZ) - 1); for(; !occupiedFlg && (sp >= 0); sp--){ x = vtx.vtX + s_to_x[sp]; y = vtx.vtY + s_to_y[sp]; z = vtx.vtZ + s_to_z[sp]; if( WlzInsideDomain(obj, z, y, x, &errNum) ){ occupiedFlg = 1; } } /* set the integrated value - only WlzUByte at the moment */ *(gwsp.u_grintptr.ubp) = (WlzUByte )occupiedFlg; gwsp.u_grintptr.ubp++; } /* use integration function */ else { /* set array of pixel values */ for(sp=0; sp < length; sp++){ x = vtx.vtX + s_to_x[sp]; y = vtx.vtY + s_to_y[sp]; z = vtx.vtZ + s_to_z[sp]; WlzGreyValueGet(gVWSp, WLZ_NINT(z), WLZ_NINT(y), WLZ_NINT(x)); switch( srcGType ){ case WLZ_GREY_LONG: pixptr.p.lnp[sp] = gVWSp->gVal[0].lnv; break; case WLZ_GREY_INT: pixptr.p.inp[sp] = gVWSp->gVal[0].inv; break; case WLZ_GREY_SHORT: pixptr.p.shp[sp] = gVWSp->gVal[0].shv; break; case WLZ_GREY_UBYTE: pixptr.p.ubp[sp] = gVWSp->gVal[0].ubv; break; case WLZ_GREY_FLOAT: pixptr.p.flp[sp] = gVWSp->gVal[0].flv; break; case WLZ_GREY_DOUBLE: pixptr.p.dbp[sp] = gVWSp->gVal[0].dbv; break; case WLZ_GREY_RGBA: pixptr.p.rgbp[sp] = gVWSp->gVal[0].rgbv; break; default: errNum = WLZ_ERR_GREY_TYPE; break; } } /* call integration function and seet value */ intFunc(pixptr, length, (int )(viewStr1->dist - WLZ_NINT(viewStr1->minvals.vtZ)), intFuncData, &errNum); } } } (void )WlzEndGreyScan(&iwsp, &gwsp); if(errNum == WLZ_ERR_EOO) /* Reset error from end of intervals */ { errNum = WLZ_ERR_NONE; } /* if no integration function then threshold - binary only */ if( intFunc == NULL ){ pixval.v.ubv = 1; rtnObj = WlzAssignObject(rtnObj, NULL); if((obj1 = WlzThreshold(rtnObj, pixval, WLZ_THRESH_HIGH, &errNum)) != NULL){ WlzFreeObj(rtnObj); values.core = NULL; rtnObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, obj1->domain, values, NULL, NULL, &errNum); WlzFreeObj(obj1); } else { WlzFreeObj(rtnObj); rtnObj = NULL; } } } /* clear space */ if( viewStr1 ){ errNum = WlzFree3DViewStruct(viewStr1); } if( s_to_x ){ AlcFree( s_to_x ); } if( s_to_y ){ AlcFree( s_to_y ); } if( s_to_z ){ AlcFree( s_to_z ); } /* check error and return */ if( dstErr ){ *dstErr = errNum; } return rtnObj; }
/*! * \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); }
/*! * \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; }
/*! * \return New 2D domain object. * \ingroup WlzArithmetic * \brief Computes a new 2D object which shares the domain of the given * object, but which has grey values that are the result of * applying the given function to the grey values of the * given object. * \param sObj Given source domain object with values. * \param fn Scalar function to be applied. * \param dstErr Destination error pointer, may be NULL. */ static WlzObject *WlzScalarFn2D(WlzObject *sObj, WlzFnType fn, WlzErrorNum *dstErr) { WlzGreyType sGType, dGType; WlzPixelV sBgd, dBgd; WlzObjectType dVType; WlzObject *dObj = NULL; WlzValues dVal; WlzIntervalWSpace sIWSp, dIWSp; WlzGreyWSpace sGWSp, dGWSp; WlzErrorNum errNum = WLZ_ERR_NONE; sGType = WlzGreyTypeFromObj(sObj, &errNum); if(errNum == WLZ_ERR_NONE) { dGType = WlzScalarFnPromoteGType(fn, sGType, &errNum); } if(errNum == WLZ_ERR_NONE) { dVType = WlzGreyTableType(WLZ_GREY_TAB_RAGR, dGType, &errNum); } if(errNum == WLZ_ERR_NONE) { sBgd = WlzGetBackground(sObj, &errNum); } if(errNum == WLZ_ERR_NONE) { dBgd = WlzScalarFnPixel(sBgd, fn, &errNum); } if(errNum == WLZ_ERR_NONE) { dVal.v = WlzNewValueTb(sObj, dVType, dBgd, &errNum); } if(errNum == WLZ_ERR_NONE) { dObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, sObj->domain, dVal, NULL, NULL, &errNum); } if(errNum == WLZ_ERR_NONE) { errNum = WlzInitGreyScan(sObj, &sIWSp, &sGWSp); } if(errNum == WLZ_ERR_NONE) { errNum = WlzInitGreyScan(dObj, &dIWSp, &dGWSp); } if(errNum == WLZ_ERR_NONE) { while((errNum == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&sIWSp)) == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&dIWSp)) == WLZ_ERR_NONE)) { int len; WlzGreyP dGP, sGP; len = sIWSp.rgtpos - sIWSp.lftpos + 1; dGP = dGWSp.u_grintptr; sGP = sGWSp.u_grintptr; WlzValueCopyGreyToGrey(dGP, 0, dGType, sGP, 0, sGType, len); WlzScalarFnItv(dGP, dGType, len, fn); } if(errNum == WLZ_ERR_EOO) { errNum = WLZ_ERR_NONE; } } if(dstErr) { *dstErr = errNum; } return(dObj); }
/*! * \return New Gaussian filtered object with new values or NULL on error. * \ingroup WlzValuesFilters * \brief Applies a Gaussian filter to the given input spatial domain * object. Only scalar valued image objects are valid for use * with this function. * \param inObj Input 2 or 3D spatial domain object * which must have values. * \param sigma Gaussian sigma values for each of the * Cartesian directions. * \param order Derivative order for each of the * Cartesian directions, range 0-2, * where 0 implies no derivative. * \param direc Required Cartesian directions, with * zero value indicating that no filtering * is to be applied for a direction. * \param gType Required return object grey type. * Passing in WLZ_GREY_ERROR will * request the given input object's grey * type. * \param pad Type of padding. * \param padVal Padding value, only used when * pad == ALG_PAD_VALUE. * \param dstErr Destination error pointer may be NULL. */ WlzObject *WlzGaussFilter( WlzObject *inObj, WlzDVertex3 sigma, WlzIVertex3 order, WlzIVertex3 direc, WlzGreyType gType, AlgPadType pad, double padVal, WlzErrorNum *dstErr) { int dim = 0; double *cBuf[3] = {NULL}; WlzIVertex3 cBufSz = {0}; WlzObject *rnObj = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; const int maxOrder = 2; const double nSigma = 3.0, sigmaMin = 0.0001; if(inObj == NULL) { errNum = WLZ_ERR_OBJECT_NULL; } else if(inObj->domain.core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } else if(inObj->values.core == NULL) { errNum = WLZ_ERR_VALUES_NULL; } else if((sigma.vtX < sigmaMin) || (sigma.vtY < sigmaMin) || (order.vtX < 0) || (order.vtX > maxOrder) || (order.vtY < 0) || (order.vtY > maxOrder)) { errNum = WLZ_ERR_PARAM_DATA; } else { switch(inObj->type) { case WLZ_2D_DOMAINOBJ: dim = 2; break; case WLZ_3D_DOMAINOBJ: dim = 3; if((sigma.vtZ < sigmaMin) || (order.vtZ < 0) || (order.vtZ > maxOrder)) { errNum = WLZ_ERR_PARAM_DATA; } break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } if((errNum == WLZ_ERR_NONE) && (gType == WLZ_GREY_ERROR)) { gType = WlzGreyTypeFromObj(inObj, &errNum); } if(errNum == WLZ_ERR_NONE) { if(errNum == WLZ_ERR_NONE) { switch(gType) { case WLZ_GREY_INT: /* FALLTHROUGH */ case WLZ_GREY_SHORT: /* FALLTHROUGH */ case WLZ_GREY_UBYTE: /* FALLTHROUGH */ case WLZ_GREY_FLOAT: /* FALLTHROUGH */ case WLZ_GREY_DOUBLE: break; default: errNum = WLZ_ERR_GREY_TYPE; break; } } } if(errNum == WLZ_ERR_NONE) { cBufSz.vtX = (int )floor(nSigma * sigma.vtX); cBufSz.vtY = (int )floor(nSigma * sigma.vtY); if(errNum == WLZ_ERR_NONE) { if(dim == 3) { cBufSz.vtZ = (int )floor(nSigma * sigma.vtZ); } } } if(errNum == WLZ_ERR_NONE) { int cSz; cSz = (cBufSz.vtX + cBufSz.vtY + cBufSz.vtZ + 3) * 2; if((cBuf[0] = (double *)AlcMalloc(sizeof(double) * cSz)) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } cBuf[1] = cBuf[0] + 1 + (2 * cBufSz.vtX); cBuf[2] = cBuf[1] + 1 + (2 * cBufSz.vtY); } if(errNum == WLZ_ERR_NONE) { int idd; for(idd = 0; idd < dim; ++idd) { int n, odr; double *cb; cb = cBuf[idd]; switch(idd) { case 0: n = cBufSz.vtX; odr = order.vtX; break; case 1: n = cBufSz.vtY; odr = order.vtY; break; case 2: n = cBufSz.vtZ; odr = order.vtZ; break; default: break; } /* Set convolution buffers. */ { int i; double g, s, t, nsn, nrm; nrm = 0.0; nsn = nSigma / n; switch(odr) { case 0: for(i = 0; i <= n; ++i) { s = n - i; t = s * nsn; g = exp(-0.5 * t * t); nrm += g; cb[i] = g; } nrm = 1.0 / ((2.0 * nrm) - cb[n]); for(i = 0; i <= n; ++i) { cb[i] *= nrm; } for(i = 1; i <= n; ++i) { cb[n + i] = cb[n - i]; } break; case 1: for(i = 0; i <= n; ++i) { s = n - i; t = s * nsn; g = exp(-0.5 * t * t) * s; nrm += g; cb[i] = g; } nrm = 1.0 / ((2.0 * nrm) - cb[n]); for(i = 0; i <= n; ++i) { cb[i] *= nrm; } for(i = 1; i <= n; ++i) { cb[n + i] = -cb[n - i]; } break; case 2: for(i = 0; i <= n; ++i) { s = n - i; t = s * nsn; g = exp(-0.5 * t * t) * (s * s - nSigma * nSigma); nrm += g; cb[i] = g; } nrm = -1.0 / ((2.0 * nrm) - cb[n]); for(i = 0; i <= n; ++i) { cb[i] *= nrm; } for(i = 1; i <= n; ++i) { cb[n + i] = cb[n - i]; } break; default: break; } #ifdef WLZ_SEPFILTER_DEBUG for(i = 0; i < (2 * n) + 1; ++i) { (void )fprintf(stderr, "%g\n", cb[i]); } (void )fprintf(stderr, "\n"); #endif /* WLZ_SEPFILTER_DEBUG */ } } } if(errNum == WLZ_ERR_NONE) { rnObj = WlzSepFilter(inObj, cBufSz, cBuf, direc, gType, pad, padVal, &errNum); } AlcFree(cBuf[0]); if(errNum != WLZ_ERR_NONE) { WlzFreeObj(rnObj); rnObj = NULL; } if(dstErr) { *dstErr = errNum; } return(rnObj); }
/*! * \ingroup WlzValuesUtils * \brief Convert a RGBA image to a compound object. The RGBA * channels are at array indices 0,1,2,3 respectively * and the sub-object grey types will be WLZ_GREY_UBYTE. * * \return Compound array of rgba values * \param obj Input domain object with value type * WLZ_GREY_RGBA * \param colSpc The colour space. * \param dstErr Destination error ponyer, may be NULL. */ WlzCompoundArray *WlzRGBAToCompound( WlzObject *obj, WlzRGBAColorSpace colSpc, WlzErrorNum *dstErr) { WlzCompoundArray *cobj=NULL; WlzErrorNum errNum=WLZ_ERR_NONE; /* check object type, and value type */ if( obj ){ switch( obj->type ){ case WLZ_2D_DOMAINOBJ: if( obj->domain.core == NULL ){ errNum = WLZ_ERR_DOMAIN_NULL; } else if ( obj->values.core == NULL ){ errNum = WLZ_ERR_VALUES_NULL; } else if( WlzGreyTypeFromObj(obj, &errNum) != WLZ_GREY_RGBA ){ errNum = WLZ_ERR_VALUES_TYPE; } break; case WLZ_3D_DOMAINOBJ: if( obj->domain.core == NULL ){ errNum = WLZ_ERR_DOMAIN_NULL; } else if( obj->domain.p->type != WLZ_PLANEDOMAIN_DOMAIN ){ errNum = WLZ_ERR_DOMAIN_TYPE; } else if ( obj->values.core == NULL ){ errNum = WLZ_ERR_VALUES_NULL; } else if( obj->values.vox->type != WLZ_VOXELVALUETABLE_GREY ){ errNum = WLZ_ERR_VALUES_TYPE; } else if( WlzGreyTypeFromObj(obj, &errNum) != WLZ_GREY_RGBA ){ errNum = WLZ_ERR_VALUES_TYPE; } return WlzRGBAToCompound3D(obj, colSpc, dstErr); case WLZ_TRANS_OBJ: /* not difficult, do it later */ errNum = WLZ_ERR_OBJECT_TYPE; break; case WLZ_COMPOUND_ARR_1: case WLZ_COMPOUND_ARR_2: /* bit recursive this ! */ errNum = WLZ_ERR_OBJECT_TYPE; break; case WLZ_EMPTY_OBJ: return (WlzCompoundArray *) WlzMakeEmpty(dstErr); default: errNum = WLZ_ERR_OBJECT_TYPE; } } else { errNum = WLZ_ERR_OBJECT_NULL; } /* check colour space */ if( errNum == WLZ_ERR_NONE ){ switch( colSpc ){ case WLZ_RGBA_SPACE_RGB: case WLZ_RGBA_SPACE_HSB: case WLZ_RGBA_SPACE_CMY: break; default: errNum = WLZ_ERR_PARAM_DATA; break; } } /* create compound object return */ if( errNum == WLZ_ERR_NONE ){ WlzValues values; WlzObject *objs[4]; WlzObjectType type; WlzPixelV oldBck, newBck; type = WlzGreyTableType( WlzGreyTableTypeToTableType(obj->values.core->type, &errNum), WLZ_GREY_UBYTE, &errNum); oldBck = WlzGetBackground(obj, &errNum); /* red */ newBck.type = WLZ_GREY_UBYTE; newBck.v.ubv = (WlzUByte )WLZ_RGBA_RED_GET(oldBck.v.rgbv); values.v = WlzNewValueTb(obj, type, newBck, &errNum); objs[0] = WlzMakeMain(obj->type, obj->domain, values, NULL, NULL, &errNum); /* green */ newBck.v.ubv = (WlzUByte )WLZ_RGBA_GREEN_GET(oldBck.v.rgbv); values.v = WlzNewValueTb(obj, type, newBck, &errNum); objs[1] = WlzMakeMain(obj->type, obj->domain, values, NULL, NULL, &errNum); /* blue */ newBck.v.ubv = (WlzUByte )WLZ_RGBA_BLUE_GET(oldBck.v.rgbv); values.v = WlzNewValueTb(obj, type, newBck, &errNum); objs[2] = WlzMakeMain(obj->type, obj->domain, values, NULL, NULL, &errNum); /* alpha */ newBck.v.ubv = (WlzUByte )WLZ_RGBA_ALPHA_GET(oldBck.v.rgbv); values.v = WlzNewValueTb(obj, type, newBck, &errNum); objs[3] = WlzMakeMain(obj->type, obj->domain, values, NULL, NULL, &errNum); /* create compound object, object pointers are assigned for mode=3 so no need to free objects */ cobj = WlzMakeCompoundArray(WLZ_COMPOUND_ARR_1, 3, 4, &(objs[0]), obj->type, &errNum); } /* iterate through objects setting values */ if( errNum == WLZ_ERR_NONE ){ WlzIntervalWSpace iwsp0, iwsp[4]; WlzGreyWSpace gwsp0, gwsp[4]; int i, j, k; int a, col[3]; errNum = WlzInitGreyScan(obj, &iwsp0, &gwsp0); for(i=0; i < 4; i++){ errNum = WlzInitGreyScan(cobj->o[i], &(iwsp[i]), &(gwsp[i])); } while((errNum == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&iwsp0)) == WLZ_ERR_NONE)){ for(i=0; i < 4; i++){ errNum = WlzNextGreyInterval(&(iwsp[i])); } switch( colSpc ){ case WLZ_RGBA_SPACE_RGB: for(j=0, k=iwsp0.lftpos; k <= iwsp0.rgtpos; j++, k++, gwsp0.u_grintptr.rgbp++){ *(gwsp[0].u_grintptr.ubp++) = (WlzUByte )WLZ_RGBA_RED_GET(*(gwsp0.u_grintptr.rgbp)); *(gwsp[1].u_grintptr.ubp++) = (WlzUByte )WLZ_RGBA_GREEN_GET(*(gwsp0.u_grintptr.rgbp)); *(gwsp[2].u_grintptr.ubp++) = (WlzUByte )WLZ_RGBA_BLUE_GET(*(gwsp0.u_grintptr.rgbp)); *(gwsp[3].u_grintptr.ubp++) = (WlzUByte )WLZ_RGBA_ALPHA_GET(*(gwsp0.u_grintptr.rgbp)); } break; case WLZ_RGBA_SPACE_HSB: /* each normalised to [0,255] */ for(j=0, k=iwsp0.lftpos; k <= iwsp0.rgtpos; j++, k++, gwsp0.u_grintptr.rgbp++){ col[0] = WLZ_RGBA_RED_GET(*(gwsp0.u_grintptr.rgbp)); col[1] = WLZ_RGBA_GREEN_GET(*(gwsp0.u_grintptr.rgbp)); col[2] = WLZ_RGBA_BLUE_GET(*(gwsp0.u_grintptr.rgbp)); a = WLZ_RGBA_ALPHA_GET(*(gwsp0.u_grintptr.rgbp)); WlzRGBAConvertRGBToHSV_UBYTENormalised(col); *(gwsp[0].u_grintptr.ubp++) = (WlzUByte )(col[0]); *(gwsp[1].u_grintptr.ubp++) = (WlzUByte )(col[1]); *(gwsp[2].u_grintptr.ubp++) = (WlzUByte )(col[2]); *(gwsp[3].u_grintptr.ubp++) = (WlzUByte )a; } break; case WLZ_RGBA_SPACE_CMY: for(j=0, k=iwsp0.lftpos; k <= iwsp0.rgtpos; j++, k++, gwsp0.u_grintptr.rgbp++){ col[0] = WLZ_RGBA_RED_GET(*(gwsp0.u_grintptr.rgbp)); col[1] = WLZ_RGBA_GREEN_GET(*(gwsp0.u_grintptr.rgbp)); col[2] = WLZ_RGBA_BLUE_GET(*(gwsp0.u_grintptr.rgbp)); a = WLZ_RGBA_ALPHA_GET(*(gwsp0.u_grintptr.rgbp)); *(gwsp[0].u_grintptr.ubp++) = (WlzUByte )((col[1] + col[2]) / 2); *(gwsp[1].u_grintptr.ubp++) = (WlzUByte )((col[2] + col[0]) / 2); *(gwsp[2].u_grintptr.ubp++) = (WlzUByte )((col[0] + col[1]) / 2); *(gwsp[3].u_grintptr.ubp++) = (WlzUByte )a; } break; default: errNum = WLZ_ERR_GREY_TYPE; break; } } if( errNum == WLZ_ERR_EOO ){ errNum = WLZ_ERR_NONE; } } if( dstErr ){ *dstErr = errNum; } return cobj; }
int main(int argc, char *argv[]) { int option, nReg = 0, tNReg = 0, ok = 1, usage = 0, verbose = 0, threshSet = 0, centreSet = 0; double minArea = 2; char *inExt, *dbgExt, *inDir, *dbgDir, *inFile, *dbgFile, *inPath = NULL, *dbgPath = NULL, *outFile = NULL; WlzRadDistVal distSort = WLZ_RADDISTVAL_AREA; WlzRadDistRec *distData = NULL; WlzPixelV thrVal; WlzDVertex2 centre; WlzCompThreshType thrMtd = WLZ_COMPTHRESH_OTSU; WlzThresholdType thrMod = WLZ_THRESH_HIGH; WlzEffFormat inFmt = WLZEFF_FORMAT_NONE, dbgFmt = WLZEFF_FORMAT_NONE; WlzObject *inObj = NULL, *disObj = NULL, *segObj = NULL; WlzGreyValueWSpace *disGVWSp = NULL; WlzObject **regObjs = NULL; FILE *fP = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; const int maxObj = 1000000; char pathBuf[FILENAME_MAX]; const double eps = 1.0e-06; const char *errMsg; static char optList[] = "hvAGDHELR:c:d:n:o:t:", defFile[] = "-"; thrVal.type = WLZ_GREY_DOUBLE; thrVal.v.dbv = 0.0; outFile = defFile; while((usage == 0) && ok && ((option = getopt(argc, argv, optList)) != -1)) { switch(option) { case 'A': distSort = WLZ_RADDISTVAL_AREA; break; case 'D': distSort = WLZ_RADDISTVAL_DIST; break; case 'G': distSort = WLZ_RADDISTVAL_ANGLE; break; case 'H': thrMod = WLZ_THRESH_HIGH; break; case 'E': thrMod = WLZ_THRESH_EQUAL; break; case 'L': thrMod = WLZ_THRESH_LOW; break; case 'R': distSort = WLZ_RADDISTVAL_RADIUS; break; case 'h': usage = 1; break; case 'v': verbose = 1; break; case 'c': centreSet = 1; if(sscanf(optarg, "%lg,%lg", &(centre.vtX), &(centre.vtY)) != 2) { usage = 1; } break; case 'd': dbgPath = optarg; break; case 'o': outFile = optarg; break; case 'n': if(sscanf(optarg, "%lg", &minArea) != 1) { usage = 1; } break; case 't': threshSet = 1; if(sscanf(optarg, "%lg", &(thrVal.v.dbv)) != 1) { usage = 1; } break; default: usage = 1; break; } } ok = !usage; if(ok) { if((optind + 1) != argc) { usage = 1; ok = 0; } else { inPath = *(argv + optind); } } if(ok && verbose) { (void )fprintf(stderr, "inPath = %s\n", inPath); } /* Parse input file path into path + name + ext. */ if(ok) { ok = (usage = WlzRadDistParsePath(inPath, &inDir, &inFile, &inExt, &inFmt)) == 0; } if(ok && verbose) { (void )fprintf(stderr, "inDir = %s\n", inDir); (void )fprintf(stderr, "inFile = %s\n", inFile); (void )fprintf(stderr, "inExt = %s\n", (inExt)? inExt: "(null)"); (void )fprintf(stderr, "inFmt = %s\n", WlzEffStringFromFormat(inFmt, NULL)); } /* Read image. */ if(ok) { errNum = WLZ_ERR_READ_EOF; if(inExt) { (void )sprintf(pathBuf, "%s/%s.%s", inDir, inFile, inExt); } else { (void )sprintf(pathBuf, "%s/%s", inDir, inFile); } if(((inObj = WlzAssignObject(WlzEffReadObj(NULL, pathBuf, inFmt, 0, 0, 0, &errNum), NULL)) == NULL) || (inObj->type != WLZ_2D_DOMAINOBJ)) { ok = 0; (void )WlzStringFromErrorNum(errNum, &errMsg); (void )fprintf(stderr, "%s: Failed to read 2D image object from file %s (%s)\n", *argv, pathBuf, errMsg); } } if(ok && verbose) { (void )fprintf(stderr, "read input image ok.\n"); } /* Convert to grey if needed, normalise 0 - 255 if needed and compute * threshold value unless already known. */ if(ok) { if(WlzGreyTypeFromObj(inObj, NULL) == WLZ_GREY_RGBA) { WlzObject *ppObj; ppObj = WlzAssignObject( WlzRGBAToModulus(inObj, &errNum), NULL); if(errNum == WLZ_ERR_NONE) { (void )WlzFreeObj(inObj); inObj = ppObj; } } if(threshSet == 0) { WlzObject *hObj = NULL; errNum = WlzGreyNormalise(inObj, 1); if(errNum == WLZ_ERR_NONE) { hObj = WlzHistogramObj(inObj, 256, 0.0, 1.0, &errNum); } if(errNum == WLZ_ERR_NONE) { threshSet = 1; errNum = WlzCompThreshold(&thrVal.v.dbv, hObj, thrMtd, 0); } (void )WlzFreeObj(hObj); } if(errNum != WLZ_ERR_NONE) { ok = 0; (void )WlzStringFromErrorNum(errNum, &errMsg); (void )fprintf(stderr, "%s: failed to normalise object (%s)\n", *argv, errMsg); } } /* Segment the object. */ if(ok) { if(inObj->values.core == NULL) { segObj = WlzAssignObject(inObj, NULL); } else { segObj = WlzAssignObject( WlzThreshold(inObj, thrVal, thrMod, &errNum), NULL); if(errNum != WLZ_ERR_NONE) { ok = 0; (void )WlzStringFromErrorNum(errNum, &errMsg); (void )fprintf(stderr, "%s: failed to segment image (%s)\n", *argv, errMsg); } } } /* Compute object with the same domain as the input object but in which * the values are the minimum distance from an edge. */ if(ok) { WlzObject *bObj = NULL; bObj = WlzBoundaryDomain(inObj, &errNum); if(errNum == WLZ_ERR_NONE) { disObj = WlzAssignObject( WlzDistanceTransform(inObj, bObj, WLZ_OCTAGONAL_DISTANCE, 0.0, 0.0, &errNum), NULL); } if(errNum == WLZ_ERR_NONE) { disGVWSp = WlzGreyValueMakeWSp(disObj, &errNum); } if(errNum != WLZ_ERR_NONE) { ok = 0; (void )WlzStringFromErrorNum(errNum, &errMsg); (void )fprintf(stderr, "%s: failed to compute distance object (%s)\n", *argv, errMsg); } (void )WlzFreeObj(bObj); } /* Output the debug image if required. */ if(ok && dbgPath) { WlzObject *dbgObj; dbgObj = WlzAssignObject(WlzCopyObject(inObj, &errNum), NULL); if(errNum == WLZ_ERR_NONE) { WlzPixelV iMin, iMax, oMin, oMax; if(dbgObj->values.core == NULL) { WlzValues tmpVal; oMax.type = WLZ_GREY_UBYTE; oMax.v.ubv = 255; tmpVal.v = WlzNewValueTb(dbgObj, WlzGreyTableType(WLZ_GREY_TAB_RAGR, WLZ_GREY_UBYTE, NULL), oMax, &errNum); if(errNum == WLZ_ERR_NONE) { dbgObj->values = WlzAssignValues(tmpVal, NULL); } } else { WlzObject *tmpObj = NULL; oMin.type = WLZ_GREY_UBYTE; oMin.v.ubv = 0; oMax.type = WLZ_GREY_UBYTE; oMax.v.ubv = 200; errNum = WlzGreyRange(dbgObj, &iMin, &iMax); if(errNum == WLZ_ERR_NONE) { errNum = WlzGreySetRange(dbgObj, iMin, iMax, oMin, oMax, 0); } if(errNum == WLZ_ERR_NONE) { tmpObj = WlzMakeMain(inObj->type, segObj->domain, dbgObj->values, NULL, NULL, &errNum); } if(errNum == WLZ_ERR_NONE) { oMax.v.ubv = 255; errNum = WlzGreySetValue(tmpObj, oMax); } (void )WlzFreeObj(tmpObj); if(errNum == WLZ_ERR_NONE) { tmpObj = WlzConvertPix(dbgObj, WLZ_GREY_UBYTE, &errNum); (void )WlzFreeObj(dbgObj); dbgObj = WlzAssignObject(tmpObj, NULL); } } } if(errNum == WLZ_ERR_NONE) { (void )WlzRadDistParsePath(dbgPath, &dbgDir, &dbgFile, &dbgExt, &dbgFmt); if(dbgExt) { (void )sprintf(pathBuf, "%s/%s.%s", dbgDir, dbgFile, dbgExt); } else { (void )sprintf(pathBuf, "%s/%s", dbgDir, dbgFile); } errNum = WlzEffWriteObj(NULL, pathBuf, dbgObj, dbgFmt); } (void )WlzFreeObj(dbgObj); if(errNum != WLZ_ERR_NONE) { ok = 0; (void )WlzStringFromErrorNum(errNum, &errMsg); (void )fprintf(stderr, "%s: failed to output the debug image (%s)\n", *argv, errMsg); } } /* Label the segmented object. */ if(ok) { errNum = WlzLabel(segObj, &nReg, ®Objs, maxObj, 0, WLZ_8_CONNECTED); if(errNum != WLZ_ERR_NONE) { ok = 0; errNum = WLZ_ERR_MEM_ALLOC; (void )WlzStringFromErrorNum(errNum, &errMsg); (void )fprintf(stderr, "%s: failed to split into components (%s)\n", *argv, errMsg); } if(ok && verbose) { (void )fprintf(stderr, "nReg = %d\n", nReg); } } /* Compute centre of mass if not known. */ if(ok) { if(centreSet == 0) { centre = WlzCentreOfMass2D(inObj, 1, NULL, &errNum); if(errNum != WLZ_ERR_NONE) { ok = 0; (void )WlzStringFromErrorNum(errNum, &errMsg); (void )fprintf(stderr, "%s: failed to compute centre of mass (%s)\n", *argv, errMsg); } } if(ok && verbose) { (void )fprintf(stderr, "centre = %lg,%lg\n", centre.vtX, centre.vtY); } } /* Allocate a radial distribution table. */ if(ok) { if((distData = (WlzRadDistRec *) AlcCalloc(nReg, sizeof(WlzRadDistRec))) == NULL) { ok = 0; errNum = WLZ_ERR_MEM_ALLOC; (void )WlzStringFromErrorNum(errNum, &errMsg); (void )fprintf(stderr, "%s: failed to allocate result lable (%s)\n", *argv, errMsg); } } /* Compute the redial distribution data. */ if(ok) { int idR = 0, idS = 0; while((errNum == WLZ_ERR_NONE) && (idR < nReg)) { double mass; WlzDVertex2 com; com = WlzCentreOfMass2D(regObjs[idR], 1, &mass, NULL); if(mass > minArea - eps) { WlzGreyValueGet(disGVWSp, 0.0, com.vtY, com.vtX); distData[idS].pos = com; distData[idS].area = mass; WLZ_VTX_2_SUB(com, centre, com); distData[idS].radius = WLZ_VTX_2_LENGTH(com); distData[idS].angle = ALG_M_PI + atan2(com.vtY, com.vtX); switch(disGVWSp->gType) { case WLZ_GREY_LONG: distData[idS].dist = *(disGVWSp->gPtr[0].lnp); break; case WLZ_GREY_INT: distData[idS].dist = *(disGVWSp->gPtr[0].inp); break; case WLZ_GREY_SHORT: distData[idS].dist = *(disGVWSp->gPtr[0].shp); break; case WLZ_GREY_UBYTE: distData[idS].dist = *(disGVWSp->gPtr[0].ubp); break; case WLZ_GREY_FLOAT: distData[idS].dist = *(disGVWSp->gPtr[0].flp); break; case WLZ_GREY_DOUBLE: distData[idS].dist = *(disGVWSp->gPtr[0].dbp); break; default: distData[idS].dist = 0.0; break; } ++idS; } ++idR; } tNReg = idS; switch(distSort) { case WLZ_RADDISTVAL_AREA: (void )qsort(distData, tNReg, sizeof(WlzRadDistRec), WlzRadDistRecSortArea); break; case WLZ_RADDISTVAL_ANGLE: (void )qsort(distData, tNReg, sizeof(WlzRadDistRec), WlzRadDistRecSortAngle); break; case WLZ_RADDISTVAL_RADIUS: (void )qsort(distData, tNReg, sizeof(WlzRadDistRec), WlzRadDistRecSortRadius); break; case WLZ_RADDISTVAL_DIST: (void )qsort(distData, tNReg, sizeof(WlzRadDistRec), WlzRadDistRecSortDist); break; } } /* Output the sorted radial distribution table. */ if(ok) { if(((fP = strcmp(outFile, "-")? fopen(outFile, "w"): stdout)) == NULL) { ok = 0; (void )fprintf(stderr, "%s: failed to open output file %s\n", *argv, outFile); } } if(ok) { int idR; for(idR = 0; idR < tNReg; ++idR) { double a; a = (distData[idR].angle > 0.0)? 0 + (180 * distData[idR].angle / ALG_M_PI): 360 + (180 * distData[idR].angle / ALG_M_PI); (void )fprintf(fP, "%g %g %g %g,%g %g\n", a, distData[idR].radius, distData[idR].area, distData[idR].pos.vtX, distData[idR].pos.vtY, distData[idR].dist); } } if(strcmp(outFile, "-")) { (void )fclose(fP); } /* Tidy up. */ AlcFree(distData); WlzGreyValueFreeWSp(disGVWSp); (void )WlzFreeObj(inObj); (void )WlzFreeObj(disObj); (void )WlzFreeObj(segObj); if(regObjs) { int idR; for(idR = 0; idR < nReg; ++idR) { (void )WlzFreeObj(regObjs[idR]); } AlcFree(regObjs); } if(usage) { (void )fprintf(stderr, "Usage: %s [-h] [-v] [-A] [-D] [-G] [-H] [-E] [-L] [-R]\n" "\t\t[-c #,#] [-d <debug image>] [-n #] [-o <out file>]\n" "\t\t[-t #] [<input image>]\n" "Segments the given object using a threshold value and outputs the \n" "radial distribution of the thresholded components.\n" "Version: %s\n" "Options:\n" " -h Help - prints this usage masseage.\n" " -v Verbose output.\n" " -A Sort output by area (default).\n" " -D Sort output by distance from boundary.\n" " -G Sort output by angle.\n" " -H Threshold high, use pixels at or above threshold (default).\n" " -E Threshold equal, use pixels at threshold.\n" " -L Threshold low, use pixels below threshold.\n" " -R Sort output by radial distance from centre.\n" " -c Centre (default is image centre).\n" " -d Debug image.\n" " -n Minimum area (default %g).\n" " -t Threshold value (default is to compute using Otsu's method).\n" "By default the input image object is read from the standard input and\n" "the radial distribution is written to the standard output.\n" "The image formats understood include wlz, jpg and tif.\n" "The output format is:\n" " <angle> <dist from centre> <area> <x pos>,<y pos> <dist form boundary>\n" "Example:\n" " %s -o out.txt -d debug.jpg in.tif\n" "The input image is read from in.tif, a debug image showing the\n" "segmented regions is written to debug.jpg and the radial distribution\n" "statistics are written to the file out.txt. With the output in\n" "out.txt, the following R code would plot the data as a set of circles\n" "with radius proportional to the square root of the component area:\n" " data <- read.table(\"out.txt\")\n" " attach(data)\n" " symbols(x=data$V1, y=data$V2, circles=sqrt(data$V3))\n", argv[0], WlzVersion(), minArea, argv[0]); } return(!ok); }
/*! * \ingroup WlzValuesUtils * \brief Calculate the modulus of the rgb values and return in an image of grey type WLZ_GREY_SHORT * * \return Grey-level object of modulus values * \param obj Input rgba object * \param dstErr error return * \par Source: * WlzRGBAConvert.c */ WlzObject *WlzRGBAToModulus( WlzObject *obj, WlzErrorNum *dstErr) { WlzObject *rtnObj=NULL; WlzErrorNum errNum=WLZ_ERR_NONE; /* check object type, and value type */ if( obj ){ switch( obj->type ){ case WLZ_2D_DOMAINOBJ: if( obj->domain.core == NULL ){ errNum = WLZ_ERR_DOMAIN_NULL; } else if ( obj->values.core == NULL ){ errNum = WLZ_ERR_VALUES_NULL; } else if( WlzGreyTypeFromObj(obj, &errNum) != WLZ_GREY_RGBA ){ errNum = WLZ_ERR_VALUES_TYPE; } break; case WLZ_3D_DOMAINOBJ: if( obj->domain.core == NULL ){ errNum = WLZ_ERR_DOMAIN_NULL; } else if( obj->domain.p->type != WLZ_PLANEDOMAIN_DOMAIN ){ errNum = WLZ_ERR_DOMAIN_TYPE; } else if ( obj->values.core == NULL ){ errNum = WLZ_ERR_VALUES_NULL; } else if( obj->values.vox->type != WLZ_VOXELVALUETABLE_GREY ){ errNum = WLZ_ERR_VALUES_TYPE; } else if( WlzGreyTypeFromObj(obj, &errNum) != WLZ_GREY_RGBA ){ errNum = WLZ_ERR_VALUES_TYPE; } return WlzRGBAToModulus3D(obj, dstErr); case WLZ_TRANS_OBJ: /* not difficult, do it later */ errNum = WLZ_ERR_OBJECT_TYPE; break; case WLZ_COMPOUND_ARR_1: case WLZ_COMPOUND_ARR_2: /* bit recursive this ! */ errNum = WLZ_ERR_OBJECT_TYPE; break; case WLZ_EMPTY_OBJ: return WlzMakeEmpty(dstErr); default: errNum = WLZ_ERR_OBJECT_TYPE; } } else { errNum = WLZ_ERR_OBJECT_NULL; } /* create object return */ if( errNum == WLZ_ERR_NONE ){ WlzValues values; WlzObjectType type; WlzPixelV oldBck, newBck; type = WlzGreyTableType( WlzGreyTableTypeToTableType(obj->values.core->type, &errNum), WLZ_GREY_SHORT, &errNum); oldBck = WlzGetBackground(obj, &errNum); newBck.type = WLZ_GREY_SHORT; newBck.v.shv = (short )WLZ_RGBA_MODULUS(oldBck.v.rgbv); /* make values table and return object */ values.v = WlzNewValueTb(obj, type, newBck, &errNum); rtnObj = WlzMakeMain(obj->type, obj->domain, values, NULL, NULL, &errNum); } /* iterate through objects setting values */ if( errNum == WLZ_ERR_NONE ){ WlzIntervalWSpace iwsp0, iwsp1; WlzGreyWSpace gwsp0, gwsp1; int j, k; errNum = WlzInitGreyScan(obj, &iwsp0, &gwsp0); errNum = WlzInitGreyScan(rtnObj, &iwsp1, &gwsp1); while((errNum == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&iwsp0)) == WLZ_ERR_NONE)){ errNum = WlzNextGreyInterval(&iwsp1); for(j=0, k=iwsp0.lftpos; k <= iwsp0.rgtpos; j++, k++, gwsp0.u_grintptr.rgbp++){ *(gwsp1.u_grintptr.shp++) = (short ) WLZ_RGBA_MODULUS(*(gwsp0.u_grintptr.rgbp)); } } if( errNum == WLZ_ERR_EOO ){ errNum = WLZ_ERR_NONE; } } if( dstErr ){ *dstErr = errNum; } return rtnObj; }
WlzObject *WlzRGBAToChannel( WlzObject *obj, WlzRGBAColorChannel chan, WlzErrorNum *dstErr) { WlzObject *rtnObj=NULL; WlzValues values; WlzObjectType type; WlzPixelV pixVal, oldBck, newBck; WlzErrorNum errNum=WLZ_ERR_NONE; /* check object and channel */ if( obj ){ switch( obj->type ){ case WLZ_2D_DOMAINOBJ: if( obj->domain.core == NULL ){ errNum = WLZ_ERR_DOMAIN_NULL; } else if ( obj->values.core == NULL ){ errNum = WLZ_ERR_VALUES_NULL; } else if( WlzGreyTypeFromObj(obj, &errNum) != WLZ_GREY_RGBA ){ errNum = WLZ_ERR_VALUES_TYPE; } break; case WLZ_3D_DOMAINOBJ: if( obj->domain.core == NULL ){ errNum = WLZ_ERR_DOMAIN_NULL; } else if( obj->domain.p->type != WLZ_PLANEDOMAIN_DOMAIN ){ errNum = WLZ_ERR_DOMAIN_TYPE; } else if ( obj->values.core == NULL ){ errNum = WLZ_ERR_VALUES_NULL; } else if( obj->values.vox->type != WLZ_VOXELVALUETABLE_GREY ){ errNum = WLZ_ERR_VALUES_TYPE; } else if( WlzGreyTypeFromObj(obj, &errNum) != WLZ_GREY_RGBA ){ errNum = WLZ_ERR_VALUES_TYPE; } return WlzRGBAToChannel3D(obj, chan, dstErr); case WLZ_TRANS_OBJ: /* not difficult, do it later */ errNum = WLZ_ERR_OBJECT_TYPE; break; case WLZ_COMPOUND_ARR_1: case WLZ_COMPOUND_ARR_2: /* bit recursive this ! */ errNum = WLZ_ERR_OBJECT_TYPE; break; case WLZ_EMPTY_OBJ: return WlzMakeEmpty(dstErr); default: errNum = WLZ_ERR_OBJECT_TYPE; } } else { errNum = WLZ_ERR_OBJECT_NULL; } if( errNum == WLZ_ERR_NONE ){ switch( chan ){ case WLZ_RGBA_CHANNEL_RED: case WLZ_RGBA_CHANNEL_GREEN: case WLZ_RGBA_CHANNEL_BLUE: case WLZ_RGBA_CHANNEL_HUE: case WLZ_RGBA_CHANNEL_SATURATION: case WLZ_RGBA_CHANNEL_BRIGHTNESS: case WLZ_RGBA_CHANNEL_CYAN: case WLZ_RGBA_CHANNEL_MAGENTA: case WLZ_RGBA_CHANNEL_YELLOW: break; default: errNum = WLZ_ERR_PARAM_DATA; break; } } /* now extract data */ if( errNum == WLZ_ERR_NONE ){ type = WlzGreyTableType( WlzGreyTableTypeToTableType(obj->values.core->type, &errNum), WLZ_GREY_UBYTE, &errNum); oldBck = WlzGetBackground(obj, &errNum); newBck.type = WLZ_GREY_UBYTE; newBck.v.ubv = (WlzUByte )WlzRGBAPixelValue(oldBck, chan, &errNum); } /* make values table and return object */ if( errNum == WLZ_ERR_NONE ){ values.v = WlzNewValueTb(obj, type, newBck, &errNum); rtnObj = WlzMakeMain(obj->type, obj->domain, values, NULL, NULL, &errNum); } /* iterate through objects setting values */ if( errNum == WLZ_ERR_NONE ){ WlzIntervalWSpace iwsp0, iwsp1; WlzGreyWSpace gwsp0, gwsp1; int j, k; errNum = WlzInitGreyScan(obj, &iwsp0, &gwsp0); errNum = WlzInitGreyScan(rtnObj, &iwsp1, &gwsp1); pixVal.type = WLZ_GREY_RGBA; while((errNum == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&iwsp0)) == WLZ_ERR_NONE)){ errNum = WlzNextGreyInterval(&iwsp1); for(j=0, k=iwsp0.lftpos; k <= iwsp0.rgtpos; j++, k++, gwsp0.u_grintptr.rgbp++){ pixVal.v.rgbv = (*(gwsp0.u_grintptr.rgbp)); *(gwsp1.u_grintptr.ubp++) = (WlzUByte ) WlzRGBAPixelValue(pixVal, chan, &errNum); } } if( errNum == WLZ_ERR_EOO ){ errNum = WLZ_ERR_NONE; } } if( dstErr ){ *dstErr = errNum; } return rtnObj; }
int main(int argc, char **argv) { int idx, option, noiseFlg = 0, ok = 1, usage = 0; double noiseMu = 0.0, noiseSigma = 0.0; WlzIBox3 cutBox, cutSet; WlzErrorNum errNum = WLZ_ERR_NONE; WlzGreyType dstGreyType = WLZ_GREY_ERROR; FILE *fP = NULL; WlzObject *inObj = NULL, *outObj = NULL; char *outObjFileStr, *inObjFileStr; int cutVal[2]; char *cutStr[2]; const char *errMsg; static char optList[] = "iNsufdM:S:o:x:y:z:h", outObjFileStrDef[] = "-", inObjFileStrDef[] = "-"; opterr = 0; cutSet.xMin = 0; cutSet.xMax = 0; cutSet.yMin = 0; cutSet.yMax = 0; cutSet.zMin = 0; cutSet.zMax = 0; outObjFileStr = outObjFileStrDef; inObjFileStr = inObjFileStrDef; while(ok && ((option = getopt(argc, argv, optList)) != -1)) { switch(option) { case 'i': dstGreyType = WLZ_GREY_INT; break; case 's': dstGreyType = WLZ_GREY_SHORT; break; case 'u': dstGreyType = WLZ_GREY_UBYTE; break; case 'f': dstGreyType = WLZ_GREY_FLOAT; break; case 'd': dstGreyType = WLZ_GREY_DOUBLE; break; case 'N': noiseFlg = 1; break; case 'M': if(sscanf(optarg, "%lg", &noiseMu) != 1) { usage = 1; ok = 0; } break; case 'S': if(sscanf(optarg, "%lg", &noiseSigma) != 1) { usage = 1; ok = 0; } break; case 'o': outObjFileStr = optarg; break; case 'x': case 'y': case 'z': if(optarg) { while(*optarg && isspace(*optarg)) { ++optarg; } if(*optarg == ',') { cutStr[0] = NULL; cutStr[1] = strtok(optarg, ","); } else { cutStr[0] = strtok(optarg, ","); cutStr[1] = strtok(NULL, ","); } if((cutStr[0] == NULL) && (cutStr[1] == NULL)) { usage = 1; ok = 0; } else { idx = 0; while(ok && (idx < 2)) { if(cutStr[idx] && (sscanf(cutStr[idx], "%d", cutVal + idx) != 1)) { usage = 1; ok = 0; } ++idx; } } } if(ok) { switch(option) { case 'x': if(cutStr[0]) { cutSet.xMin = 1; cutBox.xMin = cutVal[0]; } if(cutStr[1]) { cutSet.xMax = 1; cutBox.xMax = cutVal[1]; } break; case 'y': if(cutStr[0]) { cutSet.yMin = 1; cutBox.yMin = cutVal[0]; } if(cutStr[1]) { cutSet.yMax = 1; cutBox.yMax = cutVal[1]; } break; case 'z': if(cutStr[0]) { cutSet.zMin = 1; cutBox.zMin = cutVal[0]; } if(cutStr[1]) { cutSet.zMax = 1; cutBox.zMax = cutVal[1]; } break; } } break; case 'h': default: usage = 1; ok = 0; break; } } if((inObjFileStr == NULL) || (*inObjFileStr == '\0') || (outObjFileStr == NULL) || (*outObjFileStr == '\0')) { ok = 0; usage = 1; } if(ok && (optind < argc)) { if((optind + 1) != argc) { usage = 1; ok = 0; } else { inObjFileStr = *(argv + optind); } } if(ok) { errNum = WLZ_ERR_READ_EOF; if((inObjFileStr == NULL) || (*inObjFileStr == '\0') || ((fP = (strcmp(inObjFileStr, "-")? fopen(inObjFileStr, "r"): stdin)) == NULL) || ((inObj = WlzReadObj(fP, &errNum)) == NULL) || (errNum != WLZ_ERR_NONE)) { ok = 0; (void )WlzStringFromErrorNum(errNum, &errMsg); (void )fprintf(stderr, "%s: failed to read object from file %s (%s).\n", *argv, inObjFileStr, errMsg); } if(fP && strcmp(inObjFileStr, "-")) { fclose(fP); } } if(ok) { switch(inObj->type) { case WLZ_2D_DOMAINOBJ: if(cutSet.xMin == 0) { cutBox.xMin = inObj->domain.i->kol1; } if(cutSet.xMax == 0) { cutBox.xMax = inObj->domain.i->lastkl; } if(cutSet.yMin == 0) { cutBox.yMin = inObj->domain.i->line1; } if(cutSet.yMax == 0) { cutBox.yMax = inObj->domain.i->lastln; } cutBox.zMin = 0; cutBox.zMax = 0; break; case WLZ_3D_DOMAINOBJ: if(cutSet.xMin == 0) { cutBox.xMin = inObj->domain.p->kol1; } if(cutSet.xMax == 0) { cutBox.xMax = inObj->domain.p->lastkl; } if(cutSet.yMin == 0) { cutBox.yMin = inObj->domain.p->line1; } if(cutSet.yMax == 0) { cutBox.yMax = inObj->domain.p->lastln; } if(cutSet.zMin == 0) { cutBox.zMin = inObj->domain.p->plane1; } if(cutSet.zMax == 0) { cutBox.zMax = inObj->domain.p->lastpl; } break; default: ok = 0; errMsg = WlzStringFromObjType(inObj, NULL); (void )fprintf(stderr, "%s: invalid object type %s.\n", *argv, errMsg? errMsg: "unknown"); } } if(ok) { if(inObj->domain.core == NULL) { ok = 0; (void )fprintf(stderr, "%s: invalid object, null domain\n", *argv); } } if(ok) { if(dstGreyType == WLZ_GREY_ERROR) { if(inObj->values.core == NULL) { dstGreyType = WLZ_GREY_UBYTE; } else { dstGreyType = WlzGreyTypeFromObj(inObj, NULL); } } if(((outObj = WlzCutObjToBox3D(inObj, cutBox, dstGreyType, noiseFlg, noiseMu, noiseSigma, &errNum)) == NULL) || (errNum != WLZ_ERR_NONE)) { ok = 0; (void )WlzStringFromErrorNum(errNum, &errMsg); (void )fprintf(stderr, "%s: failed to cut object (%s).\n", *argv, errMsg); } } 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 cut object (%s).\n", *argv, errMsg); } if(fP && strcmp(outObjFileStr, "-")) { fclose(fP); } } (void )WlzFreeObj(inObj); (void )WlzFreeObj(outObj); if(usage) { (void )fprintf(stderr, "Usage: %s%s%s%sExample: %s%s", *argv, " [-dfhiNsu] [-o<out object>]\n" " [-M <mean>] [-S <std dev>]\n" " [-x<x min>,<x max>] [-y<y min>,<y max>] [-z<z min>,<z max>]\n" " [<in object>]\n" "Cuts a Woolz object using specified cut box.\n" "Version: ", WlzVersion(), "\n" "Options:\n" " -d Double output values.\n" " -f Float output values.\n" " -h Help, prints this usage message.\n" " -i Int output values.\n" " -N Use gausian noise for background.\n" " -s Short output values.\n" " -u Unsigned byte output values.\n" " -M Mean of gaussian noise.\n" " -o Output object file name.\n" " -S Standard deviation of gaussian noise.\n" " -x Column cut box limits.\n" " -y Line cut box limits.\n" " -z Plane cut box limits.\n" "All cut limits default to the input objects domain limits.\n" "Objects are read from stdin and written to stdout unless the filenames\n" "are given.\n", *argv, " -i -o cut.wlz -x 100,800 -y ,800 myobj.wlz\n" "The input Woolz object is read from myobj.wlz, cut and written\n" "to cut.wlz, with int values.\n"); } return(!ok); }
int main(int argc, char **argv) { int idx, option, dither = 0, overwrite = 1, ok = 1, usage = 0; WlzImArNorm norm = WLZ_IMARNORM_NONE; WlzErrorNum errNum = WLZ_ERR_NONE; FILE *fP = NULL; WlzObject *outObj = NULL; WlzObject *inObj[2]; WlzBinaryOperatorType operator = WLZ_BO_ADD; char *outObjFileStr; char *inObjFileStr[2]; WlzPixelV gMin[3], gMax[3]; const char *errMsg; static char optList[] = "O:o:ab:dgilmsnNh", outObjFileStrDef[] = "-", inObjFileStrDef[] = "-"; opterr = 0; inObj[0] = NULL; inObj[1] = NULL; outObjFileStr = outObjFileStrDef; inObjFileStr[0] = inObjFileStrDef; inObjFileStr[1] = inObjFileStrDef; while(ok && ((option = getopt(argc, argv, optList)) != -1)) { switch(option) { case 'O': if((sscanf(optarg, "%d", &overwrite) != 1) || (overwrite < 0) || (overwrite > 2)) { usage = 1; ok = 0; } break; case 'o': outObjFileStr = optarg; break; case 'a': operator = WLZ_BO_ADD; break; case 'b': operator = atoi(optarg); switch( operator ){ case WLZ_BO_ADD: case WLZ_BO_SUBTRACT: case WLZ_BO_MULTIPLY: case WLZ_BO_DIVIDE: case WLZ_BO_MODULUS: case WLZ_BO_EQ: case WLZ_BO_NE: case WLZ_BO_GT: case WLZ_BO_GE: case WLZ_BO_LT: case WLZ_BO_LE: case WLZ_BO_AND: case WLZ_BO_OR: case WLZ_BO_XOR: case WLZ_BO_MAX: case WLZ_BO_MIN: case WLZ_BO_MAGNITUDE: break; default: usage = 1; ok = 0; break; } break; case 'd': operator = WLZ_BO_DIVIDE; break; case 'g': operator = WLZ_BO_MAGNITUDE; break; case 'l': operator = WLZ_BO_MODULUS; break; case 'm': operator = WLZ_BO_MULTIPLY; break; case 's': operator = WLZ_BO_SUBTRACT; break; case 'n': norm = WLZ_IMARNORM_INPUT; break; case 'N': norm = WLZ_IMARNORM_256; break; case 'i': dither = 1; break; case 'h': default: usage = 1; ok = 0; break; } } if((inObjFileStr[0] == NULL) || (*inObjFileStr[0] == '\0') || (inObjFileStr[1] == NULL) || (*inObjFileStr[1] == '\0') || (outObjFileStr == NULL) || (*outObjFileStr == '\0')) { ok = 0; usage = 1; } if(ok && (optind < argc)) { idx = 0; while((idx < 2) && (optind < argc)) { inObjFileStr[idx] = *(argv + optind); ++optind; ++idx; } } if(ok && (optind != argc)) { usage = 1; ok = 0; } if(ok) { idx = 0; while((errNum == WLZ_ERR_NONE) && (idx < 2)) { errNum = WLZ_ERR_READ_EOF; if((inObjFileStr[idx] == NULL) || (*inObjFileStr[idx] == '\0') || ((fP = (strcmp(inObjFileStr[idx], "-")? fopen(inObjFileStr[idx], "r"): stdin)) == NULL) || ((inObj[idx]= WlzAssignObject(WlzReadObj(fP, &errNum), NULL)) == NULL)) { ok = 0; (void )WlzStringFromErrorNum(errNum, &errMsg); (void )fprintf(stderr, "%s: failed to read object %d from file %s (%s)\n", *argv, idx, inObjFileStr[idx], errMsg); } if(fP && strcmp(inObjFileStr[idx], "-")) { fclose(fP); } ++idx; } } if(ok) { idx = 0; while((errNum == WLZ_ERR_NONE) && (idx < 2)) { if((inObj[idx]->type != WLZ_2D_DOMAINOBJ) && (inObj[idx]->type != WLZ_3D_DOMAINOBJ)) { ok = 0; (void )fprintf(stderr, "%s: input object %d is not a domain object\n", *argv, idx); } ++idx; } } if(ok && (norm == WLZ_IMARNORM_INPUT)) { if(((errNum = WlzGreyRange(inObj[0], gMin, gMax)) != WLZ_ERR_NONE) || ((errNum = WlzGreyRange(inObj[1], gMin + 1, gMax + 1)) != WLZ_ERR_NONE)) { ok = 0; (void )WlzStringFromErrorNum(errNum, &errMsg); (void )fprintf(stderr, "%s: failed to find input objects grey range (%s)\n", *argv, errMsg); } } if(ok) { if( WlzGreyTypeFromObj(inObj[0], &errNum) == WLZ_GREY_RGBA ){ if((outObj = WlzRGBAImageArithmetic(inObj[0], inObj[1], operator, 1, &errNum)) == NULL) { ok = 0; (void )WlzStringFromErrorNum(errNum, &errMsg); (void )fprintf(stderr, "%s: failed to compute new object (%s).\n", *argv, errMsg); } } else if((outObj = WlzImageArithmetic(inObj[0], inObj[1], operator, 0, &errNum)) == NULL) { ok = 0; (void )WlzStringFromErrorNum(errNum, &errMsg); (void )fprintf(stderr, "%s: failed to compute new object (%s).\n", *argv, errMsg); } } if(ok && (norm != WLZ_IMARNORM_NONE) && (WlzGreyTypeFromObj(inObj[0], &errNum) != WLZ_GREY_RGBA) ) { if((errNum = WlzGreyRange(outObj, gMin+ 2, gMax + 2)) != WLZ_ERR_NONE) { ok = 0; (void )WlzStringFromErrorNum(errNum, &errMsg); (void )fprintf(stderr, "%s: failed to find output object's grey range (%s)\n", *argv, errMsg); } if(ok) { if(norm == WLZ_IMARNORM_256) { gMin[0].type = WLZ_GREY_UBYTE; gMin[0].v.ubv = 0; gMax[0].type = WLZ_GREY_UBYTE; gMax[0].v.ubv = 255; (void )WlzValueConvertPixel(gMin, gMin[0], gMin[2].type); (void )WlzValueConvertPixel(gMax, gMax[0], gMax[2].type); } else { (void )WlzValueConvertPixel(gMin, gMin[0], gMin[2].type); (void )WlzValueConvertPixel(gMax, gMax[0], gMax[2].type); (void )WlzValueConvertPixel(gMin + 1, gMin[1], gMin[2].type); (void )WlzValueConvertPixel(gMax + 1, gMax[1], gMax[2].type); switch(gMin[2].type) { case WLZ_GREY_INT: if(gMin[1].v.inv < gMin[0].v.inv) { gMin[0].v.inv = gMin[1].v.inv; } if(gMax[1].v.inv > gMax[0].v.inv) { gMax[0].v.inv = gMax[1].v.inv; } break; case WLZ_GREY_SHORT: if(gMin[1].v.shv < gMin[0].v.shv) { gMin[0].v.shv = gMin[1].v.shv; } if(gMax[1].v.shv > gMax[0].v.shv) { gMax[0].v.shv = gMax[1].v.shv; } break; case WLZ_GREY_UBYTE: if(gMin[1].v.ubv < gMin[0].v.ubv) { gMin[0].v.ubv = gMin[1].v.ubv; } if(gMax[1].v.ubv > gMax[0].v.ubv) { gMax[0].v.ubv = gMax[1].v.ubv; } break; case WLZ_GREY_FLOAT: if(gMin[1].v.flv < gMin[0].v.flv) { gMin[0].v.flv = gMin[1].v.flv; } if(gMax[1].v.flv > gMax[0].v.flv) { gMax[0].v.flv = gMax[1].v.flv; } break; case WLZ_GREY_DOUBLE: if(gMin[1].v.dbv < gMin[0].v.dbv) { gMin[0].v.dbv = gMin[1].v.dbv; } if(gMax[1].v.dbv > gMax[0].v.dbv) { gMax[0].v.dbv = gMax[1].v.dbv; } break; default: errNum = WLZ_ERR_GREY_TYPE; break; } } } if((errNum = WlzGreySetRange(outObj, gMin[2], gMax[2], gMin[0], gMax[0], dither)) != WLZ_ERR_NONE) { ok = 0; (void )WlzStringFromErrorNum(errNum, &errMsg); (void )fprintf(stderr, "%s: failed to set output object's grey range (%s)\n", *argv, errMsg); } } 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, "-")) { fclose(fP); } } WlzFreeObj(inObj[0]); WlzFreeObj(inObj[1]); WlzFreeObj(outObj); if(usage) { fprintf(stderr, "Usage: %s" " [-O#] [-o<out file>] [-a] [-b <op>] [-d] [-g] [-i] [-l] [-m] [-s] [-h] " "[<in object 0>] [<in object 1>]\n" "Options:\n" " -O Overwrite option (only useful for debugging)\n" " -o Output file name.\n" " -a Add the object's grey values.\n" " -b <op> Apply binary operation to the grey-values.\n" " op = %d - Add\n" " = %d - SUBTRACT\n" " = %d - MULTIPLY\n" " = %d - DIVIDE\n" " = %d - MODULUS\n" " = %d - EQ\n" " = %d - NE\n" " = %d - GT\n" " = %d - GE\n" " = %d - LT\n" " = %d - LE\n" " = %d - AND\n" " = %d - OR\n" " = %d - XOR\n" " = %d - MAX\n" " = %d - MIN\n" " = %d - MAGNITUDE\n" " -d Divide the grey values of the 1st object by those of the 2nd.\n" " -g Vector magnitude of horizontal and vertical component objects\n" " -i Dither values if setting range\n" " -l Compute the modulus of the grey values of the 1st object wrt\n" " those of the 2nd.\n" " -m Multiply the object's grey values.\n" " -s Subtract the grey values of the 2nd object from those of the 1st.\n" " -n Normalises the output object to the range of the input objects.\n" " -N Normalises the output objects to the range [0-255].\n" " -h Help, prints this usage message.\n" "Computes an arithmetic binary (two objects) operation on two domain\n" "objects. The default operator is add.\n" "The input objects are read from stdin and values are written to stdout\n" "unless the filenames are given.\n" "Example:\n%s%s%s", *argv, WLZ_BO_ADD, WLZ_BO_SUBTRACT, WLZ_BO_MULTIPLY, WLZ_BO_DIVIDE, WLZ_BO_MODULUS, WLZ_BO_EQ, WLZ_BO_NE, WLZ_BO_GT, WLZ_BO_GE, WLZ_BO_LT, WLZ_BO_LE, WLZ_BO_AND, WLZ_BO_OR, WLZ_BO_XOR, WLZ_BO_MAX, WLZ_BO_MIN, WLZ_BO_MAGNITUDE, "cat obj1.wlz | ", *argv, " -o obj3.wlz -a obj2.wlz\n" "A new object 'obj3.wlz is formed by adding the grey values of obj1 and\n" "obj2.wlz.\n"); } return(!ok); }
/*! * \return New filtered object with new values or NULL on error. * \ingroup WlzValuesFilters * \brief Applies a seperable filter to the given object using the given * convolution kernels. * \param inObj Input 2 or 3D spatial domain object * to be filtered which must have scalar * values. * \param cBufSz Convolution kernel sizes (sz), each * kernel buffer is sized (2 * sz) + 1 * with the centre indexed sz into the * buffer. * \param cBuf Convolution kernel buffers. * \param direc Set to non-zero in directions for which * the filter is to be applied. * \param gType Required return object grey type. * Passing in WLZ_GREY_ERROR will * request the given input object's grey * type. * \param pad Type of padding. * \param padVal Padding value, only used when * pad == ALG_PAD_VALUE. * \param dstErr Destination error pointer may be NULL. */ WlzObject *WlzSepFilter(WlzObject *inObj, WlzIVertex3 cBufSz, double *cBuf[], WlzIVertex3 direc, WlzGreyType gType, AlgPadType pad, double padVal, WlzErrorNum *dstErr) { int dim = 0, vSz = 0, nThr = 1; double **iBuf = NULL, **rBuf = NULL; double *vBuf = NULL; WlzObject *rnObj = NULL; WlzIVertex3 vBufSz = {0}; WlzIBox3 bBox = {0}; WlzErrorNum errNum = WLZ_ERR_NONE; #ifdef _OPENMP #pragma omp parallel { #pragma omp master { nThr = omp_get_num_threads(); } } #endif if(inObj == NULL) { errNum = WLZ_ERR_OBJECT_NULL; } else if(inObj->domain.core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } else if(inObj->values.core == NULL) { errNum = WLZ_ERR_VALUES_NULL; } else { switch(inObj->type) { case WLZ_2D_DOMAINOBJ: dim = 2; break; case WLZ_3D_DOMAINOBJ: dim = 3; break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } if((errNum == WLZ_ERR_NONE) && (gType == WLZ_GREY_ERROR)) { gType = WlzGreyTypeFromObj(inObj, &errNum); } if(errNum == WLZ_ERR_NONE) { if(errNum == WLZ_ERR_NONE) { switch(gType) { case WLZ_GREY_INT: /* FALLTHROUGH */ case WLZ_GREY_SHORT: /* FALLTHROUGH */ case WLZ_GREY_UBYTE: /* FALLTHROUGH */ case WLZ_GREY_FLOAT: /* FALLTHROUGH */ case WLZ_GREY_DOUBLE: break; default: errNum = WLZ_ERR_GREY_TYPE; break; } } } if(errNum == WLZ_ERR_NONE) { bBox = WlzBoundingBox3I(inObj, &errNum); if(errNum == WLZ_ERR_NONE) { vBufSz.vtX = bBox.xMax - bBox.xMin + 1; vBufSz.vtY = bBox.yMax - bBox.yMin + 1; if(dim == 3) { vBufSz.vtZ = bBox.zMax - bBox.zMin + 1; } } } if(errNum == WLZ_ERR_NONE) { vSz = ALG_MAX3(vBufSz.vtX, vBufSz.vtY, vBufSz.vtZ); if(((iBuf = (double **)AlcMalloc(sizeof(double *) * 2 * nThr)) == NULL) || ((vBuf = (double *)AlcMalloc(sizeof(double) * 2 * nThr * vSz)) == NULL)) { errNum = WLZ_ERR_MEM_ALLOC; } else { int idt; rBuf = iBuf + nThr; for(idt = 0; idt < nThr; ++idt) { iBuf[idt] = vBuf + (idt * vSz); rBuf[idt] = vBuf + ((nThr + idt) * vSz); } } } if(errNum == WLZ_ERR_NONE) { /* Convolve the object values. */ if(direc.vtX) { rnObj = WlzSepFilterX(inObj, dim, nThr, iBuf, rBuf, cBufSz.vtX, cBuf[0], pad, padVal, &errNum); } if((errNum == WLZ_ERR_NONE) && direc.vtY) { WlzObject *tObj; tObj = WlzSepFilterY((rnObj)? rnObj: inObj, dim, nThr, iBuf, rBuf, cBufSz.vtY, cBuf[1], pad, padVal, &errNum); (void )WlzFreeObj(rnObj); rnObj = tObj; } if((errNum == WLZ_ERR_NONE) && (dim == 3) && direc.vtZ) { WlzObject *tObj; tObj = WlzSepFilterZ((rnObj)? rnObj: inObj, bBox, nThr, iBuf, rBuf, cBufSz.vtZ, cBuf[2], pad, padVal, &errNum); (void )WlzFreeObj(rnObj); rnObj = tObj; } } if((errNum == WLZ_ERR_NONE) && (rnObj != NULL) && (gType != WLZ_GREY_DOUBLE)) { WlzObject *tObj; /* Convert object values to the required grey type. */ tObj = WlzConvertPix((rnObj)? rnObj: inObj, gType, &errNum); (void )WlzFreeObj(rnObj); rnObj = tObj; } if(errNum != WLZ_ERR_NONE) { (void )WlzFreeObj(rnObj); rnObj = NULL; } AlcFree(iBuf); AlcFree(vBuf); return(rnObj); }
int main(int argc, char **argv) { char optList[] = "hv"; int option; /* int verboseFlg=0; */ WlzErrorNum errNum=WLZ_ERR_NONE; char *tiffFile=NULL; WlzObject *inObj, *outObj, *obj, **objVec; int i, objVecCount; WlzGreyType gType; /* read the argument list and check for an input file */ opterr = 0; while( (option = getopt(argc, argv, optList)) != EOF ){ switch( option ){ case 'v': /* verboseFlg = 1; */ break; case 'h': default: usage(argv[0]); return WLZ_ERR_UNSPECIFIED; } } if( optind < argc ){ tiffFile = *(argv+optind); } else { usage(argv[0]); return WLZ_ERR_UNSPECIFIED; } /* read the TIFF file */ if( (inObj = WlzAssignObject(WlzEffReadObj(NULL, tiffFile, WLZEFF_FORMAT_TIFF, 0, 0, 0, &errNum), NULL)) == NULL ){ usage(argv[0]); return errNum; } /* if 2D then that is the shade file, else take max of 3D stack */ switch( inObj->type ){ case WLZ_2D_DOMAINOBJ: outObj = inObj; break; case WLZ_3D_DOMAINOBJ: if( (errNum = WlzExplode3D(&objVecCount, &objVec, inObj)) != WLZ_ERR_NONE ){ usage(argv[0]); return errNum; } gType = WlzGreyTypeFromObj(objVec[0], &errNum); outObj = WlzAssignObject(objVec[0], NULL); for(i=1; i < objVecCount; i++){ if( gType == WLZ_GREY_RGBA ){ obj = WlzRGBAImageArithmetic(outObj, objVec[i], WLZ_BO_MAX, 0, &errNum); } else { obj = WlzImageArithmetic(outObj, objVec[i], WLZ_BO_MAX, 0, &errNum); } if( obj ){ WlzFreeObj(outObj); outObj = WlzAssignObject(obj, &errNum); } else { break; } } WlzFreeObj(inObj); break; default: WlzFreeObj(inObj); errNum = WLZ_ERR_OBJECT_TYPE; } /* write shade object */ if( errNum == WLZ_ERR_NONE ){ WlzWriteObj(stdout, outObj); WlzFreeObj(outObj); } else { usage(argv[0]); } return errNum; }
/*! * \return New Woolz object. * \ingroup WlzAllocation * \brief Creates a new or adds to an existing 3D spatial domain * object using a rectangular buffer of values to a single * plane of the given current object (which may be NULL or * empty if the object is to be created). * The returned object will share domains and values of * planes other than the given plane with the current object. * \param cObj Given current object. * \param og Origin of rectangular buffer. * \param sz Buffer size (note 2D). * \param gType Grey type which must be consistent * with the current object (if it is * valid) and the buffer of values. * \param bufSz Number of values in the buffer * (ie sz.vtX * sz.vtY). * \param bufP Given buffer of values. * \param dstErr Destination error pointer, may be NULL. */ WlzObject *WlzBuildObj3(WlzObject *cObj, WlzIVertex3 og, WlzIVertex2 sz, WlzGreyType gType, int bufSz, WlzGreyP bufP, WlzErrorNum *dstErr) { int nPlnReq = 1; WlzDomain cDom, nDom; WlzValues cVal, nVal; WlzObject *nObj = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; cDom.core = NULL; nDom.core = NULL; cVal.core = NULL; nVal.core = NULL; if(cObj) { WlzGreyType cGType = WLZ_GREY_ERROR;; switch(cObj->type) { case WLZ_EMPTY_OBJ: cObj = NULL; break; case WLZ_3D_DOMAINOBJ: if(cObj->domain.core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } else if(cObj->values.core == NULL) { errNum = WLZ_ERR_VALUES_NULL; } else { cDom = cObj->domain; cVal = cObj->values; cGType = WlzGreyTypeFromObj(cObj, &errNum); } if((errNum == WLZ_ERR_NONE) && (cGType != gType)) { errNum = WLZ_ERR_GREY_TYPE; } break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } /* Create a new object with new plane domain and voxel values. */ if(errNum == WLZ_ERR_NONE) { WlzIBox3 nBox; WlzPixelV bgdV; float vxSz[3]; nBox.xMin = og.vtX; nBox.yMin = og.vtY; nBox.zMin = og.vtZ; nBox.xMax = og.vtX + sz.vtX - 1; nBox.yMax = og.vtY + sz.vtY - 1; nBox.zMax = og.vtZ; if(cObj) { nPlnReq = (og.vtZ < cDom.p->plane1) || (og.vtZ > cDom.p->lastpl) || ((*(cDom.p->domains + og.vtZ - cDom.p->plane1)).core == NULL); nBox.xMin = ALG_MIN(nBox.xMin, cDom.p->kol1); nBox.yMin = ALG_MIN(nBox.yMin, cDom.p->line1); nBox.zMin = ALG_MIN(nBox.zMin, cDom.p->plane1); nBox.xMax = ALG_MAX(nBox.xMax, cDom.p->lastkl); nBox.yMax = ALG_MAX(nBox.yMax, cDom.p->lastln); nBox.zMax = ALG_MAX(nBox.zMax, cDom.p->lastpl); vxSz[0] = cDom.p->voxel_size[0]; vxSz[1] = cDom.p->voxel_size[1]; vxSz[2] = cDom.p->voxel_size[2]; bgdV = WlzGetBackground(cObj, &errNum); } else { vxSz[0] = vxSz[1] = vxSz[2] = 1.0f; bgdV.type = WLZ_GREY_INT; bgdV.v.inv = 0; } if(errNum == WLZ_ERR_NONE) { nDom.p = WlzMakePlaneDomain(WLZ_PLANEDOMAIN_DOMAIN, nBox.zMin, nBox.zMax, nBox.yMin, nBox.yMax, nBox.xMin, nBox.xMax, &errNum); } if(errNum == WLZ_ERR_NONE) { nVal.vox = WlzMakeVoxelValueTb(WLZ_VOXELVALUETABLE_GREY, nBox.zMin, nBox.zMax, bgdV, NULL, &errNum); } if(errNum == WLZ_ERR_NONE) { nDom.p->voxel_size[0] = vxSz[0]; nDom.p->voxel_size[1] = vxSz[1]; nDom.p->voxel_size[2] = vxSz[2]; nObj = WlzMakeMain(WLZ_3D_DOMAINOBJ, nDom, nVal, NULL, NULL, &errNum); } } /* Set the domain and values on each plane for the new object. */ if(errNum == WLZ_ERR_NONE) { int idZ; for(idZ = nDom.p->plane1; idZ <= nDom.p->lastpl; ++idZ) { int idP; WlzDomain nDom2; WlzValues nVal2; nDom2.core = NULL; nVal2.core = NULL; idP = idZ - nDom.p->plane1; if(idZ == og.vtZ) { /* Plane with buffer. */ WlzIVertex2 og2, sz2; WlzObject *cObj2 = NULL, *nObj2 = NULL; og2.vtX = og.vtX; og2.vtY = og.vtY; sz2.vtX = sz.vtX; sz2.vtY = sz.vtY; if(nPlnReq == 0) { int idP; idP = idZ - cDom.p->plane1; cObj2 = WlzMakeMain(WLZ_2D_DOMAINOBJ, *(cDom.p->domains + idP), *(cVal.vox->values + idP), NULL, NULL, &errNum); } nObj2 = WlzBuildObj2(cObj2, og2, sz2, gType, bufSz, bufP, &errNum); if(errNum == WLZ_ERR_NONE) { nDom2 = WlzAssignDomain(nObj2->domain, NULL); nVal2 = WlzAssignValues(nObj2->values, NULL); } (void )WlzFreeObj(cObj2); (void )WlzFreeObj(nObj2); } else if((idZ >= cDom.p->plane1) && (idZ <= cDom.p->lastpl)) { /* Not buffer plane, but previously existing plane. */ int idQ; idQ = idZ - cDom.p->plane1; nDom2 = WlzAssignDomain(*(cDom.p->domains + idQ), NULL); nVal2 = WlzAssignValues(*(cVal.vox->values + idQ), NULL); } if(errNum == WLZ_ERR_NONE) { *(nDom.p->domains + idP) = nDom2; *(nVal.vox->values + idP) = nVal2; } else { break; } } } if(dstErr) { *dstErr = errNum; } return(nObj); }
int main(int argc, char **argv) { char optList[] = "b:hv"; int option; int verboseFlg=0; WlzBinaryOperatorType operator = WLZ_BO_ADD; FILE *inFile; double val; WlzPixelV pval; WlzObject *obj, *obj1; WlzErrorNum errNum; /* read the argument list and check for an input file */ opterr = 0; while( (option = getopt(argc, argv, optList)) != EOF ){ switch( option ){ case 'b': operator = atoi(optarg); switch( operator ){ case WLZ_BO_ADD: case WLZ_BO_SUBTRACT: case WLZ_BO_MULTIPLY: case WLZ_BO_DIVIDE: case WLZ_BO_MODULUS: case WLZ_BO_EQ: case WLZ_BO_NE: case WLZ_BO_GT: case WLZ_BO_GE: case WLZ_BO_LT: case WLZ_BO_LE: case WLZ_BO_AND: case WLZ_BO_OR: case WLZ_BO_XOR: case WLZ_BO_MAX: case WLZ_BO_MIN: case WLZ_BO_MAGNITUDE: break; default: usage(argv[0]); return( 1 ); } break; case 'v': verboseFlg = 1; break; case 'h': default: usage(argv[0]); return( 1 ); } } /* get the scalar value */ switch( operator ){ case WLZ_BO_ADD: case WLZ_BO_SUBTRACT: case WLZ_BO_MULTIPLY: case WLZ_BO_DIVIDE: case WLZ_BO_MODULUS: case WLZ_BO_EQ: case WLZ_BO_NE: case WLZ_BO_GT: case WLZ_BO_GE: case WLZ_BO_LT: case WLZ_BO_LE: case WLZ_BO_AND: case WLZ_BO_OR: case WLZ_BO_XOR: case WLZ_BO_MAX: case WLZ_BO_MIN: if( optind < argc ){ val = atof(*(argv+optind)); pval.type = WLZ_GREY_DOUBLE; pval.v.dbv = val; optind++; } break; case WLZ_BO_MAGNITUDE: break; } /* get the file pointer */ inFile = stdin; if( optind < argc ){ if( (inFile = fopen(*(argv+optind), "r")) == NULL ){ fprintf(stderr, "%s: can't open file %s\n", argv[0], *(argv+optind)); usage(argv[0]); return( 1 ); } } /* process objects */ while( (obj = WlzReadObj(inFile, NULL)) != NULL ) { if( WlzGreyTypeFromObj(obj, &errNum) == WLZ_GREY_RGBA ){ obj1 = WlzRGBAScalarBinaryOp(obj, pval, operator, &errNum); WlzWriteObj(stdout, obj1); WlzFreeObj(obj1); } else { WlzScalarBinaryOp(obj, pval, obj, operator); WlzWriteObj(stdout, obj); WlzFreeObj(obj); } } return 0; }
/*! * \return New Woolz object. * \ingroup WlzAllocation * \brief Creates a new 2D spatial domain object by adding a * rectangular buffer of values to the given current * object (which may be NULL or empty). * \param cObj Given current object. * \param og Origin of rectangular buffer. * \param sz Buffer size. * \param gType Grey type which must be consistent * with the current object and the * buffer of values. * \param bufSz Number of values in the buffer. * \param bufP Given buffer of values. * \param dstErr Destination error pointer, may be NULL. */ static WlzObject *WlzBuildObj2(WlzObject *cObj, WlzIVertex2 og, WlzIVertex2 sz, WlzGreyType gType, int bufSz, WlzGreyP bufP, WlzErrorNum *dstErr) { WlzDomain bDom; WlzValues bVal, nVal; WlzObject *bObj = NULL, *nObj = NULL; WlzPixelV bgdV; WlzErrorNum errNum = WLZ_ERR_NONE; bDom.core = NULL; bVal.core = NULL; nVal.core = NULL; bgdV.type = WLZ_GREY_INT; bgdV.v.inv = 0; if(cObj) { WlzGreyType cGType = WLZ_GREY_ERROR;; switch(cObj->type) { case WLZ_EMPTY_OBJ: cObj = NULL; break; case WLZ_2D_DOMAINOBJ: if(cObj->domain.core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } else if(cObj->values.core == NULL) { errNum = WLZ_ERR_VALUES_NULL; } else { cGType = WlzGreyTypeFromObj(cObj, &errNum); bgdV = WlzGetBackground(cObj, &errNum); } if((errNum == WLZ_ERR_NONE) && (cGType != gType)) { errNum = WLZ_ERR_GREY_TYPE; } break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } /* Create new object with domain and values of given rectangular buffer. */ if(errNum == WLZ_ERR_NONE) { bDom.i = WlzMakeIntervalDomain(WLZ_INTERVALDOMAIN_RECT, og.vtY, og.vtY + sz.vtY - 1, og.vtX, og.vtX + sz.vtX - 1, &errNum); } if(errNum == WLZ_ERR_NONE) { WlzObjectType gTT; gTT = WlzGreyTableType(WLZ_GREY_TAB_RECT, gType, NULL); bVal.r = WlzMakeRectValueTb(gTT, bDom.i->line1, bDom.i->lastln, bDom.i->kol1, sz.vtX, bgdV, bufP.inp, &errNum); } if(errNum == WLZ_ERR_NONE) { bObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, bDom, bVal, NULL, NULL, &errNum); } if(errNum == WLZ_ERR_NONE) { if(cObj == NULL) { /* Just copy the buffer object. */ nObj = WlzCopyObject(bObj, &errNum); } else { /* Compute union of current and buffer objects. */ nObj = (cObj)? WlzUnion2(cObj, bObj, &errNum): WlzMakeMain(WLZ_2D_DOMAINOBJ, bDom, nVal, NULL, NULL, &errNum); /* Create new value table. */ if(errNum == WLZ_ERR_NONE) { WlzObjectType gTT; gTT = WlzGreyTableType(WLZ_GREY_TAB_RAGR, gType, NULL); nVal.v = WlzNewValueTb(nObj, gTT, bgdV, &errNum); } if(errNum == WLZ_ERR_NONE) { nObj->values = WlzAssignValues(nVal, NULL); } if(errNum == WLZ_ERR_NONE) { WlzObject *tObj; /* Copy existing values to new object. */ tObj = WlzGreyTransfer(nObj, cObj, &errNum); (void )WlzFreeObj(nObj); nObj = tObj; /* Then copy buffer values to new object. */ if(errNum == WLZ_ERR_NONE) { tObj = WlzGreyTransfer(nObj, bObj, &errNum); (void )WlzFreeObj(nObj); nObj = tObj; } } } } (void )WlzFreeObj(bObj); if(dstErr) { *dstErr = errNum; } return(nObj); }
/*! * \return Woolz error code. * \ingroup WlzExtFF * \brief Writes the given Woolz 3D domain object with values to * the given file using the Amira lattice (.am file) format. * \param fP Output file pointer * \param obj Object to be written. */ static WlzErrorNum WlzEffAmWrite3DDomObj(FILE *fP, WlzObject *obj) { size_t dataCnt, dataSz; WlzDBox3 bbD; WlzIBox3 bbI; WlzIVertex3 sz, org; WlzDVertex3 vSz; char *dateS, *dataTypeS; time_t tTime; WlzGreyType gType; void ***data = NULL; WlzErrorNum errNum = WLZ_ERR_UNIMPLEMENTED; if(obj->domain.core->type != WLZ_PLANEDOMAIN_DOMAIN) { errNum = WLZ_ERR_DOMAIN_TYPE; } else if(obj->values.core == NULL) { errNum = WLZ_ERR_VALUES_NULL; } else if(obj->values.core->type != WLZ_VOXELVALUETABLE_GREY) { errNum = WLZ_ERR_VALUES_TYPE; } else { bbI = WlzBoundingBox3I(obj, &errNum); } if(errNum == WLZ_ERR_NONE) { tTime = time(NULL); dateS = ctime(&tTime); *(dateS + strlen(dateS) - 1) = '\0'; } if(errNum == WLZ_ERR_NONE) { vSz = WlzVozelSz(obj, &errNum); } if(errNum == WLZ_ERR_NONE) { bbD.xMin = bbI.xMin * vSz.vtX; bbD.xMax = bbI.xMax * vSz.vtX; bbD.yMin = bbI.yMin * vSz.vtY; bbD.yMax = bbI.yMax * vSz.vtY; bbD.zMin = bbI.zMin * vSz.vtZ; bbD.zMax = bbI.zMax * vSz.vtZ; sz.vtX = bbI.xMax - bbI.xMin + 1; sz.vtY = bbI.yMax - bbI.yMin + 1; sz.vtZ = bbI.zMax - bbI.zMin + 1; org.vtX = bbI.xMin; org.vtY = bbI.yMin; org.vtZ = bbI.zMin; gType = WlzGreyTypeFromObj(obj, &errNum); } if(errNum == WLZ_ERR_NONE) { switch(gType) { case WLZ_GREY_SHORT: dataTypeS = "short"; break; case WLZ_GREY_UBYTE: dataTypeS = "byte"; break; default: errNum = WLZ_ERR_GREY_TYPE; break; } } if(errNum == WLZ_ERR_NONE) { if(fprintf(fP, "# AmiraMesh 3D BINARY 2.0\n" "# WlzExtFF\n" "# CreationDate: %s\n" "\n" "define Lattice %d %d %d\n" "\n" "Parameters {\n" " Content \"%dx%dx%d %s, uniform coordinates\",\n" " BoundingBox %g %g %g %g %g %g,\n" " CoordType \"uniform\"\n" "}\n" "\n" "Lattice { %s Data } @1\n" "\n" "# Data section follows\n" "@1\n", dateS, sz.vtX, sz.vtY, sz.vtZ, sz.vtX, sz.vtY, sz.vtZ, dataTypeS, bbD.xMin, bbD.xMax, bbD.yMin, bbD.yMax, bbD.zMin, bbD.zMax, dataTypeS) <= 0) { errNum = WLZ_ERR_WRITE_INCOMPLETE; } } if(errNum == WLZ_ERR_NONE) { errNum = WlzToArray3D(&data, obj, sz, org, 0, gType); } if(errNum == WLZ_ERR_NONE) { dataCnt = sz.vtX * sz.vtY * sz.vtZ; switch(gType) { case WLZ_GREY_SHORT: dataSz = 2; break; case WLZ_GREY_UBYTE: dataSz = 1; break; default: break; } if(fwrite(**data, dataSz, dataCnt, fP) != dataSz * dataCnt) { errNum = WLZ_ERR_WRITE_INCOMPLETE; } } (void )Alc3Free(data); return(errNum); }
/*! * \return Shade corrected object or NULL on error. * \ingroup WlzValueFilters * \brief Shade corrects the given domain object with grey * values. * \f[ p_i = n \frac{(o_i - d_i)}{(s_i - d_i} \f] * The shade corrected image P with values \f$p_i\f$ is * created by applying a correction factor to each image * value of the given image O with values \f$o_i\f$. * \f$s_i\f$ and \f$d_i\f$ are the bright and dark-field * shade image values respectively. * \param srcObj Given object to be shade corrected. * \param shdObj Given bright field object. * \param shdDFObj Given dark field object (may be NULL). * \param nrmVal Normalization value. * \param inPlace Modify the grey values of the given * object in place if non-zero. * \param dstErr Destination error pointer, may * be null. */ WlzObject *WlzShadeCorrectBFDF( WlzObject *srcObj, WlzObject *shdObj, WlzObject *shdDFObj, double nrmVal, int inPlace, WlzErrorNum *dstErr) { WlzObject *rtnObj = NULL; WlzObject *obj1, *obj2; WlzCompoundArray *inCobj, *outCobj; WlzObject **outArray; WlzValues values; int i; WlzErrorNum errNum = WLZ_ERR_NONE; if((srcObj == NULL) || (shdObj == NULL)) { errNum = WLZ_ERR_OBJECT_NULL; } else if((srcObj->domain.core == NULL) || (shdObj->domain.core == NULL)) { errNum = WLZ_ERR_DOMAIN_NULL; } else if((srcObj->values.core == NULL) || (shdObj->values.core == NULL)) { errNum = WLZ_ERR_VALUES_NULL; } else if(WlzGreyTableIsTiled(srcObj->values.core->type) || WlzGreyTableIsTiled(shdObj->values.core->type)) { errNum = WLZ_ERR_VALUES_TYPE; } else { switch(srcObj->type) { case WLZ_2D_DOMAINOBJ: if(shdObj->type != srcObj->type) { errNum = WLZ_ERR_OBJECT_TYPE; } else if( shdDFObj ){ if( WlzGreyTypeFromObj(srcObj, &errNum) == WLZ_GREY_RGBA ){ obj1 = WlzRGBAImageArithmetic(srcObj, shdDFObj, WLZ_BO_SUBTRACT, 0, &errNum); obj2 = WlzRGBAImageArithmetic(shdObj, shdDFObj, WLZ_BO_SUBTRACT, 0, &errNum); } else { obj1 = WlzImageArithmetic(srcObj, shdDFObj, WLZ_BO_SUBTRACT, 0, &errNum); obj2 = WlzImageArithmetic(shdObj, shdDFObj, WLZ_BO_SUBTRACT, 0, &errNum); } rtnObj = WlzShadeCorrect2D(obj1, obj2, nrmVal, inPlace, &errNum); WlzFreeObj(obj1); WlzFreeObj(obj2);; } else { rtnObj = WlzShadeCorrect2D(srcObj, shdObj, nrmVal, inPlace, &errNum); } break; case WLZ_COMPOUND_ARR_1: case WLZ_COMPOUND_ARR_2: inCobj = (WlzCompoundArray *) srcObj; if( inCobj->n > 0 ){ if( (outArray = (WlzObject **) AlcCalloc(inCobj->n, sizeof(WlzObject *))) == NULL){ errNum = WLZ_ERR_MEM_ALLOC; } else { for(i=0; (i < inCobj->n) && (errNum == WLZ_ERR_NONE); i++){ /* allow special behaviour of a non-compound shade image to be used for each object in a compound but must align */ switch( shdObj->type ){ case WLZ_2D_DOMAINOBJ: case WLZ_3D_DOMAINOBJ: outArray[i] = WlzShadeCorrectBFDF(inCobj->o[i], shdObj, shdDFObj, nrmVal, inPlace, &errNum); break; case WLZ_COMPOUND_ARR_1: case WLZ_COMPOUND_ARR_2: outArray[i] = WlzShadeCorrectBFDF(inCobj->o[i], ((WlzCompoundArray *) shdObj)->o[i], shdDFObj? ((WlzCompoundArray *) shdDFObj)->o[i]:NULL, nrmVal, inPlace, &errNum); break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } if( errNum == WLZ_ERR_NONE ){ outCobj = WlzMakeCompoundArray(srcObj->type, 3, inCobj->n, outArray, outArray[0]->type, &errNum); rtnObj = (WlzObject *) outCobj; } else { while( i >= 0 ){ WlzFreeObj(outArray[i--]); } } AlcFree(outArray); } } else { errNum = WLZ_ERR_OBJECT_DATA; } break; case WLZ_3D_DOMAINOBJ: errNum = WLZ_ERR_UNIMPLEMENTED; break; case WLZ_TRANS_OBJ: if((rtnObj = WlzShadeCorrectBFDF(srcObj->values.obj, shdObj, shdDFObj, nrmVal, inPlace, &errNum)) != NULL){ values.obj = rtnObj; return WlzMakeMain(WLZ_TRANS_OBJ, srcObj->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); }