diff --git a/warpApp/Db/NDWarp.template b/warpApp/Db/NDWarp.template index bc972e8..f36528e 100644 --- a/warpApp/Db/NDWarp.template +++ b/warpApp/Db/NDWarp.template @@ -79,3 +79,14 @@ record(longout, "$(P)$(R)CenterY") { field(EGU , "px") info(autosaveFields, "VAL") } + +record(mbbo, "$(P)$(R)AutoResize") { + field(DESC, "Auto Resize mode") + field(DTYP, "asynInt32") + field(OUT , "@asyn($(PORT),0)WARP_AUTORESIZE_MODE") + field(PINI, "YES") + field(ZRVL, "0") + field(ONVL, "1") + field(ZRST, "No") + field(ONST, "Yes") +} \ No newline at end of file diff --git a/warpApp/src/NDPluginWarp.cpp b/warpApp/src/NDPluginWarp.cpp index c241468..7c18ad7 100644 --- a/warpApp/src/NDPluginWarp.cpp +++ b/warpApp/src/NDPluginWarp.cpp @@ -3,7 +3,16 @@ * State University (c) Copyright 2016. * * Author: Michael Davidsaver + * + * ############################################################# + * ############################################################# + * + * Contribution RGB and AutoResize + * Author: Guilherme Rodrigues de Lima + * Email: guilherme.lima@lnls.br + * Date: 06/22/2023 */ + #include #include @@ -14,9 +23,6 @@ #include -// pi/180 -#define PI_180 0.017453292519943295 - static bool sameShape(const NDArrayInfo& lhs, const NDArrayInfo& rhs) { @@ -24,7 +30,8 @@ bool sameShape(const NDArrayInfo& lhs, const NDArrayInfo& rhs) return lhs.nElements==rhs.nElements && lhs.xSize==rhs.xSize && lhs.ySize==rhs.ySize - && lhs.colorSize==rhs.colorSize; + && lhs.colorSize==rhs.colorSize + && lhs.colorMode==rhs.colorMode; } NDPluginWarp::NDPluginWarp(const char *portName, int queueSize, int blockingCallbacks, @@ -61,6 +68,8 @@ NDPluginWarp::NDPluginWarp(const char *portName, int queueSize, int blockingCall createParam(NDWarpCenterXString, asynParamInt32, &NDWarpCenterX); createParam(NDWarpCenterYString, asynParamInt32, &NDWarpCenterY); + createParam(NDWarpAutoResizeString, asynParamInt32, &NDWarpAutoResize); // Auto Resize Mode + setStringParam(NDPluginDriverPluginType, "NDPluginWarp"); setDoubleParam(NDWarpFactorX, 0.0); // initialize w/ no-op @@ -68,6 +77,7 @@ NDPluginWarp::NDPluginWarp(const char *portName, int queueSize, int blockingCall setDoubleParam(NDWarpAngle, 0.0); setIntegerParam(NDWarpCenterX, 0); setIntegerParam(NDWarpCenterY, 0); + setIntegerParam(NDWarpAutoResize, 0); } NDPluginWarp::~NDPluginWarp() { @@ -111,12 +121,13 @@ NDPluginWarp::processCallbacks(NDArray *pArray) NDArrayInfo info; (void)pArray->getInfo(&info); - if(pArray->ndims!=2 || info.xSize==0 || info.ySize==0) { + if(info.colorMode == 1 || info.colorMode > 4 || info.xSize==0 || info.ySize==0) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:: 2D non-empty expected", - this->portName); + this->portName); return; } + switch(pArray->dataType) { #define CASE(TYPE) case ND ## TYPE: CASE(Int8) @@ -143,13 +154,17 @@ NDPluginWarp::processCallbacks(NDArray *pArray) epicsTimeStamp before; epicsTimeGetCurrent(&before); - if(!sameShape(info, lastinfo)) { + int autoresize=0; + getIntegerParam(NDWarpAutoResize, &autoresize); + + if(!sameShape(info, lastinfo) || lastautoresize != autoresize) { asynPrint(pasynUserSelf, ASYN_TRACEIO_DRIVER, "%s: input shape changes, recompute mapping\n", this->portName); lastinfo = info; + lastautoresize = autoresize; recalculate_transform(info); - assert(mapping.size() == samp_per_pixel*lastinfo.nElements); + assert(mapping.size() == samp_per_pixel*AutoResize.nElements); } int outputmode=0; @@ -160,10 +175,33 @@ NDPluginWarp::processCallbacks(NDArray *pArray) if(outputmode==0) { // output transformed image - output.reset(cloneArray(pNDArrayPool, pArray)); + //output.reset(cloneArray(pNDArrayPool, pArray)); + + size_t dims[ND_ARRAY_MAX_DIMS]; + if (lastinfo.colorMode == 0) { + dims[0] = AutoResize.xSize; + dims[1] = AutoResize.ySize; + } + else if (lastinfo.colorMode == 2) { + dims[0] = 3; + dims[1] = AutoResize.xSize; + dims[2] = AutoResize.ySize; + } + else if (lastinfo.colorMode == 3) { + dims[0] = AutoResize.xSize; + dims[1] = 3; + dims[2] = AutoResize.ySize; + } + else if (lastinfo.colorMode == 4) { + dims[0] = AutoResize.xSize; + dims[1] = AutoResize.ySize; + dims[2] = 3; + } + + output.reset(pNDArrayPool->alloc(pArray->ndims, dims, pArray->dataType, 0, NULL)); switch(pArray->dataType) { -#define CASE(TYPE) case ND ## TYPE: warpit(pArray, output.get(), &mapping[0], lastinfo.nElements, samp_per_pixel); break; +#define CASE(TYPE) case ND ## TYPE: warpit(pArray, output.get(), &mapping[0], AutoResize.nElements, samp_per_pixel); break; CASE(Int8) CASE(UInt8) CASE(Int16) @@ -188,7 +226,7 @@ NDPluginWarp::processCallbacks(NDArray *pArray) output->getInfo(&info); for(size_t oy=0; oyM.sizex()-1 || x<0.0 || !isfinite(x)) + if(x>lastinfo.xSize-1 || x<0.0 || !isfinite(x)) { M.x(i,j) = std::numeric_limits::quiet_NaN(); - - if(y>M.sizey()-1 || y<0.0 || !isfinite(y)) + } + if(y>lastinfo.ySize-1 || y<0.0 || !isfinite(y)) { M.y(i,j) = std::numeric_limits::quiet_NaN(); + } } } - // interpolate and collapse user 2D Mapping to 1D 'mapping' (from offset to offset) Sample * const S = &mapping[0]; @@ -343,56 +417,136 @@ void NDPluginWarp::recalculate_transform(const NDArrayInfo& info) case Nearest: { assert(samp_per_pixel==1); for(size_t j=0; jweight = 1.0; + SX->index = Ioffset; + SX->valid = isfinite(x) && isfinite(y); - SX->weight = 1.0; - SX->index = Ioffset; - SX->valid = isfinite(x) && isfinite(y); + } + else { + for(size_t k=0; k<3; k++) { + size_t Ooffset; + size_t Ioffset; + double x=round(M.x(i,j)), y=round(M.y(i,j)); + switch(lastinfo.colorMode) { + case 2: { + Ooffset = i*AutoResize.xStride + j*AutoResize.yStride + k; + Ioffset = x*lastinfo.xStride+y*lastinfo.yStride + k; + } break; + case 3: { + Ooffset = i*AutoResize.xStride + j*AutoResize.yStride + k*AutoResize.xSize; + Ioffset = x*lastinfo.xStride + y*lastinfo.yStride + k*lastinfo.xSize; + } break; + case 4: { + Ooffset = i*AutoResize.xStride + j*AutoResize.yStride + k*AutoResize.xSize*AutoResize.ySize; + Ioffset = x*lastinfo.xStride+y*lastinfo.yStride + k*lastinfo.xSize*lastinfo.ySize; + } break; + } + Sample * const SX = &S[Ooffset]; + SX->weight = 1.0; + SX->index = Ioffset; + SX->valid = isfinite(x) && isfinite(y); + } + } } } } break; + case Bilinear: { assert(samp_per_pixel==4); for(size_t j=0; j mapping_t; - mapping_t mapping; // size() is samp_per_pixel*listinfo.nElements + mapping_t mapping; // size() is samp_per_pixel*AutoResize.nElements NDArrayInfo lastinfo; + int lastautoresize; + double angle = 0.0; Mapping lastmap; enum mode_t { Nearest, Bilinear, @@ -106,6 +120,7 @@ class epicsShareClass NDPluginWarp : public NDPluginDriver { int NDWarpFactorY; int NDWarpCenterX; int NDWarpCenterY; + int NDWarpAutoResize; #define LAST_NDPLUGIN_WARP_PARAM NDWarpCenterY #define NUM_NDPLUGIN_WARP_PARAMS ((int)(&LAST_NDPLUGIN_WARP_PARAM - &FIRST_NDPLUGIN_WARP_PARAM + 1)) diff --git a/warpApp/src/ndutil.h b/warpApp/src/ndutil.h index e08b919..23b5add 100644 --- a/warpApp/src/ndutil.h +++ b/warpApp/src/ndutil.h @@ -123,6 +123,7 @@ struct aPDUnlock { typedef epicsGuard aPDLock; // allow uninitialized array of same type and shape as 'proto' +/* inline NDArray* cloneArray(NDArrayPool *pool, NDArray *proto) { @@ -132,5 +133,6 @@ NDArray* cloneArray(NDArrayPool *pool, NDArray *proto) } return pool->alloc(proto->ndims, dims, proto->dataType, proto->dataSize, NULL); } +*/ #endif // NDUTIL_H