From bd7944fd8bef4315b5309e1e0094d1d6fa8f7090 Mon Sep 17 00:00:00 2001 From: Guilherme Rodrigues de Lima Date: Mon, 26 Jun 2023 11:44:41 -0300 Subject: [PATCH 1/4] Support RGB images --- warpApp/src/NDPluginWarp.cpp | 76 ++++++++++++++++++++++++++++++------ warpApp/src/NDPluginWarp.h | 5 +-- 2 files changed, 66 insertions(+), 15 deletions(-) diff --git a/warpApp/src/NDPluginWarp.cpp b/warpApp/src/NDPluginWarp.cpp index c241468..94e22b8 100644 --- a/warpApp/src/NDPluginWarp.cpp +++ b/warpApp/src/NDPluginWarp.cpp @@ -24,7 +24,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, @@ -111,12 +112,23 @@ NDPluginWarp::processCallbacks(NDArray *pArray) NDArrayInfo info; (void)pArray->getInfo(&info); + /* if(pArray->ndims!=2 || info.xSize==0 || info.ySize==0) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:: 2D non-empty expected", this->portName); + if (test == 0) { + printf("ndmins = %i\n",pArray->ndims); + printf("xSize = %i\n",info.xSize); + printf("ySize = %i\n",info.ySize); + printf("colorSize = %i\n",info.colorSize); + printf("nElements = %i\n",info.nElements); + printf("colorMode = %i\n",info.colorMode); + } + return; } + */ switch(pArray->dataType) { #define CASE(TYPE) case ND ## TYPE: CASE(Int8) @@ -188,7 +200,7 @@ NDPluginWarp::processCallbacks(NDArray *pArray) output->getInfo(&info); for(size_t oy=0; oyweight = 1.0; - SX->index = Ioffset; - SX->valid = isfinite(x) && isfinite(y); + if (lastinfo.colorMode == 0) { + const size_t Ooffset = i*lastinfo.xStride + j*lastinfo.yStride; + Sample * const SX = &S[Ooffset]; + double x=round(M.x(i,j)), y=round(M.y(i,j)); + const size_t Ioffset = x*lastinfo.xStride + + y*lastinfo.yStride; + SX->weight = 1.0; + SX->index = Ioffset; + SX->valid = isfinite(x) && isfinite(y); + } + else if (lastinfo.colorMode == 2) { + for(size_t k=0; k<3; k++) { + const size_t Ooffset = i*lastinfo.xStride + j*lastinfo.yStride + k; + //printf("x=%i y=%i pos=%i\n",i,j,Ooffset); + Sample * const SX = &S[Ooffset]; + double x=round(M.x(i,j)), y=round(M.y(i,j)); + const size_t Ioffset = x*lastinfo.xStride+y*lastinfo.yStride + k; + SX->weight = 1.0; + SX->index = Ioffset; + SX->valid = isfinite(x) && isfinite(y); + } + } + else if (lastinfo.colorMode == 3) { + for(size_t k=0; k<3; k++) { + const size_t Ooffset = i*lastinfo.xStride + j*lastinfo.yStride + k*lastinfo.xSize; + //printf("x=%i y=%i pos=%i\n",i,j,Ooffset); + Sample * const SX = &S[Ooffset]; + double x=round(M.x(i,j)), y=round(M.y(i,j)); + const size_t Ioffset = x*lastinfo.xStride + y*lastinfo.yStride + k*lastinfo.xSize; + SX->weight = 1.0; + SX->index = Ioffset; + SX->valid = isfinite(x) && isfinite(y); + } + } + else if (lastinfo.colorMode == 4) { + for(size_t k=0; k<3; k++) { + const size_t Ooffset = i*lastinfo.xStride + j*lastinfo.yStride + k*lastinfo.xSize*lastinfo.ySize; + //printf("x=%i y=%i pos=%i\n",i,j,Ooffset); + Sample * const SX = &S[Ooffset]; + double x=round(M.x(i,j)), y=round(M.y(i,j)); + const size_t Ioffset = x*lastinfo.xStride+y*lastinfo.yStride + k*lastinfo.xSize*lastinfo.ySize; + SX->weight = 1.0; + SX->index = Ioffset; + SX->valid = isfinite(x) && isfinite(y); + } + } } } } @@ -437,6 +487,8 @@ void NDPluginWarp::fill_mapping(Mapping &M) M.x(x,y) = xc+center[0]; M.y(x,y) = yc+center[1]; + + //printf("M.x(%i,%i) = %f e M.y(%i,%i) = %f \n",x,y,xc,x,y,yc); } } } diff --git a/warpApp/src/NDPluginWarp.h b/warpApp/src/NDPluginWarp.h index f35bd41..9f7621d 100644 --- a/warpApp/src/NDPluginWarp.h +++ b/warpApp/src/NDPluginWarp.h @@ -47,8 +47,7 @@ class epicsShareClass NDPluginWarp : public NDPluginDriver { virtual void processCallbacks(NDArray *pArray); virtual asynStatus writeFloat64(asynUser *pasynUser, epicsFloat64 value); virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value); - - + struct Mapping { Mapping() :yStride(0) {} void resize(const NDArrayInfo_t& info) { @@ -89,7 +88,7 @@ class epicsShareClass NDPluginWarp : public NDPluginDriver { unsigned samp_per_pixel; typedef std::vector mapping_t; - mapping_t mapping; // size() is samp_per_pixel*listinfo.nElements + mapping_t mapping; // size() is samp_per_pixel*lastinfo.nElements NDArrayInfo lastinfo; Mapping lastmap; From 934d3015af44bb35fb3f781d0390025fae8ca430 Mon Sep 17 00:00:00 2001 From: Guilherme Rodrigues de Lima Date: Thu, 22 Jun 2023 17:24:53 -0300 Subject: [PATCH 2/4] AutoResize Function --- warpApp/Db/NDWarp.template | 11 ++ warpApp/src/NDPluginWarp.cpp | 282 ++++++++++++++++++++++------------- warpApp/src/NDPluginWarp.h | 48 +++++- warpApp/src/ndutil.h | 2 + 4 files changed, 237 insertions(+), 106 deletions(-) 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 94e22b8..3401cc4 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) { @@ -62,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 @@ -69,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() { @@ -112,23 +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); - if (test == 0) { - printf("ndmins = %i\n",pArray->ndims); - printf("xSize = %i\n",info.xSize); - printf("ySize = %i\n",info.ySize); - printf("colorSize = %i\n",info.colorSize); - printf("nElements = %i\n",info.nElements); - printf("colorMode = %i\n",info.colorMode); - } - + this->portName); return; } - */ + switch(pArray->dataType) { #define CASE(TYPE) case ND ## TYPE: CASE(Int8) @@ -155,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; @@ -172,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) @@ -325,28 +351,35 @@ void NDPluginWarp::recalculate_transform(const NDArrayInfo& info) default: throw std::runtime_error("Invalid interpolation mode"); } - mapping.resize(samp_per_pixel*info.nElements); + + getDoubleParam(NDWarpAngle, &angle); + + if (lastautoresize == 1) { + AutoResize.resize(angle,lastinfo); + } else { + AutoResize.resize(0,lastinfo); + } + + mapping.resize(samp_per_pixel*AutoResize.nElements); Mapping M; - M.resize(info); + M.resize(AutoResize.xSize,AutoResize.ySize); fill_mapping(M); // sanitize mapping // replace outside range [0, size-1] with NaN for(size_t j=0; jM.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]; @@ -354,52 +387,39 @@ void NDPluginWarp::recalculate_transform(const NDArrayInfo& info) switch(cur_mode) { case Nearest: { assert(samp_per_pixel==1); - printf("colorMode = %i \n",lastinfo.colorMode); - printf("nElements = %i \n",lastinfo.nElements); for(size_t j=0; jweight = 1.0; SX->index = Ioffset; SX->valid = isfinite(x) && isfinite(y); + } - else if (lastinfo.colorMode == 2) { + else { for(size_t k=0; k<3; k++) { - const size_t Ooffset = i*lastinfo.xStride + j*lastinfo.yStride + k; - //printf("x=%i y=%i pos=%i\n",i,j,Ooffset); - Sample * const SX = &S[Ooffset]; + size_t Ooffset; + size_t Ioffset; double x=round(M.x(i,j)), y=round(M.y(i,j)); - const size_t Ioffset = x*lastinfo.xStride+y*lastinfo.yStride + k; - SX->weight = 1.0; - SX->index = Ioffset; - SX->valid = isfinite(x) && isfinite(y); - } - } - else if (lastinfo.colorMode == 3) { - for(size_t k=0; k<3; k++) { - const size_t Ooffset = i*lastinfo.xStride + j*lastinfo.yStride + k*lastinfo.xSize; - //printf("x=%i y=%i pos=%i\n",i,j,Ooffset); + 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]; - double x=round(M.x(i,j)), y=round(M.y(i,j)); - const size_t Ioffset = x*lastinfo.xStride + y*lastinfo.yStride + k*lastinfo.xSize; - SX->weight = 1.0; - SX->index = Ioffset; - SX->valid = isfinite(x) && isfinite(y); - } - } - else if (lastinfo.colorMode == 4) { - for(size_t k=0; k<3; k++) { - const size_t Ooffset = i*lastinfo.xStride + j*lastinfo.yStride + k*lastinfo.xSize*lastinfo.ySize; - //printf("x=%i y=%i pos=%i\n",i,j,Ooffset); - Sample * const SX = &S[Ooffset]; - double x=round(M.x(i,j)), y=round(M.y(i,j)); - const size_t Ioffset = x*lastinfo.xStride+y*lastinfo.yStride + k*lastinfo.xSize*lastinfo.ySize; SX->weight = 1.0; SX->index = Ioffset; SX->valid = isfinite(x) && isfinite(y); @@ -409,40 +429,95 @@ void NDPluginWarp::recalculate_transform(const NDArrayInfo& info) } } break; + case Bilinear: { assert(samp_per_pixel==4); for(size_t j=0; j mapping_t; - mapping_t mapping; // size() is samp_per_pixel*lastinfo.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, @@ -105,6 +144,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 From cddda92fb25c8732eeee1800ec7692dcdf4e6b58 Mon Sep 17 00:00:00 2001 From: Guilherme Rodrigues de Lima Date: Tue, 27 Jun 2023 14:45:06 -0300 Subject: [PATCH 3/4] correction AutoResize.yStride --- warpApp/src/NDPluginWarp.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/warpApp/src/NDPluginWarp.h b/warpApp/src/NDPluginWarp.h index 8657f72..9443aad 100644 --- a/warpApp/src/NDPluginWarp.h +++ b/warpApp/src/NDPluginWarp.h @@ -97,19 +97,19 @@ class epicsShareClass NDPluginWarp : public NDPluginDriver { if (info.colorMode == 0) { nElements = xSize * ySize; xStride = 1; - yStride = ySize; + yStride = xSize; } else if (info.colorMode == 2) { nElements = xSize * ySize * 3; xStride = 3; - yStride = ySize*3; + yStride = xSize*3; } else if (info.colorMode == 3) { nElements = xSize * ySize * 3; xStride = 1; - yStride = ySize*3; + yStride = xSize*3; } else if (info.colorMode == 4) { nElements = xSize * ySize * 3; xStride = 1; - yStride = ySize; + yStride = xSize; } } size_t xSize; From 3565374ad2c0e7a8db6e815e1d2bba9b39f5b57f Mon Sep 17 00:00:00 2001 From: Guilherme Rodrigues de Lima Date: Wed, 28 Jun 2023 09:05:26 -0300 Subject: [PATCH 4/4] debug ci compatibility --- warpApp/src/NDPluginWarp.cpp | 33 +++++++++++++++++++++++++++++++-- warpApp/src/NDPluginWarp.h | 28 ++-------------------------- 2 files changed, 33 insertions(+), 28 deletions(-) diff --git a/warpApp/src/NDPluginWarp.cpp b/warpApp/src/NDPluginWarp.cpp index 3401cc4..7c18ad7 100644 --- a/warpApp/src/NDPluginWarp.cpp +++ b/warpApp/src/NDPluginWarp.cpp @@ -337,6 +337,35 @@ asynStatus NDPluginWarp::writeInt32(asynUser *pasynUser, epicsInt32 value) return ret; } +void NDPluginWarp::auto_resize(double a) { + + AutoResize.xSize = round(cos(abs(a)*PI_180)*lastinfo.xSize + sin(abs(a)*PI_180)*lastinfo.ySize); + AutoResize.ySize = round(cos(abs(a)*PI_180)*lastinfo.ySize + sin(abs(a)*PI_180)*lastinfo.xSize); + + switch(lastinfo.colorMode) { + case 0: { + AutoResize.nElements = AutoResize.xSize * AutoResize.ySize; + AutoResize.xStride = 1; + AutoResize.yStride = AutoResize.xSize; + } break; + case 2: { + AutoResize.nElements = AutoResize.xSize * AutoResize.ySize * 3; + AutoResize.xStride = 3; + AutoResize.yStride = AutoResize.xSize*3; + } break; + case 3: { + AutoResize.nElements = AutoResize.xSize * AutoResize.ySize * 3; + AutoResize.xStride = 1; + AutoResize.yStride = AutoResize.xSize*3; + } break; + case 4: { + AutoResize.nElements = AutoResize.xSize * AutoResize.ySize * 3; + AutoResize.xStride = 1; + AutoResize.yStride = AutoResize.xSize; + } break; + } +} + void NDPluginWarp::recalculate_transform(const NDArrayInfo& info) { int rawmode=0; @@ -355,9 +384,9 @@ void NDPluginWarp::recalculate_transform(const NDArrayInfo& info) getDoubleParam(NDWarpAngle, &angle); if (lastautoresize == 1) { - AutoResize.resize(angle,lastinfo); + auto_resize(angle); } else { - AutoResize.resize(0,lastinfo); + auto_resize(0); } mapping.resize(samp_per_pixel*AutoResize.nElements); diff --git a/warpApp/src/NDPluginWarp.h b/warpApp/src/NDPluginWarp.h index 9443aad..9f49f77 100644 --- a/warpApp/src/NDPluginWarp.h +++ b/warpApp/src/NDPluginWarp.h @@ -30,8 +30,7 @@ #define NDWarpAutoResizeString "WARP_AUTORESIZE_MODE" -// pi/180 -#define PI_180 0.017453292519943295 +#define PI_180 0.017453292519943295 // pi/180 /** Generic coordinate transformation * @@ -89,39 +88,16 @@ class epicsShareClass NDPluginWarp : public NDPluginDriver { }; struct { - void resize(double a, const NDArrayInfo& info) { - - xSize = round(cos(abs(a)*PI_180)*info.xSize + sin(abs(a)*PI_180)*info.ySize); - ySize = round(cos(abs(a)*PI_180)*info.ySize + sin(abs(a)*PI_180)*info.xSize); - - if (info.colorMode == 0) { - nElements = xSize * ySize; - xStride = 1; - yStride = xSize; - } else if (info.colorMode == 2) { - nElements = xSize * ySize * 3; - xStride = 3; - yStride = xSize*3; - } else if (info.colorMode == 3) { - nElements = xSize * ySize * 3; - xStride = 1; - yStride = xSize*3; - } else if (info.colorMode == 4) { - nElements = xSize * ySize * 3; - xStride = 1; - yStride = xSize; - } - } size_t xSize; size_t ySize; size_t nElements; size_t xStride; size_t yStride; - } AutoResize; void recalculate_transform(const NDArrayInfo &info); void fill_mapping(Mapping &M); + void auto_resize(double a); unsigned samp_per_pixel; typedef std::vector mapping_t;