/*! * \return New Woolz domain object with gradient grey values or * NULL on error. * \ingroup WlzValuesFilters * \brief Computes the gradient of the gray values in the * given Woolz 2D domain object. * \param dstGrdY Destination pointer for the * gradient (partial derivative) * through lines, may be NULL. * \param dstGrdX Destination pointer for the * gradient (partial derivative) * through columns, may be NULL. * \param srcObj Given source object. * \param flt Recursive filter to use. * \param dstErr Destination error pointer, may * be null. */ static WlzObject *WlzGreyGradient2D(WlzObject **dstGrdY, WlzObject **dstGrdX, WlzObject *srcObj, WlzRsvFilter *flt, WlzErrorNum *dstErr) { WlzObject *grdX = NULL, *grdY = NULL, *dstObj = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; if(srcObj == NULL) { errNum = WLZ_ERR_OBJECT_NULL; } else if(srcObj->domain.core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } else if(srcObj->values.core == NULL) { errNum = WLZ_ERR_VALUES_NULL; } else if(WlzGreyTableIsTiled(srcObj->values.core->type)) { errNum = WLZ_ERR_VALUES_TYPE; } if(errNum == WLZ_ERR_NONE) { grdX = WlzRsvFilterObj(srcObj, flt, WLZ_RSVFILTER_ACTION_X, &errNum); } if(errNum == WLZ_ERR_NONE) { grdY = WlzRsvFilterObj(srcObj, flt, WLZ_RSVFILTER_ACTION_Y, &errNum); } if(errNum == WLZ_ERR_NONE) { dstObj = WlzImageArithmetic(grdY, grdX, WLZ_BO_MAGNITUDE, 0, &errNum); } if(dstGrdX && (errNum == WLZ_ERR_NONE)) { *dstGrdX = grdX; } else if(grdX) { WlzFreeObj(grdX); } if(dstGrdY && (errNum == WLZ_ERR_NONE)) { *dstGrdY = grdY; } else if(grdY) { WlzFreeObj(grdY); } if(dstErr) { *dstErr = errNum; } return(dstObj); }
/*! * \return Woolz error code. * \ingroup WlzBinaryOps * \brief Computes a metric which quantifies the extent to which * the domain of one of the given objects is offset from * the domain of the second. This is a symetric metric, ie * \f$OST(\Omega_0, \Omega_1) \equiv OST(\Omega_0, \Omega_1)\f$. * A domain is computed which is equidistant from the domains * of the two given objects, is within maxDist of each object's * domain and is within the convex hull of the union of the * domains of the two given objects. Within this domain the * 1st, 2nd and 3rd quantiles of the distance * (\f$q_0\f$, \f$q_1\f$ and \f$q_2\f$) are found. * The object's domains are classified as offset if * \f[ frac{q_1}{q_1 + (q_1 - q_0) + (q_2 - q_1)} \geq 0.5 \f] * ie * \f[ frac{q_1}{q_1 + q_2 - q_0} \geq 0.5 \f] * Small equi-distant domains with a volume less than half * the maximum distance do not classify the relationship as * an overlap. * \param o Array with the two given spatial * domain objects, must not be NULL * and nor must the objects. * \param t Array of temporary objects as in * WlzRCCTOIdx. * \param maxDist Maximum distance for offset. This * is used to compute a distance object, * large distances will significantly * increase the processing time. * \param dQ0 Destination pointer for 1st quantile * offset distance, must not be NULL. * \param dQ1 Destination pointer for 2nd quantile * (ie median) offset distance, * must not be NULL. * \param dQ2 Destination pointer for 3rd quantile * offset distance, must not be NULL. */ static WlzErrorNum WlzRCCOffset( WlzObject **o, WlzObject **t, int maxDist, int *dQ0, int *dQ1, int *dQ2) { int empty = 0; int q[3] = {0}; int *dHist = NULL; WlzObject *eObj = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; if(((o[0]->type == WLZ_2D_DOMAINOBJ) && (o[1]->type == WLZ_2D_DOMAINOBJ)) || ((o[0]->type == WLZ_3D_DOMAINOBJ) && (o[1]->type == WLZ_3D_DOMAINOBJ))) { if((o[0]->domain.core == NULL) || (o[1]->domain.core == NULL)) { errNum = WLZ_ERR_DOMAIN_NULL; } } else { errNum = WLZ_ERR_OBJECT_TYPE; } /* Compute distance transforms of the two given objects out to a given * maximum distance and then using these distances the equi-distant * domain between these two objects. The values of the eqi-distant object * are those of the distance between the objects.*/ if(errNum == WLZ_ERR_NONE) { int i; WlzObject *sObj = NULL, *cObj = NULL; WlzObject *dObj[2]; dObj[0] = dObj[1] = NULL; /* Create structuring element with which to dilate the given object * domains(by maxDist). */ sObj = WlzAssignObject( WlzMakeSphereObject(o[0]->type, maxDist, 0, 0, 0, &errNum), NULL); /* Create domain or convex hull of the union of the two given object * domains. */ if(errNum == WLZ_ERR_NONE) { WlzObject *uObj = NULL, *xObj = NULL; errNum = WlzRCCMakeT(o, t, WLZ_RCCTOIDX_O0O1U); if(errNum == WLZ_ERR_NONE) { uObj = WlzAssignObject(t[WLZ_RCCTOIDX_O0O1U], NULL); } if(errNum == WLZ_ERR_NONE) { xObj = WlzAssignObject( WlzObjToConvexHull(uObj, &errNum), NULL); } if(errNum == WLZ_ERR_NONE) { cObj = WlzAssignObject( WlzConvexHullToObj(xObj, o[0]->type, &errNum), NULL); } (void )WlzFreeObj(xObj); (void )WlzFreeObj(uObj); } /* Dilate the two given objects and find the ntersection of the * dilated domains with each other and the convex hull computed * above. Within his domain compute the distances. */ if(errNum == WLZ_ERR_NONE) { for(i = 0; i < 2; ++i) { WlzObject *tObj = NULL, *rObj = NULL; tObj = WlzAssignObject( WlzStructDilation(o[i], sObj, &errNum), NULL); if(errNum == WLZ_ERR_NONE) { rObj = WlzAssignObject( WlzIntersect2(tObj, cObj, &errNum), NULL); } (void )WlzFreeObj(tObj); if(errNum == WLZ_ERR_NONE) { dObj[i] = WlzAssignObject( WlzDistanceTransform(rObj, o[!i], WLZ_OCTAGONAL_DISTANCE, 0.0, maxDist, &errNum), NULL); } (void )WlzFreeObj(rObj); if(errNum == WLZ_ERR_NONE) { WlzPixelV bgdV; bgdV.type = WLZ_GREY_INT; bgdV.v.inv = maxDist; errNum = WlzSetBackground(dObj[i], bgdV); } if(errNum != WLZ_ERR_NONE) { break; } } } /* Find the domain which is equi-distant from the two given objects, * within the xDist range and within the convex hull of the union of * the two given object's domains. */ (void )WlzFreeObj(sObj); sObj = NULL; if(errNum == WLZ_ERR_NONE) { WlzLong vol = 0; WlzObject *qObj = NULL, *tObj = NULL; qObj = WlzAssignObject( WlzImageArithmetic(dObj[0], dObj[1], WLZ_BO_EQ, 0, &errNum), NULL); if(errNum == WLZ_ERR_NONE) { WlzPixelV thrV; thrV.type = WLZ_GREY_INT; thrV.v.inv = 1; tObj = WlzAssignObject( WlzThreshold(qObj, thrV, WLZ_THRESH_HIGH, &errNum), NULL); } /* Check that the eqi-distant domain is of a reasonable size ie has * a area or volume greater than half the maximum distance. */ if(errNum == WLZ_ERR_NONE) { vol = WlzVolume(tObj, &errNum); if((maxDist / 2) >= vol) { empty = 1; } } if((errNum == WLZ_ERR_NONE) && !empty) { WlzObject *mObj; WlzPixelV tmpV; tmpV.type = WLZ_GREY_INT; tmpV.v.inv = 0; mObj = WlzAssignObject( WlzGreyTemplate(dObj[0], tObj, tmpV, &errNum), NULL); if(errNum == WLZ_ERR_NONE) { tmpV.v.inv = 1; eObj = WlzAssignObject( WlzThreshold(mObj, tmpV, WLZ_THRESH_HIGH, &errNum), NULL); } (void )WlzFreeObj(mObj); } (void )WlzFreeObj(tObj); (void )WlzFreeObj(qObj); if((errNum == WLZ_ERR_NONE) && !empty) { WlzLong vol; vol = WlzVolume(eObj, &errNum); if((maxDist / 2) >= vol) { empty = 1; } } } (void )WlzFreeObj(cObj); (void )WlzFreeObj(sObj); (void )WlzFreeObj(dObj[0]); (void )WlzFreeObj(dObj[1]); } /* Compute a quantised distance histogram in which equi-distant distances * are quantized to integer values. */ if((errNum == WLZ_ERR_NONE) && !empty) { if((dHist = (int *)AlcCalloc(maxDist + 1, sizeof(int))) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } } if((errNum == WLZ_ERR_NONE) && !empty) { if(eObj->type == WLZ_2D_DOMAINOBJ) { errNum = WlzRCCCompDistHist2D(maxDist, dHist, eObj); } else { errNum = WlzRCCCompDistHist3D(maxDist, dHist, eObj); } #ifdef WLZ_RCC_DEBUG_OST { FILE *fP; fP = fopen("WLZ_RCC_DEBUG_OST.wlz", "w"); (void )WlzWriteObj(fP, eObj); (void )fclose(fP); } #endif } WlzFreeObj(eObj); if((errNum == WLZ_ERR_NONE) && !empty) { int i, n, s, nq; /* Compute the median, first and third quantile offset distances, * the ratio of median to the median plus inner inter-quantile range. */ n = 0; for(i = 0; i < maxDist; ++i) { n += dHist[i]; } i = 0; s = 0; nq = n / 4; while(s < nq) { s += dHist[i++]; } q[0] = i; nq = n / 2; while(s < nq) { s += dHist[i++]; } q[1] = i; nq = (3 * n) / 4; while(s < nq) { s += dHist[i++]; } q[2] = i; } AlcFree(dHist); *dQ0 = q[0]; *dQ1 = q[1]; *dQ2 = q[2]; return(errNum); }
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; }
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 Sobel filtered object. * \ingroup WlzValueFilters * \brief Applies a Sobel edge detection filter to the given * woolz object. * \param srcObj Given source object. * \param hFlag Apply horizontal edge kernel if * non-zero. * \param vFlag Apply vertical edge kernel if * non-zero. * \param dstErr Destination error pointer, may be NULL. */ WlzObject *WlzSobel(WlzObject *srcObj, int hFlag, int vFlag, WlzErrorNum *dstErr) { WlzObject *dstObj = NULL, *objH = NULL, *objV = NULL; WlzGreyType gType; WlzErrorNum errNum = WLZ_ERR_NONE; const int sMaskHI[] = { -1, -2, -1, 0, 0, 0, 1, 2, 1 }, sMaskVI[] = { -1, 0, 1, -2, 0, 2, -1, 0, 1 }; const double sMaskHD[] = { -1.0, -2.0, -1.0, 0.0, 0.0, 0.0, 1.0, 2.0, 1.0 }, sMaskVD[] = { -1.0, 0.0, 1.0, -2.0, 0.0, 2.0, -1.0, 0.0, 1.0 }; WlzConvolution sConv; WLZ_DBG((WLZ_DBG_LVL_1), ("WlzSobel FE %p %d %d %p\n", srcObj, hFlag, vFlag, dstErr)); if(srcObj == NULL) { errNum = WLZ_ERR_OBJECT_NULL; } else if(srcObj->type != WLZ_2D_DOMAINOBJ) { errNum = WLZ_ERR_OBJECT_TYPE; } else if(srcObj->domain.core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } else if(srcObj->values.core == NULL) { errNum = WLZ_ERR_VALUES_NULL; } else { gType = WlzGreyTableTypeToGreyType(srcObj->values.core->type, &errNum); } if(errNum == WLZ_ERR_NONE) { sConv.linkcount = 0; sConv.xsize = 3; sConv.ysize = 3; sConv.cv = NULL; sConv.divscale = 1; sConv.offset = 0; sConv.modflag = 1; switch(gType) { case WLZ_GREY_INT: case WLZ_GREY_SHORT: case WLZ_GREY_UBYTE: sConv.type = WLZ_CONVOLVE_INT; break; case WLZ_GREY_FLOAT: case WLZ_GREY_DOUBLE: sConv.type = WLZ_CONVOLVE_FLOAT; break; case WLZ_GREY_RGBA: /* RGBA to be done RAB */ default: errNum = WLZ_ERR_GREY_DATA; break; } } if(errNum == WLZ_ERR_NONE) { if(hFlag) { sConv.cv = (sConv.type == WLZ_CONVOLVE_INT)? (int *)(&(sMaskHI[0])): (int *)(&(sMaskHD[0])); objH = WlzConvolveObj(srcObj, &sConv, 1, &errNum); } if((errNum == WLZ_ERR_NONE) && vFlag) { sConv.cv = (sConv.type == WLZ_CONVOLVE_INT)? (int *)(&(sMaskVI[0])): (int *)(&(sMaskVD[0])); objV = WlzConvolveObj(srcObj, &sConv, 1, &errNum); } if(errNum == WLZ_ERR_NONE) { if(objH && objV) { dstObj = WlzImageArithmetic(objV, objH, WLZ_BO_ADD, 1, &errNum); (void )WlzFreeObj(objV); objV = NULL; (void )WlzFreeObj(objH); objH = NULL; } else if(objH && (vFlag == 0)) { dstObj = objH; objH = NULL; } else if(objV && (hFlag == 0)) { dstObj = objV; objV = NULL; } } else { (void )WlzFreeObj(objH); (void )WlzFreeObj(objV); } } if(dstErr) { *dstErr = errNum; } WLZ_DBG((WLZ_DBG_LVL_FN|WLZ_DBG_LVL_1), ("WlzSobel FX %p\n", dstObj)); return(dstObj); }
/*! * \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); }