/*! * \return New Woolz object without holes or NULL on error. * \ingroup WlzDomainOps * \brief Fills the holes in the given object's domain (which are by * definition not connected to the outside). When the given * object's domain has more than one component part, the * object should first be labeled, this function should then be * called for each of the labeled parts and then the union of * the filled domains should be formed. * \param srcObj Given 3D domain object. * \param dstErr Destination error pointer, may be NULL. */ WlzObject *WlzDomainFill3D( WlzObject *srcObj, WlzErrorNum *dstErr) { int nPln = 0; WlzObject *bndObj = NULL, *filObj = NULL, *gvnObj = NULL, *sedObj = NULL, *shlObj = NULL; WlzPixelV zeroV; WlzValues nullVal; WlzErrorNum errNum = WLZ_ERR_NONE; nullVal.core = NULL; zeroV.type = WLZ_GREY_UBYTE; zeroV.v.ubv = 0; if(srcObj == NULL) { errNum = WLZ_ERR_OBJECT_NULL; } else if(srcObj->type != WLZ_3D_DOMAINOBJ) { errNum = WLZ_ERR_OBJECT_TYPE; } else if(srcObj->domain.core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } else { gvnObj = WlzMakeMain(srcObj->type, srcObj->domain, nullVal, NULL, NULL, &errNum); } /* Create a then shell 1 voxel thick just inside the given objects's * domain. */ if(errNum == WLZ_ERR_NONE) { WlzObject *difObj = NULL; difObj = WlzAssignObject( WlzBoundaryDomain(gvnObj, &errNum), NULL); if(errNum == WLZ_ERR_NONE) { WlzIBox3 clipBox; /* Clip the dilated shell domain to make sure it stays within the * bounding box of the given object then all planes will align. */ clipBox.xMin = gvnObj->domain.p->kol1; clipBox.yMin = gvnObj->domain.p->line1; clipBox.zMin = gvnObj->domain.p->plane1; clipBox.xMax = gvnObj->domain.p->lastkl; clipBox.yMax = gvnObj->domain.p->lastln; clipBox.zMax = gvnObj->domain.p->lastpl; shlObj = WlzAssignObject( WlzClipObjToBox3D(difObj, clipBox, &errNum), NULL); } (void )WlzFreeObj(difObj); } /* Make sure that the bounding box of the thin shell domain fits it and * that it's first and last planes have interrvals. */ if(errNum == WLZ_ERR_NONE) { errNum = WlzStandardPlaneDomain(shlObj->domain.p, NULL); } /* Create a value table for the shell object with values set to zero. */ if(errNum == WLZ_ERR_NONE) { WlzValues val; WlzObjectType tType; tType = WlzGreyTableType(WLZ_GREY_TAB_INTL, WLZ_GREY_UBYTE, NULL); val.vox = WlzMakeVoxelValueTb(WLZ_VOXELVALUETABLE_GREY, shlObj->domain.p->plane1, shlObj->domain.p->lastpl, zeroV, NULL, &errNum); if(errNum == WLZ_ERR_NONE) { int p; nPln = shlObj->domain.p->lastpl - shlObj->domain.p->plane1 + 1; shlObj->values = WlzAssignValues(val, NULL); #ifdef _OPENMP #pragma omp parallel for shared(shlObj) #endif for(p = 0; p < nPln; ++p) { if(errNum == WLZ_ERR_NONE) { WlzDomain dom2; WlzErrorNum errNum2; dom2 = shlObj->domain.p->domains[p]; if(dom2.core) { WlzValues val2; WlzObject *shlObj2; shlObj2 = WlzMakeMain(WLZ_2D_DOMAINOBJ, dom2, nullVal, NULL, NULL, &errNum2); if(errNum2 == WLZ_ERR_NONE) { val2.i = WlzMakeIntervalValues(tType, shlObj2, zeroV, &errNum2); /* WlzMakeIntervalValues() sets all values to zero. */ } if(errNum2 == WLZ_ERR_NONE) { shlObj->values.vox->values[p] = WlzAssignValues(val2, NULL); } (void )WlzFreeObj(shlObj2); if(errNum2 == WLZ_ERR_NONE) { #ifdef _OPENMP #pragma omp critical { #endif if((errNum == WLZ_ERR_NONE) && (errNum2 != WLZ_ERR_NONE)) { errNum = errNum2; } #ifdef _OPENMP } #endif } } } } } } /* Compute the (plane-wise) boundary list for the given object. */ if(errNum == WLZ_ERR_NONE) { bndObj = WlzObjToBoundary(gvnObj, 0, &errNum); } /* Sweep down through the boundary object setting the values of * those voxels in the shell object to a non zero value when they * correspond to top level boundaries. */ if(errNum == WLZ_ERR_NONE) { int p; #ifdef _OPENMP #pragma omp parallel for shared(bndObj,shlObj) #endif for(p = 0; p < nPln; ++p) { if(errNum == WLZ_ERR_NONE) { WlzDomain bDom2; bDom2 = bndObj->domain.p->domains[p]; if(bDom2.core) { WlzDomain iDom2; WlzValues iVal2; WlzObject *iObj2 = NULL; WlzGreyValueWSpace *gVWSp = NULL; WlzErrorNum errNum2 = WLZ_ERR_NONE; iDom2 = shlObj->domain.p->domains[p]; iVal2 = shlObj->values.vox->values[p]; iObj2 = WlzMakeMain(WLZ_2D_DOMAINOBJ, iDom2, iVal2, NULL, NULL, &errNum2); if(errNum == WLZ_ERR_NONE) { gVWSp = WlzGreyValueMakeWSp(iObj2, &errNum2); } if(errNum2 == WLZ_ERR_NONE) { WlzBoundList *bnd, *bnd2; bnd2 = bDom2.b; for(bnd = bnd2; bnd != NULL; bnd = bnd->next) { if(bnd->poly != NULL) { WlzPolygonDomain *ply; ply = bnd->poly; if(ply) { int i; WlzIVertex2 *vtx; vtx = ply->vtx; for(i = 0; i < ply->nvertices; ++i) { WlzGreyValueGet(gVWSp, 0, vtx[i].vtY, vtx[i].vtX); *(gVWSp->gPtr[0].ubp) = 255; } } } } } else { #ifdef _OPENMP #pragma omp critical { #endif if(errNum == WLZ_ERR_NONE) { errNum = errNum2; } #ifdef _OPENMP } #endif } (void )WlzFreeObj(iObj2); WlzGreyValueFreeWSp(gVWSp); } } } } /* Threshold the shell object, throwing away all but where the voxels * are set to create a seed domain. Then remove the value table from * the shell object and free it as it's no longer needed. */ if(errNum == WLZ_ERR_NONE) { WlzObject *tObj = NULL; WlzPixelV tV; tV.type = WLZ_GREY_UBYTE; tV.v.ubv = 1; tObj = WlzAssignObject( WlzThreshold(shlObj, tV, WLZ_THRESH_HIGH, &errNum), NULL); if(errNum == WLZ_ERR_NONE) { sedObj = WlzAssignObject( WlzMakeMain(tObj->type, tObj->domain, nullVal, NULL, NULL, &errNum), NULL); } (void )WlzFreeObj(tObj); tObj = NULL; if(errNum == WLZ_ERR_NONE) { tObj = WlzAssignObject( WlzMakeMain(shlObj->type, shlObj->domain, nullVal, NULL, NULL, &errNum), NULL); } (void )WlzFreeObj(shlObj); shlObj = NULL; if(errNum == WLZ_ERR_NONE) { shlObj = tObj; tObj = NULL; } (void )WlzFreeObj(tObj); #ifdef WLZ_DOMOMAINFILL3D_DEBUG { FILE *fP; fP = fopen("debug-shlObj-00.wlz", "w"); (void )WlzWriteObj(fP, shlObj); (void )fclose(fP); } #endif } /* Label the shell domain using 26-connectivity in 3D and then * keep only those component objects which intersect the seed domain. * Then free the shell and seed domains replacing the shell domain * with the union of the intersecting labeled component objects. * Finaly free the intersecting component objects, keeping only the * new shell domain. */ if(errNum == WLZ_ERR_NONE) { int i, j, nCSObj = 0; WlzIBox3 bBox; WlzObject **csObj = NULL; bBox = WlzBoundingBox3I(shlObj, &errNum); if(errNum == WLZ_ERR_NONE) { int maxCSObj; maxCSObj = ((bBox.xMax - bBox.xMin + 1) * (bBox.yMax - bBox.yMin + 1) * (bBox.zMax - bBox.zMin + 1)) / 8; if(maxCSObj < 8) { maxCSObj = 8; } errNum = WlzLabel(shlObj, &nCSObj, &csObj, maxCSObj, 0, WLZ_26_CONNECTED); } if(errNum == WLZ_ERR_NONE) { for(i = 0; i < nCSObj; ++i) { if(!WlzHasIntersection(csObj[i], sedObj, &errNum)) { (void )WlzFreeObj(csObj[i]); csObj[i] = NULL; } } } if(errNum == WLZ_ERR_NONE) { /* Squeeze out any NULL objects reseting their number.*/ for(i = 0, j = 0; i < nCSObj; ++i) { if(csObj[i]) { csObj[j++] = csObj[i]; } } nCSObj = j; } if(errNum == WLZ_ERR_NONE) { WlzObject *iObj = NULL, *uObj = NULL; uObj = WlzAssignObject( WlzUnionN(nCSObj, csObj, 0, &errNum), NULL); iObj = WlzAssignObject( WlzIntersect2(uObj, shlObj, &errNum), NULL); (void )WlzFreeObj(uObj); (void )WlzFreeObj(shlObj); shlObj = iObj; #ifdef WLZ_DOMOMAINFILL3D_DEBUG { FILE *fP; fP = fopen("debug-shlObj-01.wlz", "w"); (void )WlzWriteObj(fP, shlObj); (void )fclose(fP); } #endif } if(csObj) { for(i = 0; i < nCSObj; ++i) { (void )WlzFreeObj(csObj[i]); } (void )AlcFree(csObj); } } /* Sweep down through the boundary lists again creating new boundary lists * which do not have boundaries that do not intersect the new shell domain. * Then create a new filled object from these boundary lists. */ if(errNum == WLZ_ERR_NONE) { int p, nPlnFil; WlzDomain filDom; nPlnFil = shlObj->domain.p->lastpl - shlObj->domain.p->plane1 + 1; filDom.p = WlzMakePlaneDomain(WLZ_PLANEDOMAIN_DOMAIN, shlObj->domain.p->plane1, shlObj->domain.p->lastpl, shlObj->domain.p->line1, shlObj->domain.p->lastln, shlObj->domain.p->kol1, shlObj->domain.p->lastkl, &errNum); #ifdef _OPENMP #pragma omp parallel for shared(bndObj,shlObj) #endif for(p = 0; p < nPlnFil; ++p) { if(errNum == WLZ_ERR_NONE) { WlzDomain bDom2; bDom2 = bndObj->domain.p->domains[p]; if(bDom2.core) { WlzDomain sDom2; WlzObject *fObj2 = NULL; WlzBoundList *newBnd = NULL; WlzErrorNum errNum2 = WLZ_ERR_NONE; sDom2 = shlObj->domain.p->domains[p]; if(sDom2.core) { newBnd = WlzDomFill3DDoBound2D(bDom2.b, sDom2, &errNum2); if(newBnd != NULL) { fObj2 = WlzBoundToObj(newBnd, WLZ_SIMPLE_FILL, &errNum2); (void )WlzFreeBoundList(newBnd); } if(errNum2 == WLZ_ERR_NONE) { if(fObj2) { filDom.p->domains[p] = WlzAssignDomain(fObj2->domain, NULL); } } else { #ifdef _OPENMP #pragma omp critical { #endif if(errNum == WLZ_ERR_NONE) { errNum = errNum2; } #ifdef _OPENMP } #endif } (void )WlzFreeObj(fObj2); } } } } if(errNum == WLZ_ERR_NONE) { errNum = WlzStandardPlaneDomain(filDom.p, NULL); } if(errNum == WLZ_ERR_NONE) { WlzObject *tObj0 = NULL, *tObj1 = NULL; /* Put back any isolated voxels this function has removed. */ tObj0 = WlzAssignObject( WlzMakeMain(srcObj->type, filDom, nullVal, NULL, NULL, &errNum), NULL); if(errNum == WLZ_ERR_NONE) { tObj1 = WlzUnion2(gvnObj, tObj0, &errNum); } if(errNum == WLZ_ERR_NONE) { filObj = WlzMakeMain(tObj1->type, tObj1->domain, nullVal, NULL, NULL, &errNum); } (void )WlzFreeObj(tObj0); (void )WlzFreeObj(tObj1); } } (void )WlzFreeObj(bndObj); (void )WlzFreeObj(gvnObj); (void )WlzFreeObj(shlObj); (void )WlzFreeObj(sedObj); if((errNum != WLZ_ERR_NONE) && (filObj != NULL)) { (void )WlzFreeObj(filObj); filObj = NULL; } if(dstErr) { *dstErr = errNum; } return(filObj); }
/*! * - Function: WlzEffWriteMeshTransform3DWithoutDisplacementVTK * - Returns: none * - Purpose: output the orginal mesh. * - Parameters: * -# *fp: pointer pointing to a specific file. * -# wmt3D: mesh transform. * - Author: J. Rao, R. Baldock and B. Hill */ static void OutPutSectionsForTest( WlzObject *WObjS, WlzObject *WObj2D, /* FILE *outFile; */ char *outFileStr, int iloop, WlzErrorNum *errNum){ WlzGreyValueWSpace *gVWSp; WlzErrorNum wErrN = WLZ_ERR_NONE; WlzGMModel *gM; WlzGMShell *cS, *fS; WlzGMLoopT *cLT, *fLT; WlzGMEdgeT *cET, *fET; WlzDVertex2 *v1, *v2; WlzIBox2 bBoxT; WlzObject *tObj; int ix, jy, kt, intensity; if( ( (WObjS->type) != WLZ_CONTOUR ) ) { wErrN = WLZ_ERR_DOMAIN_TYPE; } if( ( WObj2D->type != WLZ_2D_DOMAINOBJ ) ) { wErrN = WLZ_ERR_DOMAIN_TYPE; } if( ( WObj2D->domain.core == NULL ) ) { wErrN = WLZ_ERR_DOMAIN_NULL; } if(wErrN == WLZ_ERR_NONE) { /* copy it */ tObj = WlzCopyObject(WObj2D, &wErrN); if( wErrN != WLZ_ERR_NONE) { printf("Something wrong with when copy obj "); exit(1); } /* get the bounding box */ bBoxT = WlzBoundingBox2I(tObj, &wErrN); if( wErrN != WLZ_ERR_NONE) { printf("Something wrong with getting bounding box of obj "); exit(1); } /* revise the grey value of it */ gVWSp = WlzGreyValueMakeWSp(tObj, &wErrN); if( wErrN != WLZ_ERR_NONE) { printf("Something wrong with when make warped obj Wsp"); exit(1); } for(ix = bBoxT.xMin; ix <bBoxT.xMax; ix++) { kt = 0; for(jy= bBoxT.yMin; jy< bBoxT.yMax; jy++) { /* GetGreyValue(gVWSp, 0, jy, ix, &intensity, &errNum); */ intensity = 255; FillGreyValue(gVWSp, 0, jy, ix, intensity, &wErrN); } } } /* visualize the data: */ if( wErrN == WLZ_ERR_NONE) { iloop = 1; kt = 0; gM = WObjS->domain.ctr->model; /* For each shell of the model. */ cS = fS = (WlzGMShell *) gM->child; do { printf("Shell %d Shell index %d\n", kt, cS->idx); /* For each loop topology element of the model. */ cLT = fLT = (WlzGMLoopT *) cS->child; kt++; do { printf("Loop index %d\n", cLT->idx); /* For each edge topology element of the model. */ cET = fET = cLT->edgeT; do { if(cET == cET->edge->edgeT) /* Print edge end points */ { v1 = (WlzDVertex2 *) cET->vertexT->diskT->vertex->geo.vg2D; v2 = (WlzDVertex2 *) cET->opp->vertexT->diskT->vertex->geo.vg2D; /* printf("%lg %lg\n",cET->vertexT->diskT->vertex->geo.vg2D->vtx.vtX, \ cET->vertexT->diskT->vertex->geo.vg2D->vtx.vtY ); printf("%lg %lg\n",cET->opp->vertexT->diskT->vertex->geo.vg2D->vtx.vtX, \ cET->opp->vertexT->diskT->vertex->geo.vg2D->vtx.vtY ); */ /* if(kt%3 == iloop) */ { ix = (int) cET->vertexT->diskT->vertex->geo.vg2D->vtx.vtX; jy = (int) cET->vertexT->diskT->vertex->geo.vg2D->vtx.vtY; printf("idx %d ix %d iy %d\n", cET->vertexT->diskT->vertex->idx, ix, jy); intensity = kt * 40; FillGreyValue(gVWSp, 0, jy, ix, intensity, &wErrN); ix = (int) cET->opp->vertexT->diskT->vertex->geo.vg2D->vtx.vtX; jy = (int) cET->opp->vertexT->diskT->vertex->geo.vg2D->vtx.vtY; printf("idx %d ix %d iy %d\n", cET->opp->vertexT->diskT->vertex->idx, ix, jy); FillGreyValue(gVWSp, 0, jy, ix, intensity, &wErrN); } } cET = cET->next; } while (cET != fET); cLT = cLT->next; } while(cLT != fLT); cS = cS->next; } while(cS != fS ); } if((outFile = fopen(outFileStr, "w")) == NULL ) { printf("cannot open the output woolz file.\n"); exit(1); } if( ( wErrN = WlzWriteObj(outFile, tObj) ) != WLZ_ERR_NONE ) { printf("output Woolz Object Error.\n"); fclose(outFile); exit(1); } fclose(outFile); outFile = NULL; WlzGreyValueFreeWSp(gVWSp); }
/*! * \return Transformed object. * \ingroup WlzTransform * \brief Transform an object using the given view-transform. * Typically this is for mapping section data back into * the 3D space of the reference image/reconstruction. * \param srcObj Given source object. * \param viewStr Given view transform. * \param dstErr Destination error pointer, may be NULL. */ WlzObject *Wlz3DViewTransformObj( WlzObject *srcObj, WlzThreeDViewStruct *viewStr, WlzErrorNum *dstErr) { WlzErrorNum errNum=WLZ_ERR_NONE; AlcErrno alcErr = ALC_ER_NONE; WlzObject *dstObj=NULL; int area; int i, k, p, xp, yp, line; int plane1, lastpl, line1, lastln, kol1, lastkl; WlzIVertex3 *vertices; int numVtxs, vtxIdx; WlzIntervalWSpace iwsp; WlzGreyWSpace gwsp; WlzDomain domain, tmpDomain; WlzValues values; int numInts, itvlFlg; WlzInterval *itvl; /* check the object */ if( srcObj == NULL ) { errNum = WLZ_ERR_OBJECT_NULL; } else { switch( srcObj->type ) { case WLZ_2D_DOMAINOBJ: if( srcObj->domain.core == NULL ) { errNum = WLZ_ERR_DOMAIN_NULL; } area = WlzArea(srcObj, &errNum); if( area == 0 ) { dstObj = WlzMakeEmpty(&errNum); } break; case WLZ_2D_POLYGON: /* to be done at some time to 3D polyline */ case WLZ_BOUNDLIST: /* convert to 3D polylines */ case WLZ_TRANS_OBJ: errNum = WLZ_ERR_OBJECT_TYPE; break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } /* create the voxel list */ if( (errNum == WLZ_ERR_NONE) && (dstObj == NULL) ) { numVtxs = sizeof(WlzIVertex3) * (area+4); vertices = AlcMalloc(sizeof(WlzIVertex3) * (area+4)); numVtxs = 0; if( vertices ) { errNum = WlzInitRasterScan(srcObj, &iwsp, WLZ_RASTERDIR_ILIC); } else { errNum = WLZ_ERR_MEM_ALLOC; } if( errNum == WLZ_ERR_NONE ) { while( (errNum = WlzNextInterval(&iwsp)) == WLZ_ERR_NONE ) { float x, y, z; if((iwsp.linpos < (int) viewStr->minvals.vtY) || (iwsp.linpos > (int) viewStr->maxvals.vtY)) { continue; } yp = iwsp.linpos - (int) viewStr->minvals.vtY; for(k=iwsp.lftpos; k <= iwsp.rgtpos; k++) { if((k < (int) viewStr->minvals.vtX) || (k > (int) viewStr->maxvals.vtX)) { continue; } xp = k - (int) viewStr->minvals.vtX; x = (float )(viewStr->xp_to_x[xp] + viewStr->yp_to_x[yp]); y = (float )(viewStr->xp_to_y[xp] + viewStr->yp_to_y[yp]); z = (float )(viewStr->xp_to_z[xp] + viewStr->yp_to_z[yp]); vertices[numVtxs].vtX = WLZ_NINT(x); vertices[numVtxs].vtY = WLZ_NINT(y); vertices[numVtxs].vtZ = WLZ_NINT(z); numVtxs++; } } if(errNum == WLZ_ERR_EOO) /* Reset error from end of object */ { errNum = WLZ_ERR_NONE; } } } /* sort wrt planes, lines, kols */ if( (errNum == WLZ_ERR_NONE) && (dstObj == NULL) ) { qsort((void *) vertices, (size_t) numVtxs, sizeof(WlzIVertex3), compareVtxVal); /* create planedomain */ plane1 = vertices[0].vtZ; lastpl = vertices[numVtxs - 1].vtZ; line1 = vertices[0].vtY; lastln = line1; kol1 = vertices[0].vtX; lastkl = kol1; for(i=1; i < numVtxs; i++) { if( kol1 > vertices[i].vtX ) { kol1 = vertices[i].vtX; } if( lastkl < vertices[i].vtX ) { lastkl = vertices[i].vtX; } if( line1 > vertices[i].vtY ) { line1 = vertices[i].vtY; } if( lastln < vertices[i].vtY ) { lastln = vertices[i].vtY; } } if( (domain.p = WlzMakePlaneDomain(WLZ_PLANEDOMAIN_DOMAIN, plane1, lastpl, line1, lastln, kol1, lastkl, &errNum)) == NULL ) { AlcFree((void *) vertices); } } /* for each plane count intervals and make domain */ if( (errNum == WLZ_ERR_NONE) && (dstObj == NULL) ) { vtxIdx = 0; for(p=plane1; p <= lastpl; p++) { /* increment vertex index to current plane */ while( vertices[vtxIdx].vtZ < p ) { vtxIdx++; } /* check for empty domain */ if( vertices[vtxIdx].vtZ > p ) { domain.p->domains[p - plane1].i = NULL; continue; } /* estimate intervals - foreach pixel add one, foreach adjacent pixel on the same line subtract one */ numInts = 1; kol1 = vertices[vtxIdx].vtX; lastkl = kol1; for(i=vtxIdx+1; i < numVtxs; i++) { if( vertices[i].vtZ > p ) { break; } numInts++; if((vertices[i].vtY == vertices[i-1].vtY) && ((vertices[i].vtX == (vertices[i-1].vtX)) || (vertices[i].vtX == (vertices[i-1].vtX + 1)) )) { numInts--; } if(kol1 > vertices[i].vtX) { kol1 = vertices[i].vtX; } if(lastkl < vertices[i].vtX) { lastkl = vertices[i].vtX; } } line1 = vertices[vtxIdx].vtY; lastln = vertices[i-1].vtY; /* make the domain and add the intervals pointer */ tmpDomain.i = WlzMakeIntervalDomain(WLZ_INTERVALDOMAIN_INTVL, line1, lastln, kol1, lastkl, &errNum); itvl = (WlzInterval *) AlcMalloc(sizeof(WlzInterval)*numInts); tmpDomain.i->freeptr = AlcFreeStackPush(tmpDomain.i->freeptr, (void *) itvl, &alcErr); if(alcErr != ALC_ER_NONE) { errNum = WLZ_ERR_MEM_ALLOC; } /* one more loop to add the intervals */ itvl->ileft = vertices[vtxIdx].vtX - kol1; line = vertices[vtxIdx].vtY; itvlFlg = 1; /* interval started */ numInts = 1; for(i=vtxIdx+1; i < numVtxs; i++) { /* new plane -> interval finished if started */ if( vertices[i].vtZ > p ) { if( itvlFlg ) { itvl[numInts-1].iright = vertices[i-1].vtX - kol1; WlzMakeInterval(line, tmpDomain.i, numInts, itvl); itvl += numInts; itvlFlg = 0; /* interval finished */ numInts = 0; } break; } /* check if new interval */ if( !itvlFlg ) { itvl->ileft = vertices[i].vtX - kol1; line = vertices[i].vtY; itvlFlg = 1; numInts = 1; continue; /* no further tests */ } /* check for gap - increment interval count */ if((vertices[i].vtY == line) && ((vertices[i].vtX - vertices[i-1].vtX) > 1)) { itvl[numInts-1].iright = vertices[i-1].vtX - kol1; numInts++; itvl[numInts-1].ileft = vertices[i].vtX - kol1; itvlFlg = 1; } /* check for new-line */ if( line < vertices[i].vtY ) { itvl[numInts-1].iright = vertices[i-1].vtX - kol1; WlzMakeInterval(line, tmpDomain.i, numInts, itvl); itvl += numInts; itvl->ileft = vertices[i].vtX - kol1; line = vertices[i].vtY; itvlFlg = 1; numInts = 1; } } /* complete the last interval */ if( itvlFlg ) { itvl[numInts-1].iright = vertices[i-1].vtX - kol1; WlzMakeInterval(line, tmpDomain.i, numInts, itvl); itvl += numInts; } /* add the domain to the planedomain */ domain.p->domains[p - plane1] = WlzAssignDomain(tmpDomain, &errNum); (void) WlzIntervalCount(tmpDomain.i, 0); } } /* create the new object */ if( (errNum == WLZ_ERR_NONE) && (dstObj == NULL) ) { values.core = NULL; dstObj = WlzMakeMain(WLZ_3D_DOMAINOBJ, domain, values, NULL, NULL, &errNum); } /* check for grey-level data */ if((errNum == WLZ_ERR_NONE) && dstObj && (dstObj->type != WLZ_EMPTY_OBJ) && srcObj->values.core ) { WlzPixelV bckgrnd; WlzObject *tmpObj; WlzValues tmpValues; WlzDVertex3 vtx; WlzGreyValueWSpace *gVWSp = NULL; WlzObjectType valueTbType; /* explicit intialisation to satisfy strict ANSI on SGI */ bckgrnd = WlzGetBackground(srcObj, &errNum); valueTbType = WlzGreyTableType(WLZ_GREY_TAB_RAGR, bckgrnd.type, NULL); /* make a voxel table */ values.vox = WlzMakeVoxelValueTb(WLZ_VOXELVALUETABLE_GREY, plane1, lastpl, bckgrnd, NULL, &errNum); dstObj->values = WlzAssignValues(values, &errNum); /* set up grey-value random access to original and loop through planes setting values */ gVWSp = WlzGreyValueMakeWSp(srcObj, NULL); for(p=plane1; p <= lastpl; p++) { /* check for empty domain */ if( domain.p->domains[p-plane1].core == NULL ) { continue; } /* make a value table */ tmpObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, domain.p->domains[p-plane1], values.vox->values[p-plane1], NULL, NULL, &errNum); tmpValues.v = WlzNewValueTb(tmpObj, valueTbType, bckgrnd, &errNum); values.vox->values[p-plane1] = WlzAssignValues(tmpValues, &errNum); tmpObj->values = WlzAssignValues(tmpValues, &errNum); /* transfer values */ errNum = WlzInitGreyScan(tmpObj, &iwsp, &gwsp); while((errNum == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&iwsp)) == WLZ_ERR_NONE)) { for(i=0; i<iwsp.colrmn; i++) { vtx.vtX = iwsp.colpos + i; vtx.vtY = iwsp.linpos; vtx.vtZ = p; Wlz3DSectionTransformVtx(&vtx, viewStr); WlzGreyValueGet(gVWSp, 0.0, WLZ_NINT(vtx.vtY), WLZ_NINT(vtx.vtX)); switch( gwsp.pixeltype ) { case WLZ_GREY_LONG: *(gwsp.u_grintptr.lnp+i) = gVWSp->gVal[0].lnv; break; case WLZ_GREY_INT: *(gwsp.u_grintptr.inp+i) = gVWSp->gVal[0].inv; break; case WLZ_GREY_SHORT: *(gwsp.u_grintptr.shp+i) = gVWSp->gVal[0].shv; break; case WLZ_GREY_UBYTE: *(gwsp.u_grintptr.ubp+i) = gVWSp->gVal[0].ubv; break; case WLZ_GREY_FLOAT: *(gwsp.u_grintptr.flp+i) = gVWSp->gVal[0].flv; break; case WLZ_GREY_DOUBLE: *(gwsp.u_grintptr.dbp+i) = gVWSp->gVal[0].dbv; break; case WLZ_GREY_RGBA: *(gwsp.u_grintptr.rgbp+i) = gVWSp->gVal[0].rgbv; break; case WLZ_GREY_BIT: /* not sure what to do with these */ default: break; } } } if(errNum == WLZ_ERR_EOO) /* Reset error from end of object */ { errNum = WLZ_ERR_NONE; } WlzFreeObj(tmpObj); } WlzGreyValueFreeWSp(gVWSp); } /* clean temp allocation */ if( vertices ) { AlcFree((void *) vertices); } if( dstErr ) { *dstErr = errNum; } return dstObj; }
XImage *HGU_XmObjToXImageLut2D( XWindowAttributes *win_att, WlzObject *obj, HGU_XmLut lut, WlzErrorNum *dstErr) { XImage *rtnImage=NULL; Dimension width, height; WlzUByte *data, *dst_data; WlzGreyValueWSpace *gVWSp = NULL; WlzErrorNum errNum=WLZ_ERR_NONE; int i, j; int rIndx=0, gIndx=0, bIndx=0, aIndx=0; WlzUInt r, g, b, a; /* allocate space for the data */ width = obj->domain.i->lastkl - obj->domain.i->kol1 + 1; height = obj->domain.i->lastln - obj->domain.i->line1 + 1; if( (gVWSp = WlzGreyValueMakeWSp(obj, &errNum)) ) { if( (data = (WlzUByte *) AlcMalloc(((win_att->depth == 8)?1:4) *width*height*sizeof(char))) ) { dst_data = data; if( (rtnImage = XCreateImage(DisplayOfScreen(win_att->screen), win_att->visual, win_att->depth, ZPixmap, 0, (char *) dst_data, width, height, 8, 0)) ) { /* establish rgb index values if 24 bit */ if( win_att->depth == 24 ) { rIndx = HGU_XmGetColorIndexFromMask24(win_att->visual->red_mask, rtnImage->byte_order); gIndx = HGU_XmGetColorIndexFromMask24(win_att->visual->green_mask, rtnImage->byte_order); bIndx = HGU_XmGetColorIndexFromMask24(win_att->visual->blue_mask, rtnImage->byte_order); aIndx = HGU_XmGetColorIndexFromMask24(~(win_att->visual->red_mask| win_att->visual->green_mask| win_att->visual->blue_mask), rtnImage->byte_order); } /* fill in the values */ a = 0xff; for(j=0; j < height; j++) { for(i=0; i < width; i++, data++) { WlzGreyValueGet(gVWSp, 0, j + obj->domain.i->line1, i + obj->domain.i->kol1); switch( gVWSp->gType ) { default: case WLZ_GREY_INT: r = *(gVWSp->gPtr[0].inp); g = b = r; break; case WLZ_GREY_SHORT: r = *(gVWSp->gPtr[0].shp); g = b = r; break; case WLZ_GREY_UBYTE: r = *(gVWSp->gPtr[0].ubp); g = b = r; break; case WLZ_GREY_FLOAT: r = *(gVWSp->gPtr[0].flp); g = b = r; break; case WLZ_GREY_DOUBLE: r = *(gVWSp->gPtr[0].dbp); g = b = r; break; case WLZ_GREY_RGBA: b = *(gVWSp->gPtr[0].rgbp); r = WLZ_RGBA_RED_GET(b); g = WLZ_RGBA_GREEN_GET(b); b = WLZ_RGBA_BLUE_GET(b); break; } switch( lut.core->type ) { case HGU_XmLUT_GREY: r = lut.g->lut[r - lut.g->min]; g = lut.g->lut[g - lut.g->min]; b = lut.g->lut[b - lut.g->min]; break; case HGU_XmLUT_RGB: r = lut.rgb->lut[0][r - lut.rgb->min[0]]; g = lut.rgb->lut[1][g - lut.rgb->min[1]]; b = lut.rgb->lut[2][b - lut.rgb->min[2]]; break; case HGU_XmLUT_COMPOUND: break; } switch( win_att->depth ) { case 24: data[rIndx] = r; data[gIndx] = g; data[bIndx] = b; data[aIndx] = a; data += 3; break; case 8: data[0] = r; break; } } } } else { errNum = WLZ_ERR_UNSPECIFIED; AlcFree((void *) dst_data); } } else { errNum = WLZ_ERR_MEM_ALLOC; } WlzGreyValueFreeWSp(gVWSp); } if( dstErr ) { *dstErr = errNum; } return rtnImage; }
double WlzMixtureValue( WlzObject *obj1, WlzObject *obj2, int numCatRows, int numCatCols, double **mixing, double **contrib, WlzErrorNum *dstErr) { double val, con; WlzObject *tmpObj, *tmpObj1, *tmpObj2; WlzIntervalWSpace iwsp; WlzGreyWSpace gwsp; WlzGreyP gptr; WlzGreyValueWSpace *gVWSp; WlzPixelV minP, maxP; int i; WlzErrorNum errNum=WLZ_ERR_NONE; /* objects must be same type with grey-values */ if( (obj1 == NULL) || (obj2 == NULL) ){ errNum = WLZ_ERR_OBJECT_NULL; } else { switch( obj1->type ){ case WLZ_2D_DOMAINOBJ: if( obj2->type != obj1->type ){ errNum = WLZ_ERR_OBJECT_TYPE; } else { if((obj1->values.core == NULL) || (obj2->values.core == NULL)){ errNum = WLZ_ERR_VALUES_NULL; } else { /* convert to int and check range */ if((tmpObj1 = WlzConvertPix(obj1, WLZ_GREY_INT, &errNum)) != NULL){ errNum = WlzGreyRange(tmpObj1, &minP, &maxP); if( errNum == WLZ_ERR_NONE ){ if((minP.v.inv < 1) || (minP.v.inv > numCatRows) || (maxP.v.inv < 1) || (maxP.v.inv > numCatRows)){ errNum = WLZ_ERR_OBJECT_DATA; WlzFreeObj(tmpObj1); } } else { WlzFreeObj(tmpObj1); } } if((errNum == WLZ_ERR_NONE) && (tmpObj2 = WlzConvertPix(obj2, WLZ_GREY_INT, &errNum)) ){ errNum = WlzGreyRange(tmpObj2, &minP, &maxP); if( errNum == WLZ_ERR_NONE ){ if((minP.v.inv < 1) || (minP.v.inv > numCatCols) || (maxP.v.inv < 1) || (maxP.v.inv > numCatCols)){ errNum = WLZ_ERR_OBJECT_DATA; WlzFreeObj(tmpObj1); WlzFreeObj(tmpObj2); } } else { WlzFreeObj(tmpObj1); WlzFreeObj(tmpObj2); } } } } break; case WLZ_3D_DOMAINOBJ: default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } /* get the intersection region */ if( errNum == WLZ_ERR_NONE ){ if((tmpObj = WlzIntersect2(tmpObj1, tmpObj2, &errNum)) != NULL){ tmpObj->values = WlzAssignValues(tmpObj1->values, &errNum); } else { WlzFreeObj(tmpObj1); WlzFreeObj(tmpObj2); } } /* now calculate the mixture value */ if( errNum == WLZ_ERR_NONE ){ errNum = WlzInitGreyScan(tmpObj, &iwsp, &gwsp); gVWSp = WlzGreyValueMakeWSp(tmpObj2, &errNum); val = 0.0; con = 0.0; while((errNum == WLZ_ERR_NONE) && (errNum = WlzNextGreyInterval(&iwsp)) == WLZ_ERR_NONE ){ gptr = gwsp.u_grintptr; for (i=0; i<iwsp.colrmn; i++, gptr.inp++){ WlzGreyValueGet(gVWSp, 0, iwsp.linpos, iwsp.colpos+i); val += mixing[(*gptr.inp)-1][gVWSp->gVal[0].inv-1]; con += contrib[(*gptr.inp)-1][gVWSp->gVal[0].inv-1]; } } if( errNum == WLZ_ERR_EOO ){ errNum = WLZ_ERR_NONE; } WlzGreyValueFreeWSp(gVWSp); WlzFreeObj(tmpObj); WlzFreeObj(tmpObj1); WlzFreeObj(tmpObj2); } if( dstErr ){ *dstErr = errNum; } if( con > 0.0 ){ return val/con; } else { return 0.0; } }
/*! * \return Rescaled object. * \ingroup WlzTransform * \brief Rescales the given 2D domain object using an integer scale. * \param obj Given object. * \param scale Integer scale factor. * \param expand If zero use \f$\frac{1}{scale}\f$. * \param dstErr Destination error pointer, may be NULL. */ static WlzObject *WlzIntRescaleObj2D( WlzObject *obj, int scale, int expand, WlzErrorNum *dstErr) { WlzObject *rtnObj=NULL; WlzDomain domain; WlzValues values; WlzInterval *intvls; int k1, kl, l1, ll, l, num_intvls; WlzErrorNum errNum=WLZ_ERR_NONE; /* check expand or contract */ if( expand ) { k1 = obj->domain.i->kol1 * scale; kl = obj->domain.i->lastkl * scale + scale - 1; l1 = obj->domain.i->line1 * scale; ll = obj->domain.i->lastln * scale + scale - 1; } else { k1 = obj->domain.i->kol1 / scale; kl = obj->domain.i->lastkl / scale; l1 = obj->domain.i->line1 / scale; ll = obj->domain.i->lastln / scale; } /* create a new object */ if((domain.i = WlzMakeIntervalDomain(obj->domain.i->type, l1, ll, k1, kl, &errNum)) != NULL){ values.core = NULL; rtnObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, domain, values, NULL, NULL, NULL); } /* fill in the intervals */ if( errNum == WLZ_ERR_NONE){ if( domain.i->type == WLZ_INTERVALDOMAIN_INTVL ) { int intvline_offset, max_offset; WlzIntervalLine *intvline; num_intvls = WlzIntervalCount(obj->domain.i, NULL); num_intvls = expand ? num_intvls * scale : num_intvls; intvls = (WlzInterval *)AlcMalloc(sizeof(WlzInterval) * num_intvls); domain.i->freeptr = AlcFreeStackPush(domain.i->freeptr, (void *)intvls, NULL); max_offset = obj->domain.i->lastln - obj->domain.i->line1; for(l=l1; l <= ll; l++) { int i; intvline_offset = (expand?l/scale:l*scale) - obj->domain.i->line1; intvline_offset = WLZ_MAX(intvline_offset, 0); intvline_offset = WLZ_MIN(intvline_offset, max_offset); intvline = obj->domain.i->intvlines + intvline_offset; for(i=0; i < intvline->nintvs; i++) { intvls[i].ileft = (intvline->intvs + i)->ileft; intvls[i].iright = (intvline->intvs + i)->iright; if( expand ) { intvls[i].ileft *= scale; intvls[i].iright *= scale; intvls[i].iright += scale - 1; } else { intvls[i].ileft /= scale; intvls[i].iright /= scale; } } i = check_intvs(intvls, i); WlzMakeInterval(l, domain.i, i, intvls); intvls += i; } (void) WlzStandardIntervalDomain( domain.i ); } } /* create the valuetable */ if( (errNum == WLZ_ERR_NONE) && obj->values.core ) { WlzIntervalWSpace iwsp; WlzGreyWSpace gwsp; WlzPixelV backgrnd; WlzGreyValueWSpace *gVWSp = NULL; WlzGreyType gtype; backgrnd = WlzGetBackground(obj, NULL); if((values.v = WlzNewValueTb(rtnObj, obj->values.v->type, backgrnd, &errNum)) != NULL){ rtnObj->values = WlzAssignValues(values, NULL); /* fill in the grey-values */ errNum = WlzInitGreyScan(rtnObj, &iwsp, &gwsp); if(errNum == WLZ_ERR_NONE) { gVWSp = WlzGreyValueMakeWSp(obj, &errNum); if(errNum == WLZ_ERR_NONE) { gtype = WlzGreyTableTypeToGreyType(obj->values.v->type, NULL); } while((errNum == WLZ_ERR_NONE) && (errNum = WlzNextGreyInterval(&iwsp)) == WLZ_ERR_NONE) { int k; int lp = expand ? iwsp.linpos/scale : iwsp.linpos*scale; for( k=0; k <= (iwsp.rgtpos - iwsp.lftpos); k++ ) { int kp = expand ? (k+iwsp.lftpos)/scale : (k+iwsp.lftpos)*scale; WlzGreyValueGet(gVWSp, 0, (double) lp, (double) kp); switch(gtype) { case WLZ_GREY_INT: gwsp.u_grintptr.inp[k] = (*(gVWSp->gVal)).inv; break; case WLZ_GREY_SHORT: gwsp.u_grintptr.shp[k] = (*(gVWSp->gVal)).shv; break; case WLZ_GREY_UBYTE: gwsp.u_grintptr.ubp[k] = (*(gVWSp->gVal)).ubv; break; case WLZ_GREY_FLOAT: gwsp.u_grintptr.flp[k] = (*(gVWSp->gVal)).flv; break; case WLZ_GREY_DOUBLE: gwsp.u_grintptr.dbp[k] = (*(gVWSp->gVal)).dbv; break; case WLZ_GREY_RGBA: gwsp.u_grintptr.rgbp[k] = (*(gVWSp->gVal)).rgbv; break; default: errNum = WLZ_ERR_GREY_TYPE; break; } } } if( errNum == WLZ_ERR_EOO ){ errNum = WLZ_ERR_NONE; } WlzGreyValueFreeWSp(gVWSp); (void )WlzEndGreyScan(&iwsp, &gwsp); } } } if( dstErr ){ *dstErr = errNum; } return rtnObj; }
/*! * \return New filtered object with new values or NULL on error. * \ingroup WlzValuesFilters * \brief Applies a seperable filter along the y axis (lines) * to the given object using the given convolution kernel. * \param inObj Input 2 or 3D spatial domain object * to be filtered which must have scalar * values. * \param dim Object's dimension. * \param maxThr Maximum number of threads to use. * \param iBuf Working buffers large enough for any * column in the image with one for each * thread. * \param rBuf Buffers as for iBuf. * \param cBufSz Convolution kernel size. * \param cBuf Convolution kernel buffer. * \param pad Type of padding. * \param padVal Padding value. * \param dstErr Destination error pointer may be NULL. */ static WlzObject *WlzSepFilterY(WlzObject *inObj, int dim, int maxThr, double **iBuf, double **rBuf, int cBufSz, double *cBuf, AlgPadType pad, double padVal, WlzErrorNum *dstErr) { int idp, poff, nPln; WlzObjectType rGTT; WlzDomain *domains; WlzValues *iVal, *rVal; WlzPixelV zV; WlzObject *rnObj = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; zV.v.dbv = 0.0; zV.type = WLZ_GREY_DOUBLE; rGTT = WlzGreyTableType(WLZ_GREY_TAB_RAGR, WLZ_GREY_DOUBLE, NULL); if(dim == 3) { WlzPlaneDomain *pDom; WlzVoxelValues *vVal; pDom = inObj->domain.p; vVal = inObj->values.vox; nPln = pDom->lastpl - pDom->plane1 + 1; domains = pDom->domains; iVal = vVal->values; poff = pDom->plane1 - vVal->plane1; rnObj = WlzNewObjectValues(inObj, rGTT, zV, 1, zV, &errNum); if(errNum == WLZ_ERR_NONE) { rVal = rnObj->values.vox->values; } } else { nPln = 1; poff = 0; domains = &(inObj->domain); iVal = &(inObj->values); rnObj = WlzNewObjectValues(inObj, rGTT, zV, 1, zV, &errNum); if(errNum == WLZ_ERR_NONE) { rVal = &(rnObj->values); } } if(errNum == WLZ_ERR_NONE) { #ifdef _OPENMP #pragma omp parallel for num_threads(maxThr) #endif for(idp = 0; idp < nPln; ++idp) { if(errNum == WLZ_ERR_NONE) { if(domains[idp].core != NULL) { int thrId = 0; WlzIBox2 bBox; WlzObject *iObj = NULL, *rObj = NULL; WlzGreyValueWSpace *iVWSp = NULL, *rVWSp = NULL; WlzErrorNum errNum2 = WLZ_ERR_NONE; #ifdef _OPENMP thrId = omp_get_thread_num(); #endif iObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, domains[idp], iVal[idp + poff], NULL, NULL, &errNum); if(errNum == WLZ_ERR_NONE) { rObj = WlzMakeMain(WLZ_2D_DOMAINOBJ, domains[idp], rVal[idp], NULL, NULL, &errNum); } if(errNum == WLZ_ERR_NONE) { bBox = WlzBoundingBox2I(iObj, &errNum); } if((errNum == WLZ_ERR_NONE) && ((iVWSp = WlzGreyValueMakeWSp(iObj, &errNum)) != NULL) && ((rVWSp = WlzGreyValueMakeWSp(rObj, &errNum)) != NULL)) { int idx; for(idx = bBox.xMin; idx <= bBox.xMax; ++idx) { int y0, y1, idy; WlzUByte in = 0; for(idy = bBox.yMin; idy <= bBox.yMax + 1; ++idy) { WlzGreyValueGet(iVWSp, 0, idy, idx); if(iVWSp->bkdFlag == 0) { double *ibp; if(in == 0) { y0 = idy; in = 1; } y1 = idy; ibp = iBuf[thrId] + (y1 - y0); switch(iVWSp->gType) { case WLZ_GREY_INT: *ibp = iVWSp->gVal[0].inv; break; case WLZ_GREY_SHORT: *ibp = iVWSp->gVal[0].shv; break; case WLZ_GREY_UBYTE: *ibp = iVWSp->gVal[0].ubv; break; case WLZ_GREY_FLOAT: *ibp = iVWSp->gVal[0].flv; break; case WLZ_GREY_DOUBLE: *ibp = iVWSp->gVal[0].dbv; break; default: break; } } else if(in) { int idr, len; len = y1 - y0 + 1; AlgConvolveD(len, rBuf[thrId], cBufSz * 2 + 1, cBuf, len, iBuf[thrId], pad, padVal); for(idr = y0; idr <= y1; ++idr) { WlzGreyValueGet(rVWSp, 0, idr, idx); *(rVWSp->gPtr[0].dbp) = rBuf[thrId][idr - y0]; } } } } } WlzGreyValueFreeWSp(iVWSp); WlzGreyValueFreeWSp(rVWSp); (void )WlzFreeObj(iObj); (void )WlzFreeObj(rObj); if(errNum2 != WLZ_ERR_NONE) { #ifdef _OPENMP #pragma omp critical { #endif if(errNum == WLZ_ERR_NONE) { errNum = errNum2; } #ifdef _OPENMP } #endif } } } } } if(errNum != WLZ_ERR_NONE) { (void )WlzFreeObj(rnObj); rnObj = NULL; } if(dstErr) { *dstErr = errNum; } return(rnObj); }
/*! * \return New filtered object with new values or NULL on error. * \ingroup WlzValuesFilters * \brief Applies a seperable filter along the z axis (planes) * to the given object using the given convolution kernel. * \param inObj Input 3D spatial domain object to be * filtered which must have scalar values. * \param bBox Object's bounding box. * \param maxThr Maximum number of threads to use. * \param iBuf Working buffers large enough for any * column in the image with one for each * thread. * \param rBuf Buffers as for iBuf. * \param cBufSz Convolution kernel size. * \param cBuf Convolution kernel buffer. * \param pad Type of padding. * \param padVal Padding value. * \param dstErr Destination error pointer may be NULL. */ static WlzObject *WlzSepFilterZ(WlzObject *inObj, WlzIBox3 bBox, int maxThr, double **iBuf, double **rBuf, int cBufSz, double *cBuf, AlgPadType pad, double padVal, WlzErrorNum *dstErr) { WlzObjectType rGTT; WlzPixelV zV; WlzObject *rnObj = NULL; WlzGreyValueWSpace **iVWSp = NULL, **rVWSp = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; zV.v.dbv = 0.0; zV.type = WLZ_GREY_DOUBLE; rGTT = WlzGreyTableType(WLZ_GREY_TAB_RAGR, WLZ_GREY_DOUBLE, NULL); rnObj = WlzNewObjectValues(inObj, rGTT, zV, 1, zV, &errNum); if(errNum == WLZ_ERR_NONE) { if(((iVWSp = (WlzGreyValueWSpace **) AlcCalloc(maxThr, sizeof(WlzGreyValueWSpace *))) == NULL) || ((rVWSp = (WlzGreyValueWSpace **) AlcCalloc(maxThr, sizeof(WlzGreyValueWSpace *))) == NULL)) { errNum = WLZ_ERR_MEM_ALLOC; } } if(errNum == WLZ_ERR_NONE) { int idt; for(idt = 0; (idt < maxThr) && (errNum == WLZ_ERR_NONE); ++idt) { iVWSp[idt] = WlzGreyValueMakeWSp(inObj, &errNum); if(errNum == WLZ_ERR_NONE) { rVWSp[idt] = WlzGreyValueMakeWSp(rnObj, &errNum); } } } if(errNum == WLZ_ERR_NONE) { int idy; #ifdef _OPENMP #pragma omp parallel for num_threads(maxThr) #endif for(idy = bBox.yMin; idy <= bBox.yMax; ++idy) { int idx, thrId = 0; WlzGreyValueWSpace *iVWSpT, *rVWSpT; #ifdef _OPENMP thrId = omp_get_thread_num(); #endif iVWSpT = iVWSp[thrId]; rVWSpT = rVWSp[thrId]; for(idx = bBox.xMin; idx <= bBox.xMax; ++idx) { int z0, z1, idz; WlzUByte in = 0; for(idz = bBox.zMin; idz <= bBox.zMax + 1; ++idz) { WlzGreyValueGet(iVWSpT, idz, idy, idx); if(iVWSpT->bkdFlag == 0) { double *ibp; if(in == 0) { z0 = idz; in = 1; } z1 = idz; ibp = iBuf[thrId] + (z1 - z0); switch(iVWSpT->gType) { case WLZ_GREY_INT: *ibp = iVWSpT->gVal[0].inv; break; case WLZ_GREY_SHORT: *ibp = iVWSpT->gVal[0].shv; break; case WLZ_GREY_UBYTE: *ibp = iVWSpT->gVal[0].ubv; break; case WLZ_GREY_FLOAT: *ibp = iVWSpT->gVal[0].flv; break; case WLZ_GREY_DOUBLE: *ibp = iVWSpT->gVal[0].dbv; break; default: break; } } else if(in) { int idr, len; len = z1 - z0 + 1; AlgConvolveD(len, rBuf[thrId], cBufSz * 2 + 1, cBuf, len, iBuf[thrId], pad, padVal); for(idr = z0; idr <= z1; ++idr) { WlzGreyValueGet(rVWSpT, idr, idy, idx); *(rVWSpT->gPtr[0].dbp) = rBuf[thrId][idr - z0]; } } } } } } if(iVWSp) { int idt; for(idt = 0; idt < maxThr; ++idt) { WlzGreyValueFreeWSp(iVWSp[idt]); } AlcFree(iVWSp); } if(rVWSp) { int idt; for(idt = 0; idt < maxThr; ++idt) { WlzGreyValueFreeWSp(rVWSp[idt]); } AlcFree(rVWSp); } if(errNum != WLZ_ERR_NONE) { (void )WlzFreeObj(rnObj); rnObj = NULL; } if(dstErr) { *dstErr = errNum; } return(rnObj); }
/*! * \return Grey value work space or NULL on error. * \ingroup WlzAccess * \brief Creates a grey value work space from the given object. * The resulting grey value work space should be freed * using WlzGreyValueFreeWSp(). * \param obj Given object. * \param dstErrNum Destination error pointer, may be NULL. */ WlzGreyValueWSpace *WlzGreyValueMakeWSp(WlzObject *obj, WlzErrorNum *dstErrNum) { int planeIdx, numPlanes; WlzDomain *planeDomains; WlzValues *planeValues; WlzObjectType gTabType0, gTabType1 = WLZ_DUMMY_ENTRY; WlzGreyType gType0 = WLZ_GREY_ERROR, gType1 = WLZ_GREY_ERROR; WlzPixelV bkdPix; WlzAffineTransform *trans0, *trans1; WlzGreyValueWSpace *gVWSp = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; bkdPix.v.ubv = 0; bkdPix.type = WLZ_GREY_INT; WLZ_DBG((WLZ_DBG_LVL_1), ("WlzGreyValueMakeWSp FE %p %p\n", obj, dstErrNum)); if(obj == NULL) { errNum = WLZ_ERR_PARAM_DATA; } else { 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((gVWSp = (WlzGreyValueWSpace *)AlcCalloc(1, sizeof(WlzGreyValueWSpace))) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } else { gVWSp->objType = obj->type; gVWSp->values = obj->values; gVWSp->gType = WlzGreyTableTypeToGreyType(obj->values.core->type, &errNum); if(errNum == WLZ_ERR_NONE) { gVWSp->gTabType = WlzGreyTableTypeToTableType( obj->values.core->type, &errNum); gVWSp->gTabType2D = gVWSp->gTabType; } if(errNum == WLZ_ERR_NONE) { switch(gVWSp->gTabType2D) { case WLZ_GREY_TAB_RAGR: gVWSp->values2D = obj->values; bkdPix = gVWSp->values2D.v->bckgrnd; break; case WLZ_GREY_TAB_RECT: gVWSp->values2D = obj->values; bkdPix = gVWSp->values2D.r->bckgrnd; break; case WLZ_GREY_TAB_INTL: gVWSp->values2D = obj->values; bkdPix = gVWSp->values2D.i->bckgrnd; break; case WLZ_GREY_TAB_TILED: gVWSp->values2D = obj->values; bkdPix = gVWSp->values2D.t->bckgrnd; break; default: errNum = WLZ_ERR_VALUES_TYPE; break; } } if(errNum == WLZ_ERR_NONE) { switch(gVWSp->gType) { case WLZ_GREY_LONG: case WLZ_GREY_INT: case WLZ_GREY_SHORT: case WLZ_GREY_UBYTE: case WLZ_GREY_FLOAT: case WLZ_GREY_DOUBLE: case WLZ_GREY_RGBA: break; default: errNum = WLZ_ERR_GREY_TYPE; break; } } if((gVWSp->gType != bkdPix.type) && (errNum == WLZ_ERR_NONE)) { errNum = WLZ_ERR_VALUES_DATA; } } if(errNum == WLZ_ERR_NONE) { gVWSp->gBkd = bkdPix.v; gVWSp->domain = obj->domain; gVWSp->iDom2D = obj->domain.i; if((gVWSp->iDom2D->type != WLZ_INTERVALDOMAIN_INTVL) && (gVWSp->iDom2D->type != WLZ_INTERVALDOMAIN_RECT)) { errNum = WLZ_ERR_DOMAIN_TYPE; } } break; case WLZ_3D_DOMAINOBJ: if(obj->domain.core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } else if(obj->values.core == NULL) { errNum = WLZ_ERR_VALUES_NULL; } else if(obj->domain.core->type != WLZ_PLANEDOMAIN_DOMAIN) { errNum = WLZ_ERR_DOMAIN_TYPE; } else if((gVWSp = (WlzGreyValueWSpace *)AlcCalloc(1, sizeof(WlzGreyValueWSpace))) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } else { gVWSp->objType = obj->type; gVWSp->domain = obj->domain; gVWSp->values = obj->values; if(WlzGreyTableIsTiled(obj->values.core->type) == WLZ_GREY_TAB_TILED) { gVWSp->gTabType = WLZ_GREY_TAB_TILED; gVWSp->gTabType2D = WLZ_GREY_TAB_TILED; gVWSp->gType = WlzGreyTableTypeToGreyType( obj->values.core->type, &errNum); gVWSp->plane = obj->domain.p->plane1; gVWSp->iDom2D = (*(obj->domain.p->domains)).i; gVWSp->gBkd = obj->values.t->bckgrnd.v; if(obj->values.t->bckgrnd.type != gVWSp->gType) { errNum = WLZ_ERR_VALUES_DATA; } } else { gVWSp->gTabType = WLZ_VOXELVALUETABLE_GREY; /* Put in a list of grey-table types - purely for efficiency to avoid re-computing the type for each voxel request. When table types are no longer computed this in principle could go */ numPlanes = obj->domain.p->lastpl - obj->domain.p->plane1 + 1; if((gVWSp->gTabTypes3D = (WlzObjectType *) AlcCalloc(numPlanes, sizeof(WlzObjectType))) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } if(errNum == WLZ_ERR_NONE) { WlzObjectType *gTabTypes3D; gVWSp->values2D.core = NULL; planeIdx = obj->domain.p->plane1; planeDomains = obj->domain.p->domains; planeValues = obj->values.vox->values; gTabTypes3D = gVWSp->gTabTypes3D; while((planeIdx <= obj->domain.p->lastpl) && (errNum == WLZ_ERR_NONE)) { if(((*planeValues).core) && ((*planeValues).core->type != WLZ_EMPTY_OBJ)) { gType0 = WlzGreyTableTypeToGreyType( (*planeValues).core->type, &errNum); if(errNum == WLZ_ERR_NONE) { gTabType0 = WlzGreyTableTypeToTableType((*planeValues). core->type, &errNum); *gTabTypes3D = gTabType0; } if(errNum == WLZ_ERR_NONE) { if((gType0 != gType1) && (gType1 != WLZ_GREY_ERROR)) { errNum = WLZ_ERR_VALUES_DATA; } else { gType1 = gType0; gTabType1 = gTabType0; if(gVWSp->values2D.core == NULL) { gVWSp->plane = planeIdx; gVWSp->iDom2D = (*planeDomains).i; gVWSp->values2D = *planeValues; } } } } ++planeIdx; ++planeDomains; ++planeValues; ++gTabTypes3D; } if((gType1 == WLZ_GREY_ERROR) || (gTabType1 == WLZ_DUMMY_ENTRY)) { errNum = WLZ_ERR_VALUES_DATA; } } if(errNum == WLZ_ERR_NONE) { gVWSp->gType = gType0; gVWSp->gTabType2D = gVWSp->gTabTypes3D[0]; switch(gVWSp->gTabType2D) { case WLZ_GREY_TAB_RAGR: bkdPix = gVWSp->values2D.v->bckgrnd; break; case WLZ_GREY_TAB_RECT: bkdPix = gVWSp->values2D.r->bckgrnd; break; case WLZ_GREY_TAB_INTL: bkdPix = gVWSp->values2D.i->bckgrnd; break; case WLZ_GREY_TAB_TILED: bkdPix = gVWSp->values2D.t->bckgrnd; break; default: errNum = WLZ_ERR_VALUES_TYPE; break; } if((gVWSp->gType != bkdPix.type) && (errNum == WLZ_ERR_NONE)) { errNum = WLZ_ERR_VALUES_DATA; } else if((gVWSp->iDom2D->type != WLZ_INTERVALDOMAIN_INTVL) && (gVWSp->iDom2D->type != WLZ_INTERVALDOMAIN_RECT)) { errNum = WLZ_ERR_DOMAIN_TYPE; } else { gVWSp->gBkd = bkdPix.v; } } } } break; case WLZ_TRANS_OBJ: trans0 = NULL; while((errNum == WLZ_ERR_NONE) && (obj->type == WLZ_TRANS_OBJ)) { if(trans0 == NULL) { trans0 = WlzAffineTransformCopy(obj->domain.t, &errNum); } else { if((trans1 = WlzAffineTransformProduct(trans0, obj->domain.t, &errNum)) != NULL) { WlzFreeAffineTransform(trans0); trans0 = trans1; trans1 = NULL; } } if((obj = obj->values.obj) == NULL) { errNum = WLZ_ERR_OBJECT_NULL; } } if(errNum == WLZ_ERR_NONE) { gVWSp = WlzGreyValueMakeWSp(obj, &errNum); } if(errNum == WLZ_ERR_NONE) { gVWSp->invTrans = WlzAffineTransformInverse(trans0, &errNum); } if(trans0) { WlzFreeAffineTransform(trans0); } break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } if((errNum != WLZ_ERR_NONE) && (gVWSp != NULL)) { WlzGreyValueFreeWSp(gVWSp); gVWSp = NULL; } if(dstErrNum) { *dstErrNum = errNum; } WLZ_DBG((WLZ_DBG_LVL_FN|WLZ_DBG_LVL_1), ("WlzGreyValueMakeWSp FX %p\n", gVWSp)); return(gVWSp); }
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); }
/*! * \return New 3D domain object with corresponding WLZ_GREY_RGBA values. * \ingroup WlzValuesUtils * \brief Creates a WLZ_GREY_RGBA valued object from the given compound * array. This is a static function which will always be called * with valid parameters so they aren't checked. * \param cObj Compound array object. * \param cSpc The colour space. * \param dstErr Destination error pointer may be NULL. */ static WlzObject *WlzCompoundToRGBA2D(WlzCompoundArray *cObj, WlzRGBAColorSpace cSpc, WlzErrorNum *dstErr) { int i, j; WlzObject *rtnObj=NULL; WlzPixelV bckgrnd; WlzObject *objs[4]; WlzObjectType vType; WlzUInt b[4]; WlzErrorNum errNum=WLZ_ERR_NONE; /* Make a copy of the object pointers because WlzUnionN() modifies the * array if it contains empty objects. */ for(i = 0; i < 3; ++i) { objs[i] = cObj->o[i]; } rtnObj = WlzUnionN(3, objs, 0, &errNum); if(errNum == WLZ_ERR_NONE) { /* Add an RGBA valuetable, extract background for each channel */ vType = WlzGreyTableType(WLZ_GREY_TAB_RAGR, WLZ_GREY_RGBA, &errNum); for(i=0; (errNum == WLZ_ERR_NONE) && (i < 3); i++) { bckgrnd = WlzGetBackground(cObj->o[i], &errNum); if(errNum == WLZ_ERR_NONE) { errNum = WlzValueConvertPixel(&bckgrnd, bckgrnd, WLZ_GREY_UBYTE); b[i] = bckgrnd.v.ubv; } } } if(errNum == WLZ_ERR_NONE) { WlzValues values; bckgrnd.type = WLZ_GREY_RGBA; WLZ_RGBA_RGBA_SET(bckgrnd.v.rgbv, b[0], b[1], b[2], 255); values.v = WlzNewValueTb(rtnObj, vType, bckgrnd, &errNum); if(values.v != NULL) { rtnObj->values = WlzAssignValues(values, &errNum); } else { (void )WlzFreeObj(rtnObj); rtnObj = NULL; } } /* Transfer values */ if( errNum == WLZ_ERR_NONE) { WlzGreyValueWSpace *gValWSpc[4]; WlzIntervalWSpace iwsp; WlzGreyWSpace gwsp; WlzGreyV gval; /* do it dumb fashion for now, rgb only */ gValWSpc[0] = gValWSpc[1] = gValWSpc[2] = gValWSpc[3] = NULL; for(i=0; i < 3; i++) { if((cObj->o[i] != NULL) && (cObj->o[i]->type != WLZ_EMPTY_OBJ)) { gValWSpc[i] = WlzGreyValueMakeWSp(cObj->o[i], &errNum); if(errNum != WLZ_ERR_NONE) { break; } } } if(errNum == WLZ_ERR_NONE) { errNum = WlzInitGreyScan(rtnObj, &iwsp, &gwsp); } while((errNum == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval(&iwsp)) == WLZ_ERR_NONE)) { WlzPixelV pix; for(j = iwsp.lftpos; j <= iwsp.rgtpos; j++) { for(i = 0; i < 3; i++) { if(gValWSpc[i] == NULL) { pix.v.ubv = (i < 2)? 0: 255; } else { WlzGreyValueGet(gValWSpc[i], 0, iwsp.linpos, j); pix.type = gValWSpc[i]->gType; pix.v = gValWSpc[i]->gVal[0]; WlzValueConvertPixel(&pix, pix, WLZ_GREY_UBYTE); } b[i] = pix.v.ubv; } WLZ_RGBA_RGBA_SET(gval.rgbv, b[0], b[1], b[2], b[3]); *gwsp.u_grintptr.rgbp = gval.rgbv; gwsp.u_grintptr.rgbp++; } } if(errNum == WLZ_ERR_EOO) { errNum = WLZ_ERR_NONE; } for(i=0; i < 3; i++) { WlzGreyValueFreeWSp(gValWSpc[i]); } } if(dstErr != NULL) { *dstErr = errNum; } return(rtnObj); }
void installViewDomains( ThreeDViewStruct *view_struct) { WlzThreeDViewStruct *wlzViewStr= view_struct->wlzViewStr; WlzIntervalWSpace iwsp; WlzGreyWSpace gwsp; WlzGreyValueWSpace *gVWSp = NULL; float x, y, z; int xp, yp; int i; ViewListEntry *vl = global_view_list; WlzErrorNum errNum=WLZ_ERR_NONE; /* all domains on this plane will already have been checked for consistency, dominance etc. therefore simply set the corresponding domains in the painted object */ /* this is the set version of get section and should be in the woolz library. This is probably faster because many assumptions are made, mainly the grey-type */ gVWSp = WlzGreyValueMakeWSp(globals.obj, &errNum); if( errNum == WLZ_ERR_NONE ){ errNum = WlzInitGreyScan( view_struct->painted_object, &iwsp, &gwsp ); while((errNum == WLZ_ERR_NONE) && ((errNum = WlzNextGreyInterval( &iwsp )) == WLZ_ERR_NONE) ) { yp = iwsp.linpos - WLZ_NINT(wlzViewStr->minvals.vtY); for(i=iwsp.lftpos; i <= iwsp.rgtpos; i++){ xp = i - WLZ_NINT(wlzViewStr->minvals.vtX); x = wlzViewStr->xp_to_x[xp] + wlzViewStr->yp_to_x[yp]; y = wlzViewStr->xp_to_y[xp] + wlzViewStr->yp_to_y[yp]; z = wlzViewStr->xp_to_z[xp] + wlzViewStr->yp_to_z[yp]; WlzGreyValueGet(gVWSp, WLZ_NINT(z), WLZ_NINT(y), WLZ_NINT(x)); *(gVWSp->gPtr[0].ubp) = *(gwsp.u_grintptr.ubp); gwsp.u_grintptr.ubp++; } } if( errNum == WLZ_ERR_EOO ){ errNum = WLZ_ERR_NONE; } WlzGreyValueFreeWSp(gVWSp); } /* copy the new domains to the previous domains */ if( errNum == WLZ_ERR_NONE ){ for(i=0; i < 33; i++){ if( view_struct->prev_domain[i] ){ WlzFreeObj(view_struct->prev_domain[i]); view_struct->prev_domain[i] = NULL; } if( view_struct->curr_domain[i] ){ view_struct->prev_domain[i] = WlzAssignObject(view_struct->curr_domain[i], NULL); } } } /* set the previous distance and view object - calculate when needed */ if( errNum == WLZ_ERR_NONE ){ view_struct->prev_dist = wlzViewStr->dist; if( view_struct->prev_view_obj ){ WlzFreeObj(view_struct->prev_view_obj); view_struct->prev_view_obj = NULL; } if( view_struct->view_object ){ view_struct->prev_view_obj = WlzAssignObject(view_struct->view_object, NULL); } else { view_struct->prev_view_obj = NULL; } } /* display all views to update the new domains */ if( errNum == WLZ_ERR_NONE ){ while( vl != NULL ){ if( vl->view_struct != paint_key ){ if( vl->view_struct == view_struct ){ redisplay_view_cb(view_struct->canvas, (XtPointer) vl->view_struct, NULL); } else { display_view_cb(view_struct->canvas, (XtPointer) vl->view_struct, NULL); } } vl = vl->next; } } if( errNum != WLZ_ERR_NONE ){ MAPaintReportWlzError(globals.topl, "installViewDomains", errNum); } return; }
/*! * \return New object with the rojection. * \ingroup WlzTransform * \brief Use the view transform to define a projection from * 3D to 2D and then project the object onto this plane. * The object supplied to this function must be a 3D * spatial domain object (WLZ_3D_DOMAINOBJ) with either * no values or for integration WLZ_GREY_UBYTE values. * Integration will assign each output pixel the sum of * all input voxels mapped via either the domain density * or the voxel density. * The integration is controled by the integrate parameter * with valid values: * WLZ_PROJECT_INT_MODE_NONE - a "shadow domain" without values * is computed, * WLZ_PROJECT_INT_MODE_DOMAIN - the voxels of the domain are * integrated using * \f[ p = \frac{1}{255} n d \f] * WLZ_PROJECT_INT_MODE_VALUES - the voxel values are integrated * using * \f[ p = \frac{1}{255} \sum{l\left[v\right]}. \f] * Where * \f$p\f$ is the projected image value, * \f$n\f$ is the number of voxels projected for \f$p\f$, * \f$d\f$ is the density of domain voxels, * \f$l\f$ is the voxel value density look up table and * \f$v\f$ is a voxel value. * \param obj The given object. * \param vStr Given view structure defining the * projection plane. * \param intMod This may take three values: * WLZ_PROJECT_INT_MODE_NONE, * WLZ_PROJECT_INT_MODE_DOMAIN or * WLZ_PROJECT_INT_MODE_VALUES. * \param denDom Density of domain voxels this value * is not used unless the integration * mode is WLZ_PROJECT_INT_MODE_DOMAIN. * \param denVal Density look up table for object * voxel density values which must be * an array of 256 values. This may be * NULL if the integration mode is not * WLZ_PROJECT_INT_MODE_VALUES. * \param depth If greater than zero, the projection * depth perpendicular to the viewing * plane. * \param dstErr Destination error pointer, may be NULL. */ WlzObject *WlzProjectObjToPlane(WlzObject *obj, WlzThreeDViewStruct *vStr, WlzProjectIntMode intMod, WlzUByte denDom, WlzUByte *denVal, double depth, WlzErrorNum *dstErr) { int nThr = 1, itvVal = 0; WlzIVertex2 prjSz; WlzIBox2 prjBox = {0}; double pln[4]; WlzObject *bufObj = NULL, *prjObj = NULL; WlzThreeDViewStruct *vStr1 = NULL; double **vMat = NULL; WlzValues nullVal; WlzErrorNum errNum = WLZ_ERR_NONE; WlzAffineTransform *rescaleTr = NULL; WlzGreyValueWSpace **gVWSp = NULL; void ***prjAry = NULL; const double eps = 0.000001; #ifdef WLZ_DEBUG_PROJECT3D_TIME struct timeval times[3]; #endif /* WLZ_DEBUG_PROJECT3D_TIME */ nullVal.core = NULL; 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; } else if(vStr == NULL) { errNum = WLZ_ERR_TRANSFORM_NULL; } else if((intMod == WLZ_PROJECT_INT_MODE_VALUES) && (obj->values.core == NULL)) { errNum = WLZ_ERR_VALUES_NULL; } #ifdef WLZ_DEBUG_PROJECT3D_TIME gettimeofday(times + 0, NULL); #endif /* WLZ_DEBUG_PROJECT3D_TIME */ /* Create new view transform without voxel scaling. The voxel scaling * is done after the projection. */ if(errNum == WLZ_ERR_NONE) { if((vStr1 = WlzMake3DViewStruct(WLZ_3D_VIEW_STRUCT, &errNum)) != NULL) { vStr1->fixed = vStr->fixed; vStr1->theta = vStr->theta; vStr1->phi = vStr->phi; vStr1->zeta = vStr->zeta; vStr1->dist = vStr->dist; vStr1->scale = vStr->scale; vStr1->voxelSize[0] = 1.0; vStr1->voxelSize[1] = 1.0; vStr1->voxelSize[2] = 1.0; vStr1->voxelRescaleFlg = 0; vStr1->interp = vStr->interp; vStr1->view_mode = vStr->view_mode; vStr1->up = vStr->up; vStr1->initialised = WLZ_3DVIEWSTRUCT_INIT_NONE; vMat = vStr1->trans->mat; errNum = WlzInit3DViewStructAffineTransform(vStr1); if(errNum == WLZ_ERR_NONE) { errNum = Wlz3DViewStructTransformBB(obj, vStr1); } if(errNum != WLZ_ERR_NONE) { WlzFree3DViewStruct(vStr1); vStr1 = NULL; } } } /* Compute bounding box of the projection. */ if(errNum == WLZ_ERR_NONE) { prjBox.xMin = WLZ_NINT(vStr1->minvals.vtX); prjBox.yMin = WLZ_NINT(vStr1->minvals.vtY); prjBox.xMax = WLZ_NINT(vStr1->maxvals.vtX); prjBox.yMax = WLZ_NINT(vStr1->maxvals.vtY); prjSz.vtX = prjBox.xMax - prjBox.xMin + 1; prjSz.vtY = prjBox.yMax - prjBox.yMin + 1; } /* Compute post projection scaling. */ if((errNum == WLZ_ERR_NONE) && (vStr->voxelRescaleFlg != 0)) { WlzIBox2 sBox; WlzIVertex2 sSz; WlzThreeDViewStruct *vStr2; vStr2 = WlzMake3DViewStruct(WLZ_3D_VIEW_STRUCT, &errNum); if(errNum == WLZ_ERR_NONE) { vStr2->fixed = vStr->fixed; vStr2->theta = vStr->theta; vStr2->phi = vStr->phi; vStr2->zeta = vStr->zeta; vStr2->dist = vStr->dist; vStr2->scale = vStr->scale; vStr2->voxelSize[0] = vStr->voxelSize[0]; vStr2->voxelSize[1] = vStr->voxelSize[1]; vStr2->voxelSize[2] = vStr->voxelSize[2]; vStr2->voxelRescaleFlg = vStr->voxelRescaleFlg; vStr2->interp = vStr->interp; vStr2->view_mode = vStr->view_mode; vStr2->up = vStr->up; vStr2->initialised = WLZ_3DVIEWSTRUCT_INIT_NONE; errNum = WlzInit3DViewStructAffineTransform(vStr2); if(errNum == WLZ_ERR_NONE) { errNum = Wlz3DViewStructTransformBB(obj, vStr2); } if(errNum == WLZ_ERR_NONE) { sBox.xMin = WLZ_NINT(vStr2->minvals.vtX); sBox.yMin = WLZ_NINT(vStr2->minvals.vtY); sBox.xMax = WLZ_NINT(vStr2->maxvals.vtX); sBox.yMax = WLZ_NINT(vStr2->maxvals.vtY); sSz.vtX = sBox.xMax - sBox.xMin + 1; sSz.vtY = sBox.yMax - sBox.yMin + 1; rescaleTr = WlzMakeAffineTransform(WLZ_TRANSFORM_2D_AFFINE, &errNum); } if(errNum == WLZ_ERR_NONE) { double **m; m = rescaleTr->mat; m[0][0] = (sSz.vtX * eps) / (prjSz.vtX * eps); m[1][1] = (sSz.vtY * eps) / (prjSz.vtY * eps); m[0][2] = sBox.xMin - WLZ_NINT(m[0][0] * prjBox.xMin); m[1][2] = sBox.yMin - WLZ_NINT(m[1][1] * prjBox.yMin); } (void )WlzFree3DViewStruct(vStr2); } } /* Compute plane equation, used to clip intervals if depth was given. */ if((errNum == WLZ_ERR_NONE) && (depth > eps)) { Wlz3DViewGetPlaneEqn(vStr1, pln + 0, pln + 1, pln + 2, pln + 3); } /* Create rectangular projection array buffers, one for each thread, * also if integrating values create a grey value workspace per thread. */ if(errNum == WLZ_ERR_NONE) { int idB; #ifdef _OPENMP #pragma omp parallel { #pragma omp master { nThr = omp_get_num_threads(); } } #endif if((prjAry = (void ***)AlcCalloc(nThr, sizeof(void **))) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } else { if(intMod == WLZ_PROJECT_INT_MODE_NONE) { for(idB = 0; idB < nThr; ++idB) { if(AlcUnchar2Calloc((WlzUByte ***)&(prjAry[idB]), prjSz.vtY, prjSz.vtX) != ALC_ER_NONE) { errNum = WLZ_ERR_MEM_ALLOC; break; } } } else { for(idB = 0; idB < nThr; ++idB) { if(AlcInt2Calloc((int ***)&(prjAry[idB]), prjSz.vtY, prjSz.vtX) != ALC_ER_NONE) { errNum = WLZ_ERR_MEM_ALLOC; break; } } } } if((errNum == WLZ_ERR_NONE) && (intMod == WLZ_PROJECT_INT_MODE_VALUES)) { itvVal = (WlzGreyTableIsTiled(obj->values.core->type) == 0); if(itvVal == 0) { if((gVWSp = AlcCalloc(nThr, sizeof(WlzGreyValueWSpace *))) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } else { for(idB = 0; idB < nThr; ++idB) { gVWSp[idB] = WlzGreyValueMakeWSp(obj, &errNum); if(gVWSp[idB]->gType != WLZ_GREY_UBYTE) { errNum = WLZ_ERR_GREY_TYPE; break; } } } } } } /* Scan through the 3D domain setting value in the projection array. */ if(errNum == WLZ_ERR_NONE) { int pIdx, pCnt; WlzDomain *doms; WlzValues *vals = NULL; doms = obj->domain.p->domains; if(itvVal) { vals = obj->values.vox->values; } pCnt = obj->domain.p->lastpl - obj->domain.p->plane1 + 1; #ifdef _OPENMP #pragma omp parallel for #endif for(pIdx = 0; pIdx < pCnt; ++pIdx) { int thrId = 0; if((errNum == WLZ_ERR_NONE) && (doms[pIdx].core != NULL)) { WlzObject *obj2; WlzGreyWSpace gWSp; WlzIntervalWSpace iWSp; WlzErrorNum errNum2 = WLZ_ERR_NONE; #ifdef _OPENMP thrId = omp_get_thread_num(); #endif obj2 = WlzMakeMain(WLZ_2D_DOMAINOBJ, doms[pIdx], (vals)? vals[pIdx]: nullVal, NULL, NULL, &errNum2); if(errNum2 == WLZ_ERR_NONE) { if(itvVal) { errNum2 = WlzInitGreyScan(obj2, &iWSp, &gWSp); } else { errNum2 = WlzInitRasterScan(obj2, &iWSp, WLZ_RASTERDIR_ILIC); } } if(errNum2 == WLZ_ERR_NONE) { double plnZ, vMZX, vMZY; WlzIVertex3 p0, p1; p0.vtZ = p1.vtZ = obj->domain.p->plane1 + pIdx; vMZX = (vMat[0][2] * p0.vtZ) + vMat[0][3] - prjBox.xMin; vMZY = (vMat[1][2] * p0.vtZ) + vMat[1][3] - prjBox.yMin; plnZ = (pln[2] * p0.vtZ) + pln[3]; while(((itvVal == 0) && ((errNum2 = WlzNextInterval(&iWSp)) == WLZ_ERR_NONE)) || ((itvVal != 0) && ((errNum2 = WlzNextGreyInterval(&iWSp)) == WLZ_ERR_NONE))) { int skip = 0; WlzDVertex2 q0, q1; p0.vtX = iWSp.lftpos; p1.vtX = iWSp.rgtpos; p0.vtY = p1.vtY = iWSp.linpos; if(depth > eps) { int c; double d0, d1, plnYZ; /* Clip the 3D line segment p0,p1 using the plane equation. */ plnYZ = (pln[1] * p0.vtY) + plnZ; d0 = (pln[0] * p0.vtX) + plnYZ; d1 = (pln[0] * p1.vtX) + plnYZ; c = ((d1 > depth) << 3) | ((d0 > depth) << 2) | ((d1 < -depth) << 1) | (d0 < -depth); if(c) { if((c == 3) || (c == 12)) /* 00-- or ++00 */ { /* Both out of range, so don't render. */ skip = 1; } else { if(fabs(pln[0]) > eps) { double plnX; plnX = -1.0 / pln[0]; if((c & 1) != 0) /* x0x- */ { p0.vtX = plnX * (plnYZ + depth); } else if((c & 4) != 0) /* x+x0 */ { p0.vtX = plnX * (plnYZ - depth); } if((c & 2) != 0) /* 0x-x */ { p1.vtX = plnX * (plnYZ + depth); } else if((c & 8) != 0) /* +x0x */ { p1.vtX = plnX * (plnYZ - depth); } } } } } if(skip == 0) { q0.vtX = (vMat[0][0] * p0.vtX) + (vMat[0][1] * p0.vtY) + vMZX; q0.vtY = (vMat[1][0] * p0.vtX) + (vMat[1][1] * p0.vtY) + vMZY; q1.vtX = (vMat[0][0] * p1.vtX) + (vMat[0][1] * p1.vtY) + vMZX; q1.vtY = (vMat[1][0] * p1.vtX) + (vMat[1][1] * p1.vtY) + vMZY; switch(intMod) { case WLZ_PROJECT_INT_MODE_NONE: { WlzIVertex2 u0, u1; WLZ_VTX_2_NINT(u0, q0); WLZ_VTX_2_NINT(u1, q1); WlzProjectObjLine((WlzUByte **)(prjAry[thrId]), u0, u1); } break; case WLZ_PROJECT_INT_MODE_DOMAIN: { int np, nq; WlzDVertex3 dq; WlzIVertex2 u0, u1; WLZ_VTX_2_NINT(u0, q0); WLZ_VTX_2_NINT(u1, q1); WLZ_VTX_2_SUB(dq, q0, q1); np = denDom * (iWSp.rgtpos - iWSp.lftpos + 1); nq = (int )ceil(WLZ_VTX_2_LENGTH(dq) + eps); WlzProjectObjLineDom((int **)(prjAry[thrId]), np / nq, u0, u1); } break; case WLZ_PROJECT_INT_MODE_VALUES: if(itvVal) { WlzProjectObjLineVal((int **)(prjAry[thrId]), denVal, gWSp.u_grintptr.ubp, NULL, vMat, vMZX, vMZY, p0, p1); } else { WlzProjectObjLineVal((int **)(prjAry[thrId]), denVal, NULL, gVWSp[thrId], vMat, vMZX, vMZY, p0, p1); } break; } } } (void )WlzEndGreyScan(&iWSp, &gWSp); if(errNum2 == WLZ_ERR_EOO) { errNum2 = WLZ_ERR_NONE; } } (void )WlzFreeObj(obj2); if(errNum2 != WLZ_ERR_NONE) { #ifdef _OPENMP #pragma omp critical { #endif if(errNum == WLZ_ERR_NONE) { errNum = errNum2; } #ifdef _OPENMP } #endif } } } } /* Free grey value workspaces if they were created. */ if(gVWSp) { int idB; for(idB = 0; idB < nThr; ++idB) { WlzGreyValueFreeWSp(gVWSp[idB]); } AlcFree(gVWSp); } if(errNum == WLZ_ERR_NONE) { int idB; size_t idC, bufSz; WlzGreyP buf0, buf1; WlzIVertex2 prjOrg; prjOrg.vtX = prjBox.xMin; prjOrg.vtY = prjBox.yMin; bufSz = prjSz.vtX * prjSz.vtY; for(idB = 1; idB < nThr; ++idB) { if(intMod == WLZ_PROJECT_INT_MODE_NONE) { buf0.ubp = ((WlzUByte ***)(prjAry))[0][0], buf1.ubp = ((WlzUByte ***)(prjAry))[idB][0]; for(idC = 0; idC < bufSz; ++idC) { buf0.ubp[idC] += buf1.ubp[idC]; } } else { buf0.inp = ((int ***)(prjAry))[0][0], buf1.inp = ((int ***)(prjAry))[idB][0]; for(idC = 0; idC < bufSz; ++idC) { buf0.inp[idC] += buf1.inp[idC]; } } } switch(intMod != WLZ_PROJECT_INT_MODE_NONE) { buf0.inp = ((int ***)(prjAry))[0][0]; for(idC = 0; idC < bufSz; ++idC) { buf0.inp[idC] /= 256; } } if(intMod == WLZ_PROJECT_INT_MODE_NONE) { bufObj = WlzAssignObject( WlzFromArray2D((void **)(prjAry[0]), prjSz, prjOrg, WLZ_GREY_UBYTE, WLZ_GREY_UBYTE, 0.0, 1.0, 1, 0, &errNum), NULL); } else { bufObj = WlzAssignObject( WlzFromArray2D((void **)(prjAry[0]), prjSz, prjOrg, WLZ_GREY_INT, WLZ_GREY_INT, 0.0, 1.0, 1, 0, &errNum), NULL); } } /* Free the projection array(s). */ if(prjAry) { int idB; for(idB = 0; idB < nThr; ++idB) { (void )Alc2Free((prjAry[idB])); } AlcFree(prjAry); } /* Make return object using threshold. */ if(errNum == WLZ_ERR_NONE) { WlzPixelV tV; WlzObject *tObj = NULL; tV.type = WLZ_GREY_UBYTE; tV.v.ubv = 1; tObj = WlzAssignObject( WlzThreshold(bufObj, tV, WLZ_THRESH_HIGH, &errNum), NULL); if(tObj) { if(intMod == WLZ_PROJECT_INT_MODE_NONE) { prjObj = WlzMakeMain(tObj->type, tObj->domain, nullVal, NULL, NULL, &errNum); } else { prjObj = WlzMakeMain(tObj->type, tObj->domain, tObj->values, NULL, NULL, &errNum); } } (void )WlzFreeObj(tObj); } (void )WlzFreeObj(bufObj); (void )WlzFree3DViewStruct(vStr1); /* Scale image. */ if(rescaleTr != NULL) { if(errNum == WLZ_ERR_NONE) { WlzObject *tObj = NULL; tObj = WlzAffineTransformObj(prjObj, rescaleTr, WLZ_INTERPOLATION_NEAREST, &errNum); (void )WlzFreeObj(prjObj); prjObj = tObj; } (void )WlzFreeAffineTransform(rescaleTr); } #ifdef WLZ_DEBUG_PROJECT3D_TIME gettimeofday(times + 1, NULL); ALC_TIMERSUB(times + 1, times + 0, times + 2); (void )fprintf(stderr, "WlzGetProjectionFromObject: Elapsed time = %g\n", times[2].tv_sec + (0.000001 * times[2].tv_usec)); #endif /* WLZ_DEBUG_PROJECT3D_TIME */ if(dstErr) { *dstErr = errNum; } return(prjObj); }