WlzObject *WlzRGBABoxThreshold( WlzObject *obj, WlzPixelV lowVal, WlzPixelV highVal, WlzErrorNum *dstErr) { WlzErrorNum errNum=WLZ_ERR_NONE; WlzObject *rtnObj=NULL; int h, l; WlzUInt combineMode; /* check and reset low annd high values */ l = WLZ_RGBA_RED_GET(lowVal.v.rgbv); h = WLZ_RGBA_RED_GET(highVal.v.rgbv); if( l > h ){ WLZ_RGBA_RED_SET(highVal.v.rgbv, l); WLZ_RGBA_RED_SET(lowVal.v.rgbv, h); } l = WLZ_RGBA_GREEN_GET(lowVal.v.rgbv); h = WLZ_RGBA_GREEN_GET(highVal.v.rgbv); if( l > h ){ WLZ_RGBA_GREEN_SET(highVal.v.rgbv, l); WLZ_RGBA_GREEN_SET(lowVal.v.rgbv, h); } l = WLZ_RGBA_BLUE_GET(lowVal.v.rgbv); h = WLZ_RGBA_BLUE_GET(highVal.v.rgbv); if( l > h ){ WLZ_RGBA_BLUE_SET(highVal.v.rgbv, l); WLZ_RGBA_BLUE_SET(lowVal.v.rgbv, h); } /* set all AND for combine value and call multi-threshold */ WLZ_RGBA_RGBA_SET(combineMode, WLZ_BO_AND, WLZ_BO_AND, WLZ_BO_AND, 255); rtnObj = WlzRGBAMultiThreshold(obj, lowVal, highVal, combineMode, &errNum); /* check error and return */ if( dstErr ){ *dstErr = errNum; } return rtnObj; }
void warpSetSignalDomain( WlzIVertex2 *selVtx) { WlzErrorNum errNum=WLZ_ERR_NONE; WlzPixelV threshV, threshV1; WlzObject *obj, *obj1; WlzUInt combineMode; /* image processing sequence */ if( warpGlobals.sgnlThreshObj == NULL ){ warpSetSignalThreshObj(); } if( warpGlobals.sgnlThreshObj ){ obj1 = WlzAssignObject(warpGlobals.sgnlThreshObj, &errNum); } else { return; } /* threshold the resultant image */ if( errNum == WLZ_ERR_NONE ){ switch( warpGlobals.thresholdType ){ case WLZ_RGBA_THRESH_NONE: break; case WLZ_RGBA_THRESH_SINGLE: threshV.type = WLZ_GREY_INT; threshV.v.inv = warpGlobals.threshRangeLow; if( obj1 ){ /* clear signal object */ if( warpGlobals.sgnlObj ){ WlzFreeObj(warpGlobals.sgnlObj); } if((obj = WlzThreshold(obj1, threshV, WLZ_THRESH_HIGH, &errNum)) && (WlzVolume(obj, &errNum) > 0)){ obj = WlzAssignObject(obj, &errNum); WlzFreeObj(obj1); threshV.v.inv = warpGlobals.threshRangeHigh + 1; if((obj1 = WlzThreshold(obj, threshV, WLZ_THRESH_LOW, &errNum)) && (WlzVolume(obj1, &errNum) > 0)){ warpGlobals.sgnlObj = WlzAssignObject(obj1, &errNum); } else { if( obj1 ){ WlzFreeObj(obj1); } warpGlobals.sgnlObj = NULL; } WlzFreeObj(obj); } else { if( obj ) { WlzFreeObj(obj); } WlzFreeObj(obj1); warpGlobals.sgnlObj = NULL; } } break; case WLZ_RGBA_THRESH_MULTI: /* clear signal object */ if( warpGlobals.sgnlObj ){ WlzFreeObj(warpGlobals.sgnlObj); } /* set the thresholds and combine mode */ threshV.type = WLZ_GREY_RGBA; WLZ_RGBA_RGBA_SET(threshV.v.rgbv, warpGlobals.threshRangeRGBLow[0], warpGlobals.threshRangeRGBLow[1], warpGlobals.threshRangeRGBLow[2], 255); threshV1.type = WLZ_GREY_RGBA; WLZ_RGBA_RGBA_SET(threshV1.v.rgbv, warpGlobals.threshRangeRGBHigh[0], warpGlobals.threshRangeRGBHigh[1], warpGlobals.threshRangeRGBHigh[2], 255); WLZ_RGBA_RGBA_SET(combineMode, WLZ_BO_AND, WLZ_BO_AND, WLZ_BO_AND, 255); /* use multi-threshold */ if((obj = WlzRGBAMultiThreshold(obj1, threshV, threshV1, combineMode, &errNum))){ if( WlzIsEmpty(obj, &errNum) ){ WlzFreeObj(obj); warpGlobals.sgnlObj = NULL; } else { warpGlobals.sgnlObj = WlzAssignObject(obj, &errNum); } } else { warpGlobals.sgnlObj = NULL; } WlzFreeObj(obj1); break; case WLZ_RGBA_THRESH_BOX: /* clear signal object */ if( warpGlobals.sgnlObj ){ WlzFreeObj(warpGlobals.sgnlObj); } /* use box-threshold */ if((obj = WlzRGBABoxThreshold(obj1, warpGlobals.lowRGBPoint, warpGlobals.highRGBPoint, &errNum))){ if( WlzIsEmpty(obj, &errNum) ){ WlzFreeObj(obj); warpGlobals.sgnlObj = NULL; } else { warpGlobals.sgnlObj = WlzAssignObject(obj, &errNum); } } else { warpGlobals.sgnlObj = NULL; } WlzFreeObj(obj1); break; case WLZ_RGBA_THRESH_SLICE: /* clear signal object */ if( warpGlobals.sgnlObj ){ WlzFreeObj(warpGlobals.sgnlObj); } /* use slice-threshold */ if((obj = WlzRGBASliceThreshold(obj1, warpGlobals.lowRGBPoint, warpGlobals.highRGBPoint, &errNum))){ if( WlzIsEmpty(obj, &errNum) ){ WlzFreeObj(obj); warpGlobals.sgnlObj = NULL; } else { warpGlobals.sgnlObj = WlzAssignObject(obj, &errNum); } } else { warpGlobals.sgnlObj = NULL; } WlzFreeObj(obj1); break; case WLZ_RGBA_THRESH_SPHERE: /* clear signal object */ if( warpGlobals.sgnlObj ){ WlzFreeObj(warpGlobals.sgnlObj); } /* use Ellipsoid-threshold */ if((obj = WlzRGBAEllipsoidThreshold(obj1, warpGlobals.lowRGBPoint, warpGlobals.highRGBPoint, warpGlobals.colorEllipseEcc, &errNum))){ if( WlzIsEmpty(obj, &errNum) ){ WlzFreeObj(obj); warpGlobals.sgnlObj = NULL; } else { warpGlobals.sgnlObj = WlzAssignObject(obj, &errNum); } } else { warpGlobals.sgnlObj = NULL; } WlzFreeObj(obj1); break; default: errNum = WLZ_ERR_PARAM_DATA; if( obj1 ){ WlzFreeObj(obj1); } if( warpGlobals.sgnlObj ){ WlzFreeObj(warpGlobals.sgnlObj); warpGlobals.sgnlObj = NULL; } break; } } /* check for local mode */ if( warpGlobals.sgnlObj && !warpGlobals.globalThreshFlg ){ if( selVtx != NULL ){ warpGlobals.globalThreshVtx = *selVtx; } /* extract a local domain if the vertex is sensible */ if( warpGlobals.globalThreshVtx.vtX != -10000 ){ WlzObject **objs=NULL; int i, numObjs; double x, y; obj1 = NULL; x = warpGlobals.globalThreshVtx.vtX; y = warpGlobals.globalThreshVtx.vtY; errNum = WlzLabel(warpGlobals.sgnlObj, &numObjs, &objs, 8192, 0, WLZ_4_CONNECTED); if( (errNum == WLZ_ERR_INT_DATA) && (numObjs == 8192) ){ WlzObject *tmpObj1, *tmpObj2; WlzDomain domain; WlzValues values; /* try again, smaller domain */ for(i=0; i < numObjs; i++){ WlzFreeObj( objs[i] ); } AlcFree((void *) objs); objs = NULL; numObjs = 0; domain.i = WlzMakeIntervalDomain(WLZ_INTERVALDOMAIN_RECT, y - 80, y + 80, x - 80, x + 80, &errNum); values.core = NULL; if((tmpObj1 = WlzMakeMain(warpGlobals.sgnlObj->type, domain, values, NULL, NULL, &errNum))){ if((tmpObj2 = WlzIntersect2(warpGlobals.sgnlObj, tmpObj1, &errNum))){ tmpObj2->values = WlzAssignValues(warpGlobals.sgnlObj->values, NULL); errNum = WlzLabel(warpGlobals.sgnlObj, &numObjs, &objs, 8192, 0, WLZ_4_CONNECTED); WlzFreeObj(tmpObj2); if((errNum == WLZ_ERR_INT_DATA) && (numObjs == 8192) ){ errNum = WLZ_ERR_NONE; } } WlzFreeObj(tmpObj1); } } if( errNum == WLZ_ERR_NONE ){ for(i=0; i < numObjs; i++){ if( WlzInsideDomain( objs[i], 0.0, y, x, NULL ) ){ obj1 = WlzMakeMain(objs[i]->type, objs[i]->domain, objs[i]->values, NULL, NULL, NULL); obj1 = WlzAssignObject(obj1, NULL); } WlzFreeObj( objs[i] ); } AlcFree((void *) objs); } if( obj1 ){ WlzFreeObj(warpGlobals.sgnlObj); warpGlobals.sgnlObj = obj1; } } else { WlzFreeObj(warpGlobals.sgnlObj); warpGlobals.sgnlObj = NULL; } } /* check for increment mode */ if( warpGlobals.incrThreshFlg && sgnlIncrObj() ){ if( warpGlobals.sgnlObj ){ if((obj1 = WlzUnion2(warpGlobals.sgnlObj, sgnlIncrObj(), &errNum))){ WlzFreeObj(warpGlobals.sgnlObj); warpGlobals.sgnlObj = WlzAssignObject(obj1, &errNum); } } else { warpGlobals.sgnlObj = WlzAssignObject(sgnlIncrObj(), &errNum); } } if( errNum != WLZ_ERR_NONE ){ MAPaintReportWlzError(globals.topl, "warpSetSignalDomain", errNum); } return; }
/*! * \ingroup WlzThreshold * \brief Apply independent thresholds to each colour channel independently and combine according to the settings encoded in combineMode. Each channel can have one of two modes: WLZ_BO_AND and WLZ_BO_OR. These are encoded into a single mode variable using the RGBA macro, e.g.: WLZ_RGBA_RGBA_SET(combineMode, redMode, greenMode, blueMode, 255); The macro WLZ_RGBA_RED_GET(combineMode) will return redMode and similarly for green and blue. * * \return Thresholded object * \param obj Object to be thresholded * \param lowVal RGB low values * \param highVal RGB high values * \param combineMode Combination rules as an RGBA encoded unsigned integer * \param dstErr Error return * \par Source: * WlzRGBAThreshold.c */ WlzObject *WlzRGBAMultiThreshold( WlzObject *obj, WlzPixelV lowVal, WlzPixelV highVal, WlzUInt combineMode, WlzErrorNum *dstErr) { WlzErrorNum errNum=WLZ_ERR_NONE; WlzObject *rtnObj=NULL; WlzObject *obj1, *obj2; WlzValues values; WlzCompoundArray *cobj=NULL; int low[3], high[3]; WlzUInt mode[3]; /* check inputs */ if( obj == NULL ){ errNum = WLZ_ERR_OBJECT_NULL; } else { /* must be grey-type RGBA or compound with at least three channels */ switch( obj->type ){ case WLZ_2D_DOMAINOBJ: case WLZ_3D_DOMAINOBJ: if( obj->values.core == NULL ){ errNum = WLZ_ERR_VALUES_NULL; } else { /* create compound object */ if((cobj = WlzRGBAToCompound(obj, WLZ_RGBA_SPACE_RGB, &errNum)) != NULL){ cobj = (WlzCompoundArray *) WlzAssignObject((WlzObject *) cobj, &errNum); } } break; case WLZ_TRANS_OBJ: if((obj1 = WlzRGBAMultiThreshold(obj->values.obj, lowVal, highVal, combineMode, &errNum)) != NULL){ values.obj = WlzAssignObject(obj1, NULL); rtnObj = WlzMakeMain(obj->type, obj->domain, values, NULL, obj, &errNum); } break; case WLZ_COMPOUND_ARR_1: case WLZ_COMPOUND_ARR_2: cobj = (WlzCompoundArray *) WlzAssignObject(obj, &errNum); if( cobj->n < 3 ){ errNum = WLZ_ERR_OBJECT_DATA; WlzFreeObj((WlzObject *) cobj); } else if((cobj->o[0]->values.core == NULL) || (cobj->o[1]->values.core == NULL) || (cobj->o[2]->values.core == NULL)){ errNum = WLZ_ERR_VALUES_NULL; } break; case WLZ_EMPTY_OBJ: rtnObj = WlzMakeEmpty(&errNum); break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } if((errNum == WLZ_ERR_NONE) && (rtnObj == NULL)){ if((lowVal.type != WLZ_GREY_RGBA) || (highVal.type != WLZ_GREY_RGBA)){ errNum = WLZ_ERR_PARAM_TYPE; } else { low[0] = WLZ_RGBA_RED_GET(lowVal.v.rgbv); low[1] = WLZ_RGBA_GREEN_GET(lowVal.v.rgbv); low[2] = WLZ_RGBA_BLUE_GET(lowVal.v.rgbv); high[0] = WLZ_RGBA_RED_GET(highVal.v.rgbv); high[1] = WLZ_RGBA_GREEN_GET(highVal.v.rgbv); high[2] = WLZ_RGBA_BLUE_GET(highVal.v.rgbv); } } if((errNum == WLZ_ERR_NONE) && (rtnObj == NULL)){ mode[0] = WLZ_RGBA_RED_GET(combineMode); mode[1] = WLZ_RGBA_GREEN_GET(combineMode); mode[2] = WLZ_RGBA_BLUE_GET(combineMode); } /* get thresholded channels */ if((errNum == WLZ_ERR_NONE) && (cobj != NULL) && (rtnObj == NULL)){ WlzObject *objs[3]; int i; WlzPixelV threshV; for(i=0; i < 3; i++){ threshV.type = WLZ_GREY_INT; threshV.v.inv = low[i]; if((obj1 = WlzThreshold(cobj->o[i], threshV, WLZ_THRESH_HIGH, &errNum)) != NULL){ obj1 = WlzAssignObject(obj1, &errNum); threshV.v.inv = high[i] + 1; if((obj2 = WlzThreshold(obj1, threshV, WLZ_THRESH_LOW, &errNum)) != NULL){ objs[i] = WlzAssignObject(obj2, &errNum); } else { objs[i] = NULL; } WlzFreeObj(obj1); } else { objs[i] = NULL; } } /* combine according to mode what to do here? AND against a channel implies that the threshold constraint must be satisfied, OR implies it may be satisfied so all AND implies intersection, all OR implies union. Otherwise union of ORs and intersect with the ANDs. What about XOR? */ /* find union of all then intersect with ANDs */ obj1 = WlzAssignObject(WlzMakeEmpty(&errNum), NULL); for(i=0; (i < 3) && (errNum == WLZ_ERR_NONE); i++){ if( objs[i] ){ obj2 = WlzUnion2(obj1, objs[i], &errNum); WlzFreeObj(obj1); obj1 = WlzAssignObject(obj2, &errNum); } } for(i=0; i < 3; i++){ if( objs[i] ){ if( (mode[i] == WLZ_BO_AND) && (errNum == WLZ_ERR_NONE) ){ obj2 = WlzIntersect2(obj1, objs[i], &errNum); WlzFreeObj(obj1); obj1 = WlzAssignObject(obj2, &errNum); } WlzFreeObj(objs[i]); } } /* create the return object and add grey-table if possible */ if( obj1 ){ if( WlzIsEmpty(obj1, &errNum) ){ rtnObj = WlzMakeMain(obj1->type, obj1->domain, obj1->values, NULL, NULL, &errNum); } else { if( obj1->type == obj->type ){ rtnObj = WlzMakeMain(obj1->type, obj1->domain, obj->values, NULL, NULL, &errNum); } else { rtnObj = WlzMakeMain(obj1->type, obj1->domain, obj1->values, NULL, NULL, &errNum); } } WlzFreeObj(obj1); } } if( cobj ){ WlzFreeObj((WlzObject *) cobj); } /* check error and return */ if( dstErr ){ *dstErr = errNum; } return rtnObj; }